int main (int argc, char *argv[]) { Arguments args; int i, use_taskstat; int in_initrd, clean_environment = 1; int stat_fd, disk_fd, uptime_fd, meminfo_fd, pid, ret = 1; PidScanner *scanner = NULL; unsigned long reltime = 0; BufferFile *stat_file, *disk_file, *per_pid_file, *meminfo_file; PidEventClosure pid_ev_cl; int *fds[] = { &stat_fd, &disk_fd, &uptime_fd, &meminfo_fd, NULL }; const char *fd_names[] = { "/stat", "/diskstats", "/uptime", "/meminfo", NULL }; StackMap map = STACK_MAP_INIT; /* make me findable */ arguments_set_defaults (&args); arguments_parse (&args, argc, argv); if (args.usleep_time > 0) { usleep (args.usleep_time); return 0; } if (enter_environment (args.console_debug)) return 1; fprintf (stderr, "bootchart-collector started as pid %d with %d args: ", (int) getpid(), argc - 1); for (i = 1; i < argc; i++) fprintf (stderr, "'%s' ", argv[i]); fprintf (stderr, "\n"); if (args.dump_path) { Arguments remote_args; ret = buffers_extract_and_dump (args.dump_path, &remote_args); ret |= dump_header (args.dump_path); if (!remote_args.relative_time) ret |= dump_dmsg (args.dump_path); if (!ret) cleanup_dev (); goto exit; } if (!args.relative_time) { /* manually started */ in_initrd = am_in_initrd (); if (in_initrd && sanity_check_initrd ()) goto exit; } pid = bootchart_find_running_pid (NULL); if (args.probe_running) { clean_environment = pid < 0; ret = pid < 0; goto exit; } else { if (pid >= 0) { clean_environment = 0; fprintf (stderr, "bootchart collector already running as pid %d, exiting...\n", pid); goto exit; } } /* defaults */ if (!args.hz) args.hz = 50; for (i = 0; fds [i]; i++) { char *path = malloc (strlen (PROC_PATH) + strlen (fd_names[i]) + 1); strcpy (path, PROC_PATH); strcat (path, fd_names[i]); *fds[i] = open (path, O_RDONLY); if (*fds[i] < 0) { fprintf (stderr, "error opening '%s': %s'\n", path, strerror (errno)); exit (1); } } stat_file = buffer_file_new (&map, "proc_stat.log"); disk_file = buffer_file_new (&map, "proc_diskstats.log"); if ( (use_taskstat = init_taskstat()) ) per_pid_file = buffer_file_new (&map, "taskstats.log"); else per_pid_file = buffer_file_new (&map, "proc_ps.log"); meminfo_file = buffer_file_new (&map, "proc_meminfo.log"); pid_ev_cl.cmdline_file = buffer_file_new (&map, "cmdline2.log"); pid_ev_cl.paternity_file = buffer_file_new (&map, "paternity.log"); if (!stat_file || !disk_file || !per_pid_file || !meminfo_file || !pid_ev_cl.cmdline_file || !pid_ev_cl.paternity_file) { fprintf (stderr, "Error allocating output buffers\n"); return 1; } scanner = pid_scanner_new_netlink (pid_event_cb, &pid_ev_cl); if (!scanner) scanner = pid_scanner_new_proc (PROC_PATH, pid_event_cb, &pid_ev_cl); if (!scanner) return 1; if (args.relative_time) { reltime = get_uptime (uptime_fd); if (! reltime) exit (1); } while (1) { pid_t pid; char uptime[80]; size_t uptimelen; unsigned long u; if (in_initrd) { if (have_dev_tmpfs ()) { if (chroot_into_dev ()) { fprintf (stderr, "failed to chroot into /dev - exiting so run_init can proceed\n"); return 1; } in_initrd = 0; } } u = get_uptime (uptime_fd); if (!u) return 1; uptimelen = sprintf (uptime, "%lu\n", u - reltime); buffer_file_dump_frame_with_timestamp (stat_file, stat_fd, uptime, uptimelen); buffer_file_dump_frame_with_timestamp (disk_file, disk_fd, uptime, uptimelen); buffer_file_dump_frame_with_timestamp (meminfo_file, meminfo_fd, uptime, uptimelen); /* output data for each pid */ buffer_file_append (per_pid_file, uptime, uptimelen); pid_scanner_restart (scanner); while ((pid = pid_scanner_next (scanner))) { if (use_taskstat) dump_taskstat (per_pid_file, scanner); else dump_proc_stat (per_pid_file, pid); } buffer_file_append (per_pid_file, "\n", 1); usleep (1000000 / args.hz); } /* * In reality - we are always killed before we reach * this point */ if (use_taskstat) { if (close (netlink_socket) < 0) { perror ("failed to close netlink socket"); exit (1); } } for (i = 0; fds [i]; i++) { if (close (*fds[i]) < 0) { fprintf (stderr, "error closing file '%s': %s'\n", fd_names[i], strerror (errno)); return 1; } } ret = 0; exit: arguments_free (&args); if (scanner) ret |= pid_scanner_free (scanner); if (clean_environment) clean_enviroment(); return ret; }
/* * finds (another) bootchart-collector process and * returns it's pid (or -1) if not found, ignores * the --usleep mode we use to simplify our scripts. */ int bootchart_find_running_pid (Arguments *opt_args) { DIR *proc; struct dirent *ent; int pid = -1; char exe_path[1024]; Arguments sargs, *args; if (opt_args) { args = opt_args; } else { args = &sargs; arguments_set_defaults (args); } proc = opendir (PROC_PATH); while ((ent = readdir (proc)) != NULL) { int len; char link_target[1024]; if (!isdigit (ent->d_name[0])) continue; strcpy (exe_path, PROC_PATH); strcat (exe_path, "/"); strcat (exe_path, ent->d_name); strcat (exe_path, "/exe"); if ((len = readlink (exe_path, link_target, 1024-1)) < 0) continue; link_target[len] = '\0'; if (strstr (link_target, PROGRAM_PREFIX "bootchart" PROGRAM_SUFFIX "-collector")) { FILE *argf; int harmless = 0; int p = atoi (ent->d_name); /* log ("found collector '%s' pid %d (my pid %d)\n", link_target, p, getpid()); */ if (p == getpid()) continue; /* I'm not novel */ strcpy (exe_path + strlen (exe_path) - strlen ("/exe"), "/cmdline"); argf = fopen (exe_path, "r"); if (argf) { int i; char abuffer[4096]; len = fread (abuffer, 1, 4095, argf); if (len > 0) { /* step through args */ int argc; char *argv[128]; abuffer[len] = '\0'; argv[0] = abuffer; for (argc = i = 0; i < len && argc < 127; i++) { if (abuffer[i] == '\0') argv[++argc] = abuffer + i + 1; } arguments_set_defaults (args); arguments_parse (args, argc, argv); if (args->usleep_time) harmless = 1; } fclose (argf); } if (!harmless) { pid = p; break; } } } closedir (proc); if (args == &sargs) arguments_free (&sargs); return pid; }