hang on exit bug under Linux

"Petersen, Jörg" j.petersen at msh.de
Thu Dec 13 02:15:30 EST 2001


If you like a C-Version; you might be inspired by my "daemon.c":
I use it to run Shell-Scripts as "clean" daemons:


/* daemon.c
 * $Id: daemon.c,v 1.4 2001/10/10 07:14:59 jp Exp $
 * $Source: /home/u/jp/RCS/daemon.c,v $
 *
 * 1.1   19.09.2001 jp- RCS-Checkin der ersten Version
 * 1.2   19.09.2001 jp- Einbau Option -l logfile, -c, -q
 * 1.3   19.09.2001 jp- ID als extern-String
 * 1.4   10.10.2001 jp- Usage auch auf stderr
 */

/*
   cc daemon.c -o daemon; strip daemon
 */
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/syslog.h>
#include <sys/types.h>

extern char version[]="$Id: daemon.c,v 1.4 2001/10/10 07:14:59 jp Exp $";
char * progname;
int chdirRoot=0;
int quiet=0;

void usage(char * txt) {
        fprintf (stderr,"%s\n",txt);
        fprintf (stderr,"Usage: %s [-c] [-l /log/file] /path/to/exe arg1
arg2\n",
                        progname);
        fprintf (stderr,"   -l /log/file  does '>/log/file 2>&1'\n");
        fprintf (stderr,"   -c            does cd / (use whenever
possible!)\n");
        syslog (LOG_INFO | LOG_DAEMON,"%s\n",txt);
        syslog (LOG_INFO | LOG_DAEMON,"Usage: %s [-c] [-l /log/file]
/path/to/exe arg1 arg2\n",
                        progname);
        syslog (LOG_INFO | LOG_DAEMON,"   -l /log/file  does '>/log/file
2>&1'\n");
        syslog (LOG_INFO | LOG_DAEMON,"   -c            does cd / (use
whenever possible!)\n");
        exit(-1);
}

char * timetext(void) {
    time_t current;
    struct tm * local;
    static char str[22];
    time(&current); /* momentane Zeit */
    local = localtime(&current);
    sprintf(str,"%02i.%02i.%04i,%02i:%02i:%02i",
                local->tm_mday,
                local->tm_mon+1,
                local->tm_year+1900,
                local->tm_hour,
                local->tm_min,
                local->tm_sec);
    return str;
}

void MSHdaemon(char * logfile, char * infotxt) {
        int rc;

          rc=fork();
          if (-1==rc) {
            syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to fork()\n");
            exit(-1);
          }
          if (rc>0) exit(0); /* parent should exit and return control,
                 it's OK. */
          rc=setsid();
          if (-1==rc) {
            syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to setsid()\n");
            exit(-1);
          }
          rc=fork();
          if (-1==rc) {
            syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to fork()\n");
            exit(-1);
          }
          if (rc>0) exit(0); /* parent should exit and return control,
                                         it's OK. */

        if (chdirRoot == 1) {
          rc=chdir("/");
          if (-1==rc) {
            syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to chdir()\n");
            exit(-1);
          }
          /* umask(0); */
        }

        if (!freopen("/dev/null", "r", stdin)) {
 syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to freopen(%s,...,%s):
%s\n",
                "/dev/null","stdin",strerror (errno));
            fflush(stderr);
            exit(-1);
        }
        if (!freopen(logfile, "a", stdout)) {
 syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to freopen(%s,...,%s):
%s\n",
                logfile,"stdout",strerror (errno));
            fflush(stderr);
            exit(-1);
        }
        if (! quiet)
            fprintf(stdout,"Test stdout\n");
        fflush(stdout);
        if (!freopen(logfile, "a", stderr)) {
 syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to freopen(%s,...,%s):
%s\n",
                logfile,"stderr",strerror (errno));
            fflush(stderr);
            exit(-1);
        }
        if (! quiet)
            fprintf(stderr,"Test stderr\n");
        if (! quiet)
            fprintf(stderr,"%s\n",infotxt);
        fprintf(stderr,"%s\n__O_u_t_p_u_t_:____\n",timetext());
        fflush(stderr);
        if (! quiet)
            syslog (LOG_INFO | LOG_DAEMON, infotxt);
        return; /* a grandchild returns... free as a bird..  */
}


int main (int argc, char * const * argv) {
    char prog[1024];
    char infotxt[1024];
    char errmsg[1024];
    FILE * ftest;

    extern char *optarg;
    extern int optind;
    int fd;
    int ch;                     /* global int chdirRoot: cd / ? */
    char logfile[256] = "/dev/null";    /* logfile:
                                       where stdout&stderr are sent to */
    progname = argv[0];
    while ((ch = getopt(argc, argv, "qcl:")) != -1)
        switch (ch) {
            case 'q':
                quiet = 1;
                break;
            case 'c':
                chdirRoot = 1;
                break;
            case 'l':
                if (argc < 2) {
 syslog (LOG_INFO | LOG_DAEMON,"Logfilename too long! (max 255 char.!)\n");
                    exit(-1);
                }
                strcpy(logfile,optarg);
                break;
             case '?':
             default:
                     usage("Unbekanntes Argument");
     }
     argc -= optind;
     argv += optind;



    if (strlen(progname)+strlen(argv[1]) > 750) {
            syslog (LOG_INFO | LOG_DAEMON,"ArgV too long.... Tschuess\n");
        exit(-1);
    }
    if (argc < 1) {
        usage("Zu wenig Argumente!");
    }
    /* Testen ob Logfile geschrieben werden kann */
        ftest=fopen(logfile, "w");
        if (!ftest) {
   syslog (LOG_INFO | LOG_DAEMON,"daemon - Unable to fopen(%s): %s\n",
                logfile,strerror (errno));
            fflush(stderr);
            exit(-1);
        }
        fclose(ftest);
    sprintf(prog,"uid=%i prog='%s'",(int)geteuid(),argv[0]);
    sprintf(infotxt,"run as daemon: %s log='%s'",prog,logfile);
    if (! quiet)
        fprintf(stdout,"%s\n",infotxt);
    MSHdaemon(logfile,infotxt);
    execvp(argv[0],argv);
    /* Wenn wir hier ankommen, hat exec nicht funktioniert... */
    sprintf(errmsg,"%s ERROR: %s",prog,strerror (errno));
    syslog (LOG_ERR | LOG_DAEMON, errmsg);

    /* Write to log too ... */
    syslog (LOG_INFO | LOG_DAEMON,"\nERROR\n%s\n",errmsg);
    fflush(stderr);
    fclose(stderr);
    exit(0);
    return 0;
}




More information about the openssh-unix-dev mailing list