static error_t handle_option(int key, char* arg, struct argp_state *state) { error_t err = 0; arguments* config = (arguments*) state->input; switch (key) { case ARGP_KEY_INIT: state->child_inputs[0] = config; break; case OPTION_KERN_COLOR: err = parse_option_arg_string(arg, &config->common_config.bar->sections[0]->color); break; case OPTION_USER_COLOR: err = parse_option_arg_string(arg, &config->common_config.bar->sections[1]->color); break; case OPTION_NICE_COLOR: err = parse_option_arg_string(arg, &config->common_config.bar->sections[2]->color); break; case OPTION_IDLE_COLOR: err = parse_option_arg_string(arg, &config->common_config.bar->sections[3]->color); break; case OPTION_CPU_INDEX: config->cpu_index = parse_unsigned_int(arg, NULL); break; default: err = ARGP_ERR_UNKNOWN; break; } return err; }
/** * Parse CPU field from stat. * * @param stat Contents of the /proc/stat file * @param size Size of the content * @param field Name of the field to parse, e.g. "cpu" or "cpu1", zero terminated * @param kern On return, contains the parsed value or zero. * @param user On return, contains the parsed value or zero. * @param nice On return, contains the parsed value or zero. * @param idle On return, contains the parsed value or zero. * @return Zero on success, -1 if the field is not found. Note that any * parse errors are not detected. */ static int parse_stat(const char* stat, const unsigned int size, const char* field, unsigned int *kern, unsigned int *user, unsigned int *nice, unsigned int *idle) { const char* p = stat; unsigned int len = size; /* Initialize to zeros */ *kern = *user = *nice = *idle = 0; /* Find the field */ do { p = memstr(p, field, len); if (!p) { log_error("Field not found: %d", -1); return -1; } } while (p != stat && p[-1] != '\n' && p++ && (len = size - (p - stat))); /* Skip the label */ p += strlen(field); *user = parse_unsigned_int(p, &p); *nice = parse_unsigned_int(p, &p); *kern = parse_unsigned_int(p, &p); *idle = parse_unsigned_int(p, NULL); return 0; }
int main(int argc, char *argv[]) { int out_fd = -1, use_splice = 1, truncate = O_TRUNC, verboseness = 0; char *buf = NULL, *dev_path = DEV_PATH, *out_path = NULL; int restart_requested, dev_fd, pipe_in, pipe_out, pipe_fd[2]; ssize_t n, m; unsigned int snaplen = 0, buflen = 8192; ssize_t (*read_dev)(void); ssize_t (*write_out)(void); struct argp_option options[] = { {"append", 'a', 0, 0, "append new records instead of overwriting"}, {"device", 'd', "DEVICE", 0, "read events from DEVICE (default: " DEV_PATH ")"}, {"buflen", 'l', "BYTES", 0, "set buffer length; implies -n (default: 8192)"}, {"no-splice", 'n', 0, 0, "use read()/write() instead of splice"}, {"quiet", 'q', 0, 0, "decrease verboseness of debug output"}, {"snaplen", 's', "BYTES", 0, "set maximum packet capture size to BYTES bytes"}, {"verbose", 'v', 0, 0, "increase verboseness of debug output"}, {0}, }; error_t parse_opt(int key, char *arg, struct argp_state *state) { switch (key) { case 'a': truncate = 0; break; case 'd': dev_path = arg; break; case 'l': if (parse_unsigned_int(&buflen, arg)) argp_error(state, "invalid buflen: %s\n", arg); use_splice = 0; break; case 'n': use_splice = 0; break; case 'q': verboseness--; break; case 's': if (parse_unsigned_int(&snaplen, arg)) argp_error(state, "invalid snaplen: %s\n", arg); break; case 'v': verboseness++; break; case ARGP_KEY_ARG: if (!state->arg_num) out_path = arg; else return ARGP_ERR_UNKNOWN; break; default: return ARGP_ERR_UNKNOWN; } return 0; } struct argp argp = {options, parse_opt, "[OUTPUT_FILE]", "Read Hone events and write to a file or standard output.", NULL, NULL, NULL}; if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) err(EX_OSERR, "argp_parse() failed"); if (verboseness > 0) verbose1 = log_stderr; if (verboseness > 1) verbose2 = log_stderr; if (verboseness > 2) verbose3 = log_stderr; verbose2("Options:\n"); verbose2(" buffer size: "); if (use_splice) verbose2("unused\n"); else verbose2("%u\n", buflen); verbose2(" input device: %s\n", dev_path); verbose2(" output file: %s\n", out_path ?: "<standard output>"); verbose2(" snaplen: %u\n", snaplen); verbose2(" use splice: %s\n", use_splice ? "yes" : "no"); verbose2(" verbosity level: %d\n", verboseness); if (verboseness > 3) err(EX_USAGE, "verboseness limit exceeded"); signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGTERM, sighandler); ssize_t splice_read(void) { return splice(dev_fd, NULL, pipe_in, NULL, 65536, 0); } ssize_t splice_write(void) { return splice(pipe_out, NULL, out_fd, NULL, n, 0); } ssize_t conventional_read(void) { return read(dev_fd, buf, buflen); } ssize_t conventional_write(void) { return write(out_fd, buf, n); } if (use_splice) { if (pipe(pipe_fd)) err(EX_OSERR, "pipe() failed"); pipe_out = pipe_fd[0]; pipe_in = pipe_fd[1]; read_dev = splice_read; write_out = splice_write; } else { if (!(buf = (typeof(buf)) malloc(buflen))) err(EX_OSERR, "malloc() failed"); read_dev = conventional_read; write_out = conventional_write; } if ((dev_fd = open(dev_path, O_RDONLY, 0)) == -1) err(EX_NOINPUT, "open() failed on %s", dev_path); if (snaplen && ioctl(dev_fd, HEIO_SET_SNAPLEN, snaplen) == -1) err(EX_IOERR, "set snaplen ioctl() failed"); void close_out(void) { if (close(out_fd)) err(EX_OSERR, "close() failed on %s", out_path); out_fd = -1; } restart: restart = 0; restart_requested = 0; if (out_fd != -1) close_out(); if (!out_path || !strcmp(out_path, "-")) { if ((out_fd = dup(STDOUT_FILENO)) == -1) err(EX_CANTCREAT, "dup() failed on stdout"); } else { if ((out_fd = open(out_path, O_WRONLY | O_CREAT | O_LARGEFILE | truncate, 00664)) == -1) err(EX_CANTCREAT, "open() failed on %s", out_path); if (!truncate && lseek(out_fd, 0, SEEK_END) == (off_t) -1) err(EX_OSERR, "error seeking to end of output file"); } if (use_splice) { int is_fifo = 0; struct stat st; if (fstat(out_fd, &st)) warn("fstat() failed"); else is_fifo = S_ISFIFO(st.st_mode); pipe_in = is_fifo ? out_fd : pipe_fd[1]; verbose2("output file is%s a FIFO\n", is_fifo ? "" : " not"); } for (;;) { if ((restart || done) && !restart_requested) { if (ioctl(dev_fd, HEIO_RESTART) == -1) err(EX_OSERR, "reset ioctl() failed"); verbose1("Requesting device restart.\n"); restart_requested = 1; } if ((n = read_dev()) == -1) { if (errno != EINTR && errno != EAGAIN) err(EX_OSERR, "reading from device failed"); continue; } if (!n) { verbose1("Device restarted.\n"); if (done || ioctl(dev_fd, HEIO_GET_AT_HEAD) <= 0) break; verbose1("Reopening output file.\n"); goto restart; } verbose3("Read %ld bytes\n", n); if (out_fd == pipe_in) /* spliced directly to FIFO */ continue; while (n > 0) { if ((m = write_out()) == -1) { if (errno != EINTR && errno != EAGAIN) err(EX_OSERR, "writing to output failed"); continue; } verbose3("Wrote %ld bytes\n", m); n -= m; } } close_out(); close(dev_fd); close(pipe_fd[0]); close(pipe_fd[1]); free(buf); exit(EX_OK); }