1e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley/* bootchartd.c - bootchartd is commonly used to profile the boot process.
2e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley *
3e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
4e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley * Copyright 2014 Kyungwan Han <asura321@gmail.com>
5e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley *
6e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley * No Standard
7e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
8098ff070fdafc1b3f5ec037a8b17365a176ec184Rob LandleyUSE_BOOTCHARTD(NEWTOY(bootchartd, 0, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
9e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
10e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleyconfig BOOTCHARTD
11e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  bool "bootchartd"
12e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  default n
13e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  help
14098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    usage: bootchartd {start [PROG ARGS]}|stop|init
15e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
16e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    Create /var/log/bootlog.tgz with boot chart data
17e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
18098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    start: start background logging; with PROG, run PROG,
19098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley           then kill logging with USR1
20e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    stop:  send USR1 to all bootchartd processes
21098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    init:  start background logging; stop when getty/xdm is seen
22098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley          (for init scripts)
23098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
24e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    Under PID 1: as init, then exec $bootchart_init, /init, /sbin/init
25e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley*/
26098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
27e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley#define FOR_bootchartd
28e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley#include "toys.h"
29e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
30e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob LandleyGLOBALS(
31e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  char buf[32];
32e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  long smpl_period_usec;
33e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int proc_accounting;
34e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int is_login;
35098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
36098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  void *head;
37e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley)
38e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
39e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystruct pid_list {
40098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  struct pid_list *next, *prev;
41e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int pid;
42e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley};
43e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
44e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic int push_pids_in_list(pid_t pid, char *name)
45e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
46098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  struct pid_list *new = xzalloc(sizeof(struct pid_list));
47098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
48098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  new->pid = pid;
49098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  dlist_add_nomalloc((void *)&TT.head, (void *)new);
50098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
51e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  return 0;
52e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
53e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
54e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic void dump_data_in_file(char *fname, int wfd)
55e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
56e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int rfd = open(fname, O_RDONLY);
57e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
58e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (rfd != -1) {
59e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    xwrite(wfd, TT.buf, strlen(TT.buf));
60e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    xsendfile(rfd, wfd);
61e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    close(rfd);
62e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    xwrite(wfd, "\n", 1);
63e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
64e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
65e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
66e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic int dump_proc_data(FILE *fp)
67e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
68e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  struct dirent *pid_dir;
69e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int login_flag = 0;
70e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  pid_t pid;
71e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  DIR *proc_dir = opendir("/proc");
72e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
73e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fputs(TT.buf, fp);
74e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  while ((pid_dir = readdir(proc_dir))) {
75e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    char filename[64];
76e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    int fd;
77e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
78e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!isdigit(pid_dir->d_name[0])) continue;
79e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    sscanf(pid_dir->d_name, "%d", &pid);
80e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    sprintf(filename, "/proc/%d/stat", pid);
81e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if ((fd = open(filename, O_RDONLY)) != -1 ) {
82e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      char *ptr;
83e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      ssize_t len;
84e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
8514a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma      if ((len = readall(fd, toybuf, sizeof(toybuf)-1)) < 0) {
8614a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma        xclose(fd);
8714a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma        continue;
8814a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma      }
89e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      toybuf[len] = '\0';
90e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      close(fd);
91e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      fputs(toybuf, fp);
92e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (!TT.is_login) continue;
93e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if ((ptr = strchr(toybuf, '('))) {
94e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        char *tmp = strchr(++ptr, ')');
95e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
96e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        if (tmp) *tmp = '\0';
97e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      }
98e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      // Checks for gdm, kdm or getty
99e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (((ptr[0] == 'g' || ptr[0] == 'k' || ptr[0] == 'x') && ptr[1] == 'd'
100e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley            && ptr[2] == 'm') || strstr(ptr, "getty")) login_flag = 1;
101e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    }
102e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
103e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  closedir(proc_dir);
104e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fputc('\n', fp);
105e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  return login_flag;
106e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
107e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
108e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic int parse_config_file(char *fname)
109e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
110e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  size_t len = 0;
111e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  char  *line = NULL;
112e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  FILE *fp = fopen(fname, "r");
113e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
114e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (!fp) return 0;
115e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  for (;getline(&line, &len, fp) != -1; line = NULL) {
116e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    char *ptr = line;
117e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
118e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    while (*ptr == ' ' || *ptr == '\t') ptr++;
119e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!*ptr || *ptr == '#' || *ptr == '\n') continue;
120e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!strncmp(ptr, "SAMPLE_PERIOD", strlen("SAMPLE_PERIOD"))) {
121e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      double smpl_val;
122e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
123e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if ((ptr = strchr(ptr, '='))) ptr += 1;
124e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      else continue;
125e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      sscanf(ptr, "%lf", &smpl_val);
126e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      TT.smpl_period_usec = smpl_val * 1000000;
127e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (TT.smpl_period_usec <= 0) TT.smpl_period_usec = 1;
128e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    }
129e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!strncmp(ptr, "PROCESS_ACCOUNTING", strlen("PROCESS_ACCOUNTING"))) {
130e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if ((ptr = strchr(ptr, '='))) ptr += 1;
131e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      else continue;
132e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      sscanf(ptr, "%s", toybuf);  // string will come with double quotes.
133e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (!(strncmp(toybuf+1, "on", strlen("on"))) ||
134e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley          !(strncmp(toybuf+1, "yes", strlen("yes")))) TT.proc_accounting = 1;
135e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    }
136e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    free(line);
137e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
138e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fclose(fp);
139e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  return 1;
140e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
141e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
142e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic char *create_tmp_dir()
143e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
144e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  char *dir_list[] = {"/tmp", "/mnt", "/boot", "/proc"}, **target = dir_list;
145e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  char *dir, dir_path[] = "/tmp/bootchart.XXXXXX";
146e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
147e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if ((dir = mkdtemp(dir_path))) {
148e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    xchdir((dir = xstrdup(dir)));
149e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    return dir;
150e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
151e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  while (mount("none", *target, "tmpfs", (1<<15), "size=16m")) //MS_SILENT
152e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!++target) perror_exit("can't mount tmpfs");
153e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  xchdir(*target);
154e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (umount2(*target, MNT_DETACH)) perror_exit("Can't unmount tmpfs");
155e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  return *target;
156e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
157e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
158e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic void start_logging()
159e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
160e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int proc_stat_fd = xcreate("proc_stat.log",
161e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      O_WRONLY | O_CREAT | O_TRUNC, 0644);
162e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int proc_diskstats_fd = xcreate("proc_diskstats.log",
163e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      O_WRONLY | O_CREAT | O_TRUNC, 0644);
164e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  FILE *proc_ps_fp = xfopen("proc_ps.log", "w");
165e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  long tcnt = 60 * 1000 * 1000 / TT.smpl_period_usec;
166e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
167e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (tcnt <= 0) tcnt = 1;
168e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (TT.proc_accounting) {
169e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    int kp_fd = xcreate("kernel_procs_acct", O_WRONLY | O_CREAT | O_TRUNC,0666);
170e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
171e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    xclose(kp_fd);
172e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    acct("kernel_procs_acct");
173e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
174e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  memset(TT.buf, 0, sizeof(TT.buf));
175f8e940c52cd4016821e582cfbf1458084d4229c8Rob Landley  while (--tcnt && !toys.signal) {
176e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    int i = 0, j = 0, fd = open("/proc/uptime", O_RDONLY);
177e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (fd < 0) goto wait_usec;
178e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    char *line = get_line(fd);
179e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
180e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (!line)  goto wait_usec;
181e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    while (line[i] != ' ') {
182e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (line[i] == '.') {
183e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        i++;
184e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        continue;
185e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      }
186e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      TT.buf[j++] = line[i++];
187e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    }
188e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    TT.buf[j++] = '\n';
189e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    TT.buf[j] = '\0';
190e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    free(line);
191e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    close(fd);
192e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    dump_data_in_file("/proc/stat", proc_stat_fd);
193e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    dump_data_in_file("/proc/diskstats", proc_diskstats_fd);
194e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    // stop proc dumping in 2 secs if getty or gdm, kdm, xdm found
195e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (dump_proc_data(proc_ps_fp))
196e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      if (tcnt > 2 * 1000 * 1000 / TT.smpl_period_usec)
197e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        tcnt = 2 * 1000 * 1000 / TT.smpl_period_usec;
198e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    fflush(NULL);
199e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleywait_usec:
200e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    usleep(TT.smpl_period_usec);
201e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
202e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  xclose(proc_stat_fd);
203e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  xclose(proc_diskstats_fd);
204e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fclose(proc_ps_fp);
205e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
206e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
207e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleystatic void stop_logging(char *tmp_dir, char *prog)
208e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
209e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  char host_name[32];
210e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  int kcmd_line_fd;
211e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  time_t t;
212e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  struct tm st;
213e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  struct utsname uts;
214e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  FILE *hdr_fp = xfopen("header", "w");
215e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
216e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (TT.proc_accounting) acct(NULL);
217e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (prog) fprintf(hdr_fp, "profile.process = %s\n", prog);
218e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  gethostname(host_name, sizeof(host_name));
219e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  time(&t);
220e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  localtime_r(&t, &st);
221e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  memset(toybuf, 0, sizeof(toybuf));
222e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  strftime(toybuf, sizeof(toybuf), "%a %b %e %H:%M:%S %Z %Y", &st);
223e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fprintf(hdr_fp, "version = TBX_BCHARTD_VER 1.0.0\n");
224e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fprintf(hdr_fp, "title = Boot chart for %s (%s)\n", host_name, toybuf);
225e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (uname(&uts) < 0) perror_exit("uname");
226e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fprintf(hdr_fp, "system.uname = %s %s %s %s\n", uts.sysname, uts.release,
227e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      uts.version, uts.machine);
228e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  memset(toybuf, 0, sizeof(toybuf));
229e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if ((kcmd_line_fd = open("/proc/cmdline", O_RDONLY)) != -1) {
230e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    ssize_t len;
231098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
23214a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma    if ((len = readall(kcmd_line_fd, toybuf, sizeof(toybuf)-1)) > 0) {
23314a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma      toybuf[len] = 0;
23414a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma      while (--len >= 0 && !toybuf[len]) continue;
23514a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma      for (; len > 0; len--) if (toybuf[len] < ' ') toybuf[len] = ' ';
23614a11ed5ebfb2309a3fdfea1ce7a741519e44693Ashwini Sharma    } else *toybuf = 0;
237e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
238e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fprintf(hdr_fp, "system.kernel.options = %s", toybuf);
239e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  close(kcmd_line_fd);
240e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  fclose(hdr_fp);
241e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  memset(toybuf, 0, sizeof(toybuf));
242e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  snprintf(toybuf, sizeof(toybuf), "tar -zcf /var/log/bootlog.tgz header %s *.log",
243e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      TT.proc_accounting ? "kernel_procs_acct" : "");
244e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  system(toybuf);
245e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (tmp_dir) {
246e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    unlink("header");
247e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    unlink("proc_stat.log");
248e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    unlink("proc_diskstats.log");
249e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    unlink("proc_ps.log");
250e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (TT.proc_accounting) unlink("kernel_procs_acct");
251e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    rmdir(tmp_dir);
252e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
253e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
254e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
255e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landleyvoid bootchartd_main()
256e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley{
257e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  pid_t lgr_pid, self_pid = getpid();
258098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  int bchartd_opt = 0; // 0=PID1, 1=start, 2=stop, 3=init
259e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  TT.smpl_period_usec = 200 * 1000;
260e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
261098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  TT.is_login = (self_pid == 1);
262098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  if (*toys.optargs) {
263098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    if (!strcmp("start", *toys.optargs)) bchartd_opt = 1;
264098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    else if (!strcmp("stop", *toys.optargs)) bchartd_opt = 2;
265098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    else if (!strcmp("init", *toys.optargs)) bchartd_opt = 3;
266098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    else error_exit("Unknown option '%s'", *toys.optargs);
267098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
268e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (bchartd_opt == 2) {
269e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      struct pid_list *temp;
270e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      char *process_name[] = {"bootchartd", NULL};
271e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
272e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      names_to_pid(process_name, push_pids_in_list);
273098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley      temp = TT.head;
274098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley      if (temp) temp->prev->next = 0;
275098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley      for (; temp; temp = temp->next)
276e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley        if (temp->pid != self_pid) kill(temp->pid, SIGUSR1);
277098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley      llist_traverse(TT.head, free);
278098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
279e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley      return;
280e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    }
281098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  } else if (!TT.is_login) error_exit("not PID 1");
282098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley
283e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  // Execute the code below for start or init or PID1
284e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (!parse_config_file("bootchartd.conf"))
285e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    parse_config_file("/etc/bootchartd.conf");
286e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
287e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  memset(toybuf, 0, sizeof(toybuf));
288d8872c43b48eae5501998a4e5a84337017d8fbe6Rob Landley  if (!(lgr_pid = xfork())) {
289e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    char *tmp_dir = create_tmp_dir();
290e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
291f8e940c52cd4016821e582cfbf1458084d4229c8Rob Landley    sigatexit(generic_signal);
292e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    raise(SIGSTOP);
293098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    if (!bchartd_opt && !getenv("PATH"))
294098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley      putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin");
295e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    start_logging();
296e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    stop_logging(tmp_dir, bchartd_opt == 1 ? toys.optargs[1] : NULL);
297e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    return;
298e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
299e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  waitpid(lgr_pid, NULL, WUNTRACED);
300e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  kill(lgr_pid, SIGCONT);
301e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
302098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley  if (!bchartd_opt) {
303e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    char *pbchart_init = getenv("bootchart_init");
304e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
305e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    if (pbchart_init) execl(pbchart_init, pbchart_init, NULL);
306098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    execl("/init", "init", (void *)0);
307098ff070fdafc1b3f5ec037a8b17365a176ec184Rob Landley    execl("/sbin/init", "init", (void *)0);
308e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
309e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  if (bchartd_opt == 1 && toys.optargs[1]) {
310e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    pid_t prog_pid;
311e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley
312c0045207a7cd3bc11aace920d895c69b027c16afRob Landley    if (!(prog_pid = xfork())) xexec(toys.optargs+1);
313e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    waitpid(prog_pid, NULL, 0);
314e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley    kill(lgr_pid, SIGUSR1);
315e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley  }
316e9b7fcf57bbc6c7ad58592f7ab9bd3224ef4aae1Rob Landley}
317