static void server_loop(int fd) { struct timeval snaptime = { 0 }; struct pollfd p; p.fd = fd; p.events = p.revents = POLLIN; sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d", getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000); load_info(); for (;;) { int status; time_t tdiff; struct timeval now; gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); if (tdiff >= scan_interval) { update_db(tdiff); snaptime = now; tdiff = 0; } if (poll(&p, 1, scan_interval - tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); if (clnt >= 0) { pid_t pid; if (children >= 5) { close(clnt); } else if ((pid = fork()) != 0) { if (pid > 0) children++; close(clnt); } else { FILE *fp = fdopen(clnt, "w"); if (fp) dump_raw_db(fp, 0); exit(0); } } } while (children && waitpid(-1, &status, WNOHANG) > 0) children--; } }
static void server_loop(int fd) { struct timeval snaptime; struct pollfd p; memset(&snaptime, 0, sizeof(snaptime)); p.fd = fd; p.events = p.revents = POLLIN; load_info(); for (;;) { int status; int tdiff; struct timeval now; gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); // if (tdiff >= 0) { update_db(tdiff); snaptime = now; tdiff = 0; // } if (poll(&p, 1, conf.scan_interval-tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); if (clnt >= 0) { pid_t pid; /* We assume forking will be ok so update database here not have races with forked process */ gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); // if (tdiff >= min_interval) { update_db(tdiff); snaptime = now; tdiff = 0; // } poll_client(clnt); sprintf(info_source, "pid=%d sampling_interval=%d " "time_const=%d", getpid(), conf.scan_interval/1000, conf.time_constant/1000); if (children >= 5) { close(clnt); } else if ((pid = fork()) != 0) { if (pid>0) children++; close(clnt); } else { FILE *fp = fdopen(clnt, "w"); if (fp) { /* Write on clients socket */ dump_raw_db(fp); } exit(0); } } } while (children && waitpid(-1, &status, WNOHANG) > 0) children--; } }
int main(int argc, char *argv[]) { char hist_name[128]; struct sockaddr_un sun; FILE *hist_fp = NULL; int ch; int fd; while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:e", longopts, NULL)) != EOF) { switch (ch) { case 'z': dump_zeros = 1; break; case 'r': reset_history = 1; break; case 'a': ignore_history = 1; break; case 's': no_update = 1; break; case 'n': no_output = 1; break; case 'e': show_errors = 1; break; case 'j': json_output = 1; break; case 'p': pretty = 1; break; case 'd': scan_interval = atoi(optarg) * 1000; if (scan_interval <= 0) { fprintf(stderr, "ifstat: invalid scan interval\n"); exit(-1); } break; case 't': time_constant = atoi(optarg); if (time_constant <= 0) { fprintf(stderr, "ifstat: invalid time constant divisor\n"); exit(-1); } break; case 'v': case 'V': printf("ifstat utility, iproute2-ss%s\n", SNAPSHOT); exit(0); case 'h': case '?': default: usage(); } } argc -= optind; argv += optind; sun.sun_family = AF_UNIX; sun.sun_path[0] = 0; sprintf(sun.sun_path+1, "ifstat%d", getuid()); if (scan_interval > 0) { if (time_constant == 0) time_constant = 60; time_constant *= 1000; W = 1 - 1/exp(log(10)*(double)scan_interval/time_constant); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("ifstat: socket"); exit(-1); } if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { perror("ifstat: bind"); exit(-1); } if (listen(fd, 5) < 0) { perror("ifstat: listen"); exit(-1); } if (daemon(0, 0)) { perror("ifstat: daemon"); exit(-1); } signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, sigchild); server_loop(fd); exit(0); } patterns = argv; npatterns = argc; if (getenv("IFSTAT_HISTORY")) snprintf(hist_name, sizeof(hist_name), "%s", getenv("IFSTAT_HISTORY")); else snprintf(hist_name, sizeof(hist_name), "%s/.ifstat.u%d", P_tmpdir, getuid()); if (reset_history) unlink(hist_name); if (!ignore_history || !no_update) { struct stat stb; fd = open(hist_name, O_RDWR|O_CREAT|O_NOFOLLOW, 0600); if (fd < 0) { perror("ifstat: open history file"); exit(-1); } if ((hist_fp = fdopen(fd, "r+")) == NULL) { perror("ifstat: fdopen history file"); exit(-1); } if (flock(fileno(hist_fp), LOCK_EX)) { perror("ifstat: flock history file"); exit(-1); } if (fstat(fileno(hist_fp), &stb) != 0) { perror("ifstat: fstat history file"); exit(-1); } if (stb.st_nlink != 1 || stb.st_uid != getuid()) { fprintf(stderr, "ifstat: something is so wrong with history file, that I prefer not to proceed.\n"); exit(-1); } if (!ignore_history) { FILE *tfp; long uptime = -1; if ((tfp = fopen("/proc/uptime", "r")) != NULL) { if (fscanf(tfp, "%ld", &uptime) != 1) uptime = -1; fclose(tfp); } if (uptime >= 0 && time(NULL) >= stb.st_mtime+uptime) { fprintf(stderr, "ifstat: history is aged out, resetting\n"); if (ftruncate(fileno(hist_fp), 0)) perror("ifstat: ftruncate"); } } load_raw_table(hist_fp); hist_db = kern_db; kern_db = NULL; } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 && (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0 || (strcpy(sun.sun_path+1, "ifstat0"), connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) && verify_forging(fd) == 0) { FILE *sfp = fdopen(fd, "r"); load_raw_table(sfp); if (hist_db && source_mismatch) { fprintf(stderr, "ifstat: history is stale, ignoring it.\n"); hist_db = NULL; } fclose(sfp); } else { if (fd >= 0) close(fd); if (hist_db && info_source[0] && strcmp(info_source, "kernel")) { fprintf(stderr, "ifstat: history is stale, ignoring it.\n"); hist_db = NULL; info_source[0] = 0; } load_info(); if (info_source[0] == 0) strcpy(info_source, "kernel"); } if (!no_output) { if (ignore_history || hist_db == NULL) dump_kern_db(stdout); else dump_incr_db(stdout); } if (!no_update) { if (ftruncate(fileno(hist_fp), 0)) perror("ifstat: ftruncate"); rewind(hist_fp); json_output = 0; dump_raw_db(hist_fp, 1); fclose(hist_fp); } exit(0); }