Ejemplo n.º 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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
void ach_notify(int sig) {
    if( ach_pid_notify > 0 ) {
        if( kill(ach_pid_notify, sig) ) {
            ACH_LOG( LOG_ERR, "Could not notify pid %d of failure: %s\n",
                     ach_pid_notify, strerror(errno) );
        }
        ach_pid_notify = 0;
    }
}
Ejemplo n.º 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) );
        }
    }
}
Ejemplo n.º 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) );
        }
    }
}
Ejemplo n.º 6
0
Archivo: io.c Proyecto: KimBP/ach
enum ach_status achd_printf(int fd, const char fmt[], ...) {
    int n = ACHD_LINE_LENGTH-1;
    do {
        char buf[n+1];
        va_list ap;
        va_start(ap, fmt);
        n = vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end( ap );
        if( n < 0 ) {
            ACH_LOG( LOG_CRIT, "Error in printf\n");
            return ACH_BUG;
        } else if( (size_t)n < sizeof(buf) ) {
            if ( (ssize_t)n == achd_write( fd, buf, (size_t)n ) ) {
                return ACH_OK;
            } else {
                return ACH_FAILED_SYSCALL;
            }
        } /* else continue */
    } while(!cx.sig_received);
    return ACH_FAILED_SYSCALL;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
static void *worker( void *arg ) {
    struct log_desc *desc = (struct log_desc*)arg;

    /* write header */
    fprintf( desc->fout,
             "ACHLOG\n"
             "channel-name: %s\n"
             "log-version: 0\n"
             "log-time-ach: %lu.%09lu\n"
             "log-time-real: %lu.%09lu # %s"
             "local-host: %s\n",
             desc->name,
             now_ach.tv_sec, now_ach.tv_nsec,
             now_real.tv_sec, now_real.tv_nsec, now_real_str,
             host );
    if( passwd ) {
        fprintf( desc->fout,
                 "user: %s # %s\n",
                 passwd->pw_name, passwd->pw_gecos
            );
    }
    fputs( ".\n", desc->fout );

    if( fflush(desc->fout) ) {
        ACH_LOG( LOG_ERR, "Could not flush file %s: %s\n",
                 desc->name, strerror(errno) );
    }

    size_t max = 512;
    ach_pipe_frame_t *frame = ach_pipe_alloc( max );

    /* get frames */
    int canceled = 0;
    while( ! canceled ) {
        /* push the data */
        size_t frame_size;
        ach_status_t r = ach_get( &desc->chan, frame->data, max, &frame_size,  NULL,
                                  ACH_O_WAIT | ((opt_last ) ? ACH_O_LAST : 0) );
        switch(r) {
        case ACH_OVERFLOW:
            /* enlarge buffer and retry on overflow */
            assert(frame_size > max );
            max = frame_size;
            free(frame);
            frame = ach_pipe_alloc( max );
            continue;
        case ACH_MISSED_FRAME:
        case ACH_OK:
        {
            ach_pipe_set_size( frame, frame_size );
            size_t size = sizeof(ach_pipe_frame_t) - 1 + frame_size;
            size_t s = fwrite( frame, 1, size, desc->fout );
            if( s != size ) {
                ACH_LOG( LOG_ERR, "Could not write frame to %s, %"PRIuPTR" written instead of %"PRIuPTR"\n",
                         desc->name, s, size );
                canceled = 1;
            }
        }
        break;
        case ACH_CANCELED:
            canceled = 1;
            break;
        default:
            ACH_LOG( LOG_ERR, "Could not get frame from %s: %s\n",
                     desc->name, strerror(errno) );
            canceled = 1;
            break;
        }
    }

    /* sync */
    if( fflush(desc->fout) ) {
        ACH_LOG( LOG_ERR, "Could not flush file %s: %s\n",
                 desc->name, strerror(errno) );
    }
    return arg;
}
Ejemplo n.º 9
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;
}