Пример #1
0
static FILE *filter( const char *program, const char *channel, const char *suffix ) {
    size_t n = strlen(channel) + strlen(suffix) + 1;
    char buf[n];
    strcpy(buf, channel);
    strcat(buf, suffix);
    FILE *fout = fopen( buf, "w");
    if( NULL == fout ) {
        ACH_DIE( "Could not open log file %s: %s\n",
                 buf, strerror(errno) );
    }
    int oldout = dup(STDOUT_FILENO);
    if( oldout < 0 )  {
        ACH_DIE( "Could not dup stdout: %s\n", strerror(errno) );
    }
    if( dup2(fileno(fout), STDOUT_FILENO) < 0 ) {
        ACH_DIE( "Could not dup output: %s\n", strerror(errno) );
    }
    FILE *f = popen(program, "w");
    if( NULL == f ) {
        ACH_DIE( "Could not popen `%s': %s\n", program, strerror(errno) );
    }
    if( dup2(oldout, STDOUT_FILENO) < 0 ) {
        ACH_DIE( "Could not dup stdout back: %s\n", strerror(errno) );
    }
    if( close(oldout) ) {
        ACH_LOG( LOG_WARNING, "Could not close dup'ed stdout: %s\n", strerror(errno) );
    }
    if( fclose(fout) )  {
        ACH_LOG( LOG_WARNING, "Could not close dup'ed output file: %s\n", strerror(errno) );
    }

    return f;
}
Пример #2
0
void ach_sig_mask( const int *sig, sigset_t *mask ) {
    if( sigemptyset(mask) ) ACH_DIE("sigemptyset failed: %s\n", strerror(errno));
    size_t i;
    for( i = 0; sig[i]; i ++ ) {
        if( sigaddset(mask, sig[i]) ) {
            ACH_DIE("sigaddset of %s (%d) failed: %s\n",
                    strsignal(sig[i]), sig[i], strerror(errno) );
        }
    }
}
Пример #3
0
int ach_sig_wait( const int *sigs ) {
    ACH_LOG( LOG_DEBUG, "pid %d waiting for signal\n", getpid() );

    sigset_t waitset;
    ach_sig_mask( sigs, &waitset );

    int sig;
    if( sigwait(&waitset, &sig) ) {
        ACH_DIE("sigwait failed: %s\n", strerror(errno));
    }

    ACH_LOG( LOG_DEBUG, "pid %d signalled: '%s' %d\n",
             getpid(), strsignal(sig), sig );

    return sig;
}
Пример #4
0
void ach_sig_dfl_unblock( const int *sig ) {
    size_t i;
    for( i = 0; sig[i]; i ++ ) {
        /* Default Disposition */
        if( SIG_ERR == signal(sig[i], SIG_DFL) ) {
            ACH_LOG( LOG_ERR, "Couldn't set default signal disposition for %s (%d): %s",
                     strsignal(sig[i]), sig[i], strerror(errno) );
        }
    }
    /* Unblock Signal */
    {
        sigset_t blockmask;
        ach_sig_mask( sig, &blockmask );
        if( sigprocmask(SIG_UNBLOCK, &blockmask, NULL) ) {
            ACH_DIE( "sigprocmask failed: %s\n", strerror(errno) );
        }
    }
}
Пример #5
0
void ach_sig_block_dummy( const int *sig ) {
    /* Block Signal */
    {
        sigset_t blockmask;
        ach_sig_mask( sig, &blockmask );
        if( sigprocmask(SIG_BLOCK, &blockmask, NULL) ) {
            ACH_DIE( "sigprocmask failed: %s\n", strerror(errno) );
        }
    }
    /* Install Dummy Handler */
    size_t i;
    for( i = 0; sig[i]; i ++ ) {
        struct sigaction act;
        memset( &act, 0, sizeof(act) );
        act.sa_handler = &ach_sigdummy;
        if (sigaction(sig[i], &act, NULL) < 0) {
            ACH_LOG( LOG_ERR, "Couldn't install signal handler: %s", strerror(errno) );
        }
    }
}
Пример #6
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;
}
Пример #7
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;
}