static long ach_ch_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { /* TODO: Validate argument */ int ret = 0; struct ach_ch_file *ch_file = (struct ach_ch_file *)file->private_data; KDEBUG("ach: In ach_ch_ioctl\n"); switch (cmd) { case ACH_CH_SET_MODE: { struct achk_opt opt; if (copy_from_user(&opt, (void*)arg, sizeof(opt)) ) { ret = -EFAULT; } else { /* This is not threadsafe */ ch_file->mode = opt; /* if (ch_file->mode.reltime.tv_sec != 0 */ /* || ch_file->mode.reltime.tv_nsec != 0) */ /* KDEBUG("ach: Setting wait time to %ld.%09ld\n", */ /* ch_file->mode.reltime.tv_sec, */ /* ch_file->mode.reltime.tv_nsec); */ /* KDEBUG("ach: Got cmd ACH_CH_SET_MODE: \n"); */ /* KDEBUG1(" ACH_O_WAIT=%d\n", */ /* ch_file->mode.mode & ACH_O_WAIT); */ /* KDEBUG1(" ACH_O_LAST=%d\n", */ /* ch_file->mode.mode & ACH_O_LAST); */ /* KDEBUG1(" ACH_O_COPY=%d\n", */ /* ch_file->mode.mode & ACH_O_COPY); */ ret = 0; break; } } case ACH_CH_GET_MODE: { KDEBUG("ach: Got cmd ACH_CH_GET_MODE: %ld\n", arg); if( copy_to_user((void*)arg, &ch_file->mode, sizeof(ch_file->mode)) ) ret = -EFAULT; else ret = 0; break; } case ACH_CH_GET_STATUS: { KDEBUG("ach: Got cmd ACH_CH_GET_STATUS\n"); if (rt_mutex_lock_interruptible(&ch_file->shm->sync.mutex)) { ret = -ERESTARTSYS; break; } { struct ach_ch_status stat; struct ach_header *shm = ch_file->shm; ach_index_t *index_ar = ACH_SHM_INDEX(shm); size_t oldest_index = oldest_index_i(shm); uint64_t oldest_seq = index_ar[oldest_index].seq_num; stat.mode = ch_file->mode.options; stat.size = shm->len; stat.count = shm->index_cnt - shm->index_free; if (oldest_seq > ch_file->seq_num) { stat.new_msgs = shm->last_seq - oldest_seq; } else { stat.new_msgs = shm->last_seq - ch_file->seq_num; } stat.last_seq = shm->last_seq; stat.last_seq_read = ch_file->seq_num; printk(KERN_INFO "ach: Status:\n"); printk(KERN_INFO "ach: mode : %02x\n", stat.mode); printk(KERN_INFO "ach: size : %zu\n", stat.size); printk(KERN_INFO "ach: count: %zu\n", stat.count); printk(KERN_INFO "ach: new : %zu\n", stat.new_msgs); printk(KERN_INFO "ach: last_seq : %lu\n", stat.last_seq); printk(KERN_INFO "ach: last_seq_read : %lu\n", stat.last_seq_read); if (copy_to_user((void *)arg, &stat, sizeof(stat))) { ret = -EFAULT; } } rt_mutex_unlock(&ch_file->shm->sync.mutex); } case ACH_CH_FLUSH: KDEBUG("ach: Got cmd ACH_CH_FLUSH\n"); ret = -get_errno( ach_flush(ch_file) ); break; case ACH_CH_CANCEL: { unsigned int unsafe = (unsigned int)arg; KDEBUG("ach: Got cmd ACH_CH_CANCEL\n"); ret = -get_errno(ach_cancel(ch_file, unsafe)); break; } case ACH_CH_GET_OPTIONS: { struct ach_ch_options retval; retval.mode = ch_file->mode; retval.clock = ch_file->shm->clock; if( copy_to_user( (void*)arg, &retval, sizeof(retval) ) ) ret = -EFAULT; else ret = 0; break; } default: printk(KERN_ERR "ach: Unknown ioctl option: %d\n", cmd); ret = -ENOSYS; break; } return ret; }
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; }