Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Unix signal handling using PRO*C

Re: Unix signal handling using PRO*C

From: Alexey M. Reshetov <real_at_kpbank.ru>
Date: 26 Aug 1998 01:07:50 GMT
Message-ID: <6rvn56$jh3$1@home.kpbank.ru>


jedimaster (jedimast_at_concentric.net) wrote:

: Can anyone give me some example code showing the proper way to handle
: SIGINT and SIGCHLD signals in a Unix program?  I'm having a problem
: with core dumps occuring under 7.3.3 when I try to trap these two
: signals?

: Thanks,
: Bob

: =====================================================
: "When the long night comes, return to the end of the beginning."

: Message from Ambassador Kosh to Sheridan - Babylon 5

: =====================================================

It's a part of code of my unix daemon with signal handlers and comments. This works fine under Digital Unix. Enjoy!

/*
 *	sq network daemon
 *	sq - designed for System V and BSD compatibility
 *	Created by Alexey Reshetov, 16.12.96.
 *	References to network server from R.Stevens.
 */


#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <syslog.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>

/* #include "sqlca.h" */
EXEC SQL INCLUDE sqlca;

int Port; /* Port number for communications */

typedef char asciiz[40];

EXEC SQL TYPE asciiz IS STRING(40) REFERENCE;

asciiz username;
asciiz password;
asciiz col_name;

char table_name[40];
char oracle_sid[40];
char oracle_home[40];  

void sql_error(); /* For ORACLE exceptions and LOGIN Errors */

void reapchild();
void die();
void init();
void onalarm();
void gettimenow();
int stat_file();

char *pname;
char str[2] = "#"; /* Null value for control table */

int start_flg; /* At start flag == 0, at restrart flag = 1, then 0 */

#define PID_FILE "/var/run/sq.pid"
#define CONF_FILE "/var/adm/sq/sq.conf"
#define LOG_FILE "/var/adm/sq/sq.log"

#define MAXLINE 80
 

int TIMERINT = 1; /* default time value for TIMER */

pid_t childpid;		/* childpid - clobal variable, therefore easy
			 * to kill child, but if at one time there are
			 * few childs (i.e. few connections), then
			 * childpid will redefined, and it will difficult
			 * way to kill correctly.
			 */

main( int argc, char *argv[])
{

	int sockfd, newsockfd, clilen, fd;
	struct sockaddr_in   serv_addr, cli_addr;
	struct servent *sp;
	int status;
	pid_t pid;
	FILE *fp;
	static struct stat statbuf;
	char buf[MAXLINE];
	char hostname[MAXHOSTNAMELEN];	/* local host name */
   
	start_flg = 0;

	/* unlink(LOG_FILE); */

	pname = argv [0];

	if ((sp = getservbyname("sq", "tcp")) == NULL)
	{
		fprintf(stderr, "sq/tcp: unknown service\n");
		err_dump("sq/tcp: unknown service");
		exit (-1);
	}

	/* User's default parameters for connect to ORACLE */
	strcpy(username, "Frank");
	strcpy(password, "Zappa");

	EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE ERROR--");
	EXEC SQL WHENEVER NOT FOUND DO break;

      /*
       *   If we are not started in the background ( there should be
       *    important _if_ above), fork and let parent exit.
       *    This also guarantees the first child is not a process
       *    group leader  
       */
           if ( (childpid = fork()) < 0 )
                err_dump("can't fork first child");
           else if ( childpid > 0)
                exit(0);           /* parent */

       /*
        *     First child process
        */

	if (stat_file (CONF_FILE, R_OK) != 0)
	{
		fprintf(stderr, "sq: Can't stat config file.\n");
		exit (-1);
	}
  
	init (0);
	if (stat(PID_FILE, &statbuf) == 0)
	{
		fprintf(stderr, "File %s exists!\n", PID_FILE);
		exit (-1);
	}
	else if ((fp = fopen (PID_FILE, "w")) != NULL)
	{
		fprintf(fp, "%d\n", getpid());
		(void) fclose (fp);
	}
	else if (fp == NULL)
	{
		fprintf(stderr, "Can't open file %s\n", PID_FILE);
		exit (-1);
	}
	
	/* Set environment variables */
	if (setenv("ORACLE_HOME", oracle_home, 1) != 0)
	{
		fprintf(stderr, "ORACLE_HOME is not set\n");
		err_dump("ORACLE_HOME is not set");
		exit (-1);
	}
	if (setenv("ORACLE_SID", oracle_sid, 1) != 0)
	{
		fprintf(stderr, "ORACLE_SID is not set\n");
		err_dump("ORACLE_SID is not set");
		exit (-1);
	}

      /*
       *   Disassociate from Contol Terminal  and process group.                
       *   Ensure the process can't reaquire a new contorlling terminal.  
       */
	/* For BSD, not for System V 
	    if ( setpgrp(0, setpid()) == -1 ) 
                 err_dump("can't change process group");
	*/
       
            if ( (fd = open("/dev/tty", O_RDWR )) >= 0)
              {
                ioctl(fd, TIOCNOTTY, (char *)NULL);  /* lose controlling tty */
                close(fd);
              };

       /*
        *    Close any open files ( stdin, stdout etc ) descriptors
        */
             for (fd =0; fd < NOFILE; fd++ )
                close(fd);
        /*
         *   Move current directory to root
         */
             chdir("/");

        /*
         *   Set file mode creation mask.
         */
             umask(022);
	
	/* SIGNALS */
	(void) signal (SIGHUP, init);
	(void) signal (SIGTERM, die);
	(void) signal (SIGINT, die);
	(void) signal (SIGQUIT, die);
	/*
         *   Don't wait child signals. This successfully prevent
         *       ugly zombies creation
	 */
        (void) signal ( SIGCHLD, reapchild );


      /*
       *    Open a TCP socket ( an Internet stream socket )
       */

      if ( (sockfd = socket (AF_INET, SOCK_STREAM, 0 )) <0)
          err_dump("can't open stream socket");

      /*
       *    Bind our local address so that the client can send to us
       */

       bzero( (char *) &serv_addr, sizeof(serv_addr) );
       serv_addr.sin_family      = AF_INET;
       serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
       serv_addr.sin_port        = Port = sp->s_port;

       if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
       {
           err_dump("can't bind local address");
 	   exit (-1);
       }

	pid = getpid();

        listen( sockfd, 5 );

       for(;;)
       {
           /*
            *    Wait for a connection from client process
            *    This is an example of concurrent server  
            */
            
            clilen = sizeof(cli_addr);
            newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

            if ( newsockfd < 0 )
	    {
		if (start_flg == 0)
                    err_dump("accept error"); 
	    }

	    signal (SIGALRM, onalarm);
	    alarm(TIMERINT);

	    if ((childpid = fork()) < 0)
		   err_dump("fork error");
            
            else if (childpid == 0 )
            {                              /* child process */
                close(sockfd);               /* close original socket */
		EXEC SQL CONNECT :username IDENTIFIED BY :password;
		EXEC SQL DECLARE linkstat CURSOR FOR
			SELECT req_atr FROM control_ip_connect;
		EXEC SQL OPEN linkstat; 
		EXEC SQL FETCH linkstat INTO :str;  
		EXEC SQL CLOSE linkstat;  
		EXEC SQL COMMIT WORK RELEASE; 
                str_echo(newsockfd, str);        /* process the request */
		close(newsockfd);
                exit(getpid());
            }
	    else if (childpid > 0)
	    {
	        while (waitpid(childpid, &status, 0) != 0)
		    break;
	        signal (SIGALRM, SIG_IGN);

		/* If the wait, waitpid, wait3, or wait4 function returns
		 * because the status of a child process is available, the
		 * process ID of the child is returned to the calling process.
		 * If they return because a signal was caught by the calling
		 * process, -1 is returned and errno is set to [EINTR].
		 * If the WNOHANG option was specified, and there are no
		 * stopped or exited child processes, the waitpid, wait3,
		 * and wait4 functions return a value of zero (0). Otherwise,
		 * -1 is returned and errno is set to indicate the error.
		 */


	    }
            close(newsockfd);                     /* in parent process */
	    start_flg = 0;
	    sleep(TIMERINT+1);
        }
	exit (0);

}
/* init - read config file
 * config file allows comments (#)
 */
            
/* 
 * die - to kill all child processes, close all opened files
	/* Close all opened files */
	for (fd = 0; fd < NOFILE; fd++)
		close (fd);
	if (signo != 0)
	{
		sprintf(buf, "die: Process %d Exiting on signal %d", 
				getpid(), signo);
		err_dump(buf);
		errno = 0;
	}
	/*
	if (unlink(PID_FILE) != 0)
		err_dump("die: Can't delete pid-file");
	*/

	exit (0);

}

void sql_error(msg)
char *msg;
{

	char err_msg[512];
	char buf[1024];
	size_t buf_len, msg_len;
	
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	sprintf(buf, "SQL-%s\n", msg);
	err_dump(buf);

	/* Call sqlglm() to get the complete text of the error message. */
	buf_len = sizeof (err_msg);
	sqlglm (err_msg, &buf_len, &msg_len);
	sprintf(buf, "SQL-%s.%s\n", msg_len, err_msg);
	err_dump(buf);

	EXEC SQL ROLLBACK RELEASE;
	return;

}         
/* 
 * reapchild()
 */

void reapchild (int signo)
{

      /*
       *  Use the wait3() systems call with the WNOHANG option
       *
       */
/*     union wait    status;  */
	int status; 

   while (wait3( (int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
         ;

}
/*
 * onalarm - after received signal SIGALRM, kill child process
 */

void onalarm(int signo)
{

        char buf[80];

	sprintf(buf, "onalarm - kill child process %d", childpid);
	err_dump(buf);
	kill (childpid, SIGINT);

}

Alexey Reshetov
real_at_kpbank.ru Received on Tue Aug 25 1998 - 20:07:50 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US