Exemple #1
0
pid_t ach_detach ( unsigned timeout ) {
    pid_t gp_pid = getpid();
    ACH_LOG( LOG_DEBUG, "detach grandparent: %d\n", gp_pid );
    /* Block signals for child status notification */
    const int sigs[] = {ACH_SIG_OK, ACH_SIG_FAIL, SIGALRM, 0};
    ach_sig_block_dummy(sigs);

    /* fork */
    pid_t pid1 = fork();
    if( pid1 < 0 ) {
        ACH_DIE( "First fork failed: %s\n", strerror(errno) );
    } else if ( pid1 ) { /* parent */
        /* wait for a signal */
        alarm( timeout );
        int sig = ach_sig_wait(sigs);
        ACH_LOG( LOG_DEBUG, "Detach grandparent got: '%s' (%d)\n",
                 strsignal(sig), sig );
        switch( sig ) {
        case SIGALRM:
            ACH_LOG( LOG_ERR, "Detached child failed on timeout\n" );
            exit( EXIT_FAILURE );
        case SIGUSR2:
            ACH_LOG( LOG_ERR, "Detached child reported failure\n" );
            exit( EXIT_FAILURE );
        case SIGUSR1:
            ACH_LOG( LOG_DEBUG, "Detached child OK\n" );
            exit(EXIT_SUCCESS);
        default:
            ACH_LOG( LOG_ERR, "Unexpected signal in detach: %s (%d)\n",
                     strsignal(sig), sig );
            exit( EXIT_FAILURE );
        }
        assert(0);
    } /* else child */

    /* Unblock signals that were blocked in the parent */
    ach_sig_dfl_unblock( sigs );

    /* set session id to lose our controlling terminal */
    if( setsid() < 0 ) {
        ACH_LOG( LOG_ERR, "Couldn't set sid: %s\n", strerror(errno) );
    }

    /* refork to prevent future controlling ttys */
    pid_t pid2 = fork();
    if( pid2 < 0 ) {
        ACH_LOG( LOG_ERR, "Second fork failed: %s\n", strerror(errno) );
        /* Don't give up */
    } else if ( pid2 ) { /* parent */
        ACH_LOG( LOG_DEBUG, "detach parent: %d\n", getpid() );
        exit(EXIT_SUCCESS);
    } /* else child */

    ACH_LOG( LOG_DEBUG, "detach child: %d\n", getpid() );

    /* ignore sighup */
    if( SIG_ERR == signal(SIGHUP, SIG_IGN) ) {
        ACH_LOG( LOG_ERR, "Couldn't ignore SIGHUP: %s", strerror(errno) );
    }

    /* cd to root */
    if( chdir("/") ) {
        ACH_LOG( LOG_ERR, "Couldn't cd to /: %s", strerror(errno) );
    }

    /* close stdin */
    if( close(STDIN_FILENO) ) {
        ACH_LOG( LOG_ERR, "Couldn't close stdin: %s", strerror(errno) );
    }

    return gp_pid;
}
Exemple #2
0
int main( int argc, char **argv ) {
    /* Check if we're running under achcop */
    if( getenv("ACHCOP") ) {
        ach_pid_notify = getppid();
    }

    int c;
    while( (c = getopt( argc, argv, "zlnh?V")) != -1 ) {
        switch(c) {
        case 'v':
            ach_verbosity ++;
            break;
        case 'l':
            opt_last = 1;
            break;
        case 'n':
            opt_last = 0;
            break;
        case 'z':
            opt_gzip = 1;
            break;
        /* case 'f': */
        /*     opt_freq = atof(optarg); */
        /*     break; */
        case 'V':   /* version     */
            ach_print_version("achpipe.bin");
            exit(EXIT_SUCCESS);
        case '?':
        case 'h':
        case 'H':
            puts( "Usage: achlog [OPTIONS] channels...\n"
                  "Log ach channels to files"
                  "\n"
                  "Options:\n"
                  "  -?,                  Show help\n"
                  "  -z,                  Filter output through gzip\n"
                  "\n"
                  "Examples:\n"
                  "  achlog foo bar       Log channels foo and bar\n"
                  "\n"
                  "Report bugs to <*****@*****.**>"
                );
            exit(EXIT_SUCCESS);
        default:
            posarg(optarg);
        }
    }
    while( optind < argc ) {
        posarg(argv[optind++]);
    }
    if( 0 == n_log ) ACH_DIE("No channels to log\n");

    /* Block Signals */
    /* Have to block these before forking so ctrl-C doesn't kill the
     * gzip */
    int sigs[] = {SIGTERM, SIGINT, 0};
    ach_sig_block_dummy( sigs );

    /* Open Channels */
    size_t i;
    for( i = 0; i < n_log; i ++ ) {
        ach_status_t r = ach_open(&log_desc[i].chan, log_desc[i].name, NULL);
        if( ACH_OK != r ) {
            ACH_DIE( "Could not open channel %s: %s\n",
                     log_desc[i].name, ach_result_to_string(r) );
        }
        /* Open log file */
        if( opt_gzip ) {
            log_desc[i].fout = filter( "gzip -c", log_desc[i].name, ".gz" );
        } else {
            log_desc[i].fout = fopen(log_desc[i].name, "w");
        }
        if( NULL == log_desc[i].fout ) {
            ACH_DIE( "Could not open log file for %s: %s\n",
                     log_desc[i].name, strerror(errno) );
        }
    }

    /* get some data */
    if( clock_gettime(ACH_DEFAULT_CLOCK, &now_ach ) ||
        clock_gettime(CLOCK_REALTIME,    &now_real ) )
    {
        ACH_DIE( "Could not get time: %s\n", strerror(errno) );
    }
    if( gethostname( host, sizeof(host) ) ) {
        ACH_LOG(LOG_ERR, "Could not get host name: %s\n", strerror(errno));
    }
    host[sizeof(host)-1] = '\0';
    passwd = getpwuid(getuid());
    if( passwd ) {
        strtok(passwd->pw_gecos, ",");
    }
    now_real_str = ctime( &now_real.tv_sec );

    /* Create Workers */
    pthread_t thread[n_log];
    for( i = 0; i < n_log; i ++ ) {
        int r = pthread_create( thread+i, NULL, worker, (void*)(log_desc+i) );
        if( r ) ACH_DIE( "Couldn't start worker thread: %s\n", strerror(r) );
    }
    ach_notify(ACH_SIG_OK);

    /* Wait for Signal */
    ach_sig_wait( sigs );

    /* Cancel workers */
    ach_cancel_attr_t cattr;
    ach_cancel_attr_init( &cattr );
    cattr.async_unsafe = 1;
    for( i = 0; i < n_log; i ++ ) {
        ach_cancel( &log_desc[i].chan, &cattr );
    }

    /* Join worker threads */
    for( i = 0; i < n_log; i ++ ) {
        int r = pthread_join( thread[i], NULL );
        if( r ) ACH_DIE( "Couldn't join worker thread: %s\n", strerror(r) );
        if( opt_gzip ) {
            if( pclose(log_desc[i].fout) < 0 ) {
                ACH_LOG( LOG_ERR, "Could not pclose output for %s: %s\n",
                         log_desc[i].name, strerror(errno) );
            }
        } else {
            fclose(log_desc[i].fout);
        }
    }

    return 0;
}