diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-04 15:45:25 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-04 15:45:25 +0200 |
commit | ff027d6f50bfa24228e230b84a3297c51d37d000 (patch) | |
tree | 9131e36c21870d52b02c079fe877be8a5c87970c | |
parent | fe360480aa30adf776a06dc9f09c704abcfa9000 (diff) | |
download | busybox-w32-ff027d6f50bfa24228e230b84a3297c51d37d000.tar.gz busybox-w32-ff027d6f50bfa24228e230b84a3297c51d37d000.tar.bz2 busybox-w32-ff027d6f50bfa24228e230b84a3297c51d37d000.zip |
bootchartd: new applet
Usage: bootchartd start [PROG ARGS]|init|stop
Create /var/log/bootchart.tgz with boot chart data
Options:
start: start background logging; with PROG, run PROG, then kill
logging with USR1
stop: send USR1 to all bootchartd processes
init: start background logging; stop when getty/gdm is seen (for init scripts)
Under PID 1: as init, then exec $bootchart_init, /init, /sbin/init
function old new delta
bootchartd_main - 907 +907
dump_procs - 353 +353
packed_usage 26566 26735 +169
dump_file - 91 +91
static.dirs - 23 +23
applet_names 2176 2187 +11
applet_main 1284 1288 +4
applet_nameofs 642 644 +2
------------------------------------------------------------------------------
(add/remove: 5/0 grow/shrink: 4/0 up/down: 1560/0) Total: 1560 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/usage.h | 34 | ||||
-rw-r--r-- | init/Config.in | 14 | ||||
-rw-r--r-- | init/Kbuild | 7 | ||||
-rw-r--r-- | init/bootchartd.c | 355 |
5 files changed, 396 insertions, 15 deletions
diff --git a/include/applets.h b/include/applets.h index ef5dd781d..dfb20b9be 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -83,6 +83,7 @@ IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) | |||
83 | //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) | 83 | //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) |
84 | IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 84 | IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
85 | IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) | 85 | IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) |
86 | IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP)) | ||
86 | IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) | 87 | IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) |
87 | IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 88 | IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
88 | IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat)) | 89 | IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat)) |
diff --git a/include/usage.h b/include/usage.h index 2c2a90d16..636d01943 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -154,18 +154,15 @@ | |||
154 | "\n -r Repetitions" \ | 154 | "\n -r Repetitions" \ |
155 | "\n -n Start new tone" \ | 155 | "\n -n Start new tone" \ |
156 | 156 | ||
157 | #define fbsplash_trivial_usage \ | 157 | #define bootchartd_trivial_usage \ |
158 | "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" | 158 | "start [PROG ARGS]|stop|init" |
159 | #define fbsplash_full_usage "\n\n" \ | 159 | #define bootchartd_full_usage "\n\n" \ |
160 | "Options:" \ | 160 | "Create /var/log/bootchart.tgz with boot chart data\n" \ |
161 | "\n -s Image" \ | 161 | "\nOptions:" \ |
162 | "\n -c Hide cursor" \ | 162 | "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" \ |
163 | "\n -d Framebuffer device (default /dev/fb0)" \ | 163 | "\nstop: send USR1 to all bootchartd processes" \ |
164 | "\n -i Config file (var=value):" \ | 164 | "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" \ |
165 | "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \ | 165 | "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" \ |
166 | "\n BAR_R,BAR_G,BAR_B" \ | ||
167 | "\n -f Control pipe (else exit after drawing image)" \ | ||
168 | "\n commands: 'NN' (% for progress bar) or 'exit'" \ | ||
169 | 166 | ||
170 | #define brctl_trivial_usage \ | 167 | #define brctl_trivial_usage \ |
171 | "COMMAND [BRIDGE [INTERFACE]]" | 168 | "COMMAND [BRIDGE [INTERFACE]]" |
@@ -1174,6 +1171,19 @@ | |||
1174 | "$ echo $?\n" \ | 1171 | "$ echo $?\n" \ |
1175 | "1\n" | 1172 | "1\n" |
1176 | 1173 | ||
1174 | #define fbsplash_trivial_usage \ | ||
1175 | "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" | ||
1176 | #define fbsplash_full_usage "\n\n" \ | ||
1177 | "Options:" \ | ||
1178 | "\n -s Image" \ | ||
1179 | "\n -c Hide cursor" \ | ||
1180 | "\n -d Framebuffer device (default /dev/fb0)" \ | ||
1181 | "\n -i Config file (var=value):" \ | ||
1182 | "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \ | ||
1183 | "\n BAR_R,BAR_G,BAR_B" \ | ||
1184 | "\n -f Control pipe (else exit after drawing image)" \ | ||
1185 | "\n commands: 'NN' (% for progress bar) or 'exit'" \ | ||
1186 | |||
1177 | #define fbset_trivial_usage \ | 1187 | #define fbset_trivial_usage \ |
1178 | "[OPTIONS] [MODE]" | 1188 | "[OPTIONS] [MODE]" |
1179 | #define fbset_full_usage "\n\n" \ | 1189 | #define fbset_full_usage "\n\n" \ |
diff --git a/init/Config.in b/init/Config.in index 3d99d4792..76d509207 100644 --- a/init/Config.in +++ b/init/Config.in | |||
@@ -120,4 +120,18 @@ config MESG | |||
120 | Mesg controls access to your terminal by others. It is typically | 120 | Mesg controls access to your terminal by others. It is typically |
121 | used to allow or disallow other users to write to your terminal | 121 | used to allow or disallow other users to write to your terminal |
122 | 122 | ||
123 | config BOOTCHARTD | ||
124 | bool "bootchartd" | ||
125 | default n | ||
126 | help | ||
127 | bootchartd is commonly used to profile the boot process | ||
128 | for the purpose of speeding it up. In this case, it is started | ||
129 | by the kernel as the init process. This is configured by adding | ||
130 | the init=/sbin/bootchartd option to the kernel command line. | ||
131 | |||
132 | It can also be used to monitor the resource usage of a specific | ||
133 | application or the running system in general. In this case, | ||
134 | bootchartd is started interactively by running bootchartd start | ||
135 | and stopped using bootchartd stop. | ||
136 | |||
123 | endmenu | 137 | endmenu |
diff --git a/init/Kbuild b/init/Kbuild index c060f3af4..ce3f30256 100644 --- a/init/Kbuild +++ b/init/Kbuild | |||
@@ -5,6 +5,7 @@ | |||
5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. | 5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. |
6 | 6 | ||
7 | lib-y:= | 7 | lib-y:= |
8 | lib-$(CONFIG_HALT) += halt.o | 8 | lib-$(CONFIG_HALT) += halt.o |
9 | lib-$(CONFIG_INIT) += init.o | 9 | lib-$(CONFIG_INIT) += init.o |
10 | lib-$(CONFIG_MESG) += mesg.o | 10 | lib-$(CONFIG_MESG) += mesg.o |
11 | lib-$(CONFIG_BOOTCHARTD) += bootchartd.o | ||
diff --git a/init/bootchartd.c b/init/bootchartd.c new file mode 100644 index 000000000..fccaaceb4 --- /dev/null +++ b/init/bootchartd.c | |||
@@ -0,0 +1,355 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
4 | */ | ||
5 | #include "libbb.h" | ||
6 | #include <sys/mount.h> | ||
7 | #ifndef MS_SILENT | ||
8 | # define MS_SILENT (1 << 15) | ||
9 | #endif | ||
10 | #ifndef MNT_DETACH | ||
11 | # define MNT_DETACH 0x00000002 | ||
12 | #endif | ||
13 | |||
14 | #define BC_VERSION_STR "0.8" | ||
15 | |||
16 | /* For debugging, set to 0: | ||
17 | * strace won't work with DO_SIGNAL_SYNC set to 1. | ||
18 | */ | ||
19 | #define DO_SIGNAL_SYNC 1 | ||
20 | |||
21 | |||
22 | //Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf | ||
23 | |||
24 | //# tmpfs size | ||
25 | //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) | ||
26 | //TMPFS_SIZE=32m | ||
27 | // | ||
28 | //# Sampling period (in seconds) | ||
29 | //SAMPLE_PERIOD=0.2 | ||
30 | // | ||
31 | //# Whether to enable and store BSD process accounting information. The | ||
32 | //# kernel needs to be configured to enable v3 accounting | ||
33 | //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities | ||
34 | //# is also required. | ||
35 | //PROCESS_ACCOUNTING="no" | ||
36 | // | ||
37 | //# Tarball for the various boot log files | ||
38 | //BOOTLOG_DEST=/var/log/bootchart.tgz | ||
39 | // | ||
40 | //# Whether to automatically stop logging as the boot process completes. | ||
41 | //# The logger will look for known processes that indicate bootup completion | ||
42 | //# at a specific runlevel (e.g. gdm-binary, mingetty, etc.). | ||
43 | //AUTO_STOP_LOGGER="yes" | ||
44 | // | ||
45 | //# Whether to automatically generate the boot chart once the boot logger | ||
46 | //# completes. The boot chart will be generated in $AUTO_RENDER_DIR. | ||
47 | //# Note that the bootchart package must be installed. | ||
48 | //AUTO_RENDER="no" | ||
49 | // | ||
50 | //# Image format to use for the auto-generated boot chart | ||
51 | //# (choose between png, svg and eps). | ||
52 | //AUTO_RENDER_FORMAT="png" | ||
53 | // | ||
54 | //# Output directory for auto-generated boot charts | ||
55 | //AUTO_RENDER_DIR="/var/log" | ||
56 | |||
57 | |||
58 | /* Globals */ | ||
59 | struct globals { | ||
60 | char jiffy_line[sizeof(bb_common_bufsiz1)]; | ||
61 | } FIX_ALIASING; | ||
62 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
63 | #define INIT_G() do { } while (0) | ||
64 | |||
65 | static void dump_file(FILE *fp, const char *filename) | ||
66 | { | ||
67 | int fd = open(filename, O_RDONLY); | ||
68 | if (fd >= 0) { | ||
69 | fputs(G.jiffy_line, fp); | ||
70 | fflush(fp); | ||
71 | bb_copyfd_eof(fd, fileno(fp)); | ||
72 | close(fd); | ||
73 | fputc('\n', fp); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static int dump_procs(FILE *fp, int look_for_login_process) | ||
78 | { | ||
79 | struct dirent *entry; | ||
80 | DIR *dir = opendir("/proc"); | ||
81 | int found_login_process = 0; | ||
82 | |||
83 | fputs(G.jiffy_line, fp); | ||
84 | while ((entry = readdir(dir)) != NULL) { | ||
85 | char name[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; | ||
86 | int stat_fd; | ||
87 | unsigned pid = bb_strtou(entry->d_name, NULL, 10); | ||
88 | if (errno) | ||
89 | continue; | ||
90 | |||
91 | /* Android's version reads /proc/PID/cmdline and extracts | ||
92 | * non-truncated process name. Do we want to do that? */ | ||
93 | |||
94 | sprintf(name, "/proc/%u/stat", pid); | ||
95 | stat_fd = open(name, O_RDONLY); | ||
96 | if (stat_fd >= 0) { | ||
97 | char *p; | ||
98 | char stat_line[4*1024]; | ||
99 | int rd = safe_read(stat_fd, stat_line, sizeof(stat_line)-2); | ||
100 | |||
101 | close(stat_fd); | ||
102 | if (rd < 0) | ||
103 | continue; | ||
104 | stat_line[rd] = '\0'; | ||
105 | p = strchrnul(stat_line, '\n'); | ||
106 | *p++ = '\n'; | ||
107 | *p = '\0'; | ||
108 | fputs(stat_line, fp); | ||
109 | if (!look_for_login_process) | ||
110 | continue; | ||
111 | p = strchr(stat_line, '('); | ||
112 | if (!p) | ||
113 | continue; | ||
114 | p++; | ||
115 | strchrnul(p, ')')[0] = '\0'; | ||
116 | /* If is gdm, kdm or a getty? */ | ||
117 | if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm') | ||
118 | || strstr(p, "getty") | ||
119 | ) { | ||
120 | found_login_process = 1; | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | closedir(dir); | ||
125 | fputc('\n', fp); | ||
126 | return found_login_process; | ||
127 | } | ||
128 | |||
129 | static char *make_tempdir(const char *prog) | ||
130 | { | ||
131 | char template[] = "/tmp/bootchart.XXXXXX"; | ||
132 | char *tempdir = xstrdup(mkdtemp(template)); | ||
133 | if (!tempdir) { | ||
134 | /* /tmp is not writable (happens when we are used as init). | ||
135 | * Try to mount a tmpfs, them cd and lazily unmount it. | ||
136 | * Since we unmount it at once, we can mount it anywhere. | ||
137 | * Try a few locations which are likely ti exist. | ||
138 | */ | ||
139 | static const char dirs[] = "/mnt\0""/tmp\0""/boot\0""/proc\0"; | ||
140 | const char *try_dir = dirs; | ||
141 | while (mount("none", try_dir, "tmpfs", MS_SILENT, "size=16m") != 0) { | ||
142 | try_dir += strlen(try_dir) + 1; | ||
143 | if (!try_dir[0]) | ||
144 | bb_perror_msg_and_die("can't %smount tmpfs", ""); | ||
145 | } | ||
146 | //bb_error_msg("mounted tmpfs on %s", try_dir); | ||
147 | xchdir(try_dir); | ||
148 | if (umount2(try_dir, MNT_DETACH) != 0) { | ||
149 | bb_perror_msg_and_die("can't %smount tmpfs", "un"); | ||
150 | } | ||
151 | } else { | ||
152 | xchdir(tempdir); | ||
153 | } | ||
154 | { | ||
155 | FILE *header_fp = xfopen("header", "w"); | ||
156 | if (prog) | ||
157 | fprintf(header_fp, "profile.process = %s\n", prog); | ||
158 | fputs("version = "BC_VERSION_STR"\n", header_fp); | ||
159 | fclose(header_fp); | ||
160 | } | ||
161 | |||
162 | return tempdir; | ||
163 | } | ||
164 | |||
165 | static void do_logging(void) | ||
166 | { | ||
167 | //# Enable process accounting if configured | ||
168 | //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then | ||
169 | // [ -e kernel_pacct ] || : > kernel_pacct | ||
170 | // accton kernel_pacct | ||
171 | //fi | ||
172 | |||
173 | FILE *proc_stat = xfopen("proc_stat.log", "w"); | ||
174 | FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); | ||
175 | //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); | ||
176 | FILE *proc_ps = xfopen("proc_ps.log", "w"); | ||
177 | int look_for_login_process = (getppid() == 1); | ||
178 | unsigned count = 60*1000*1000 / 200*1000; /* ~1 minute */ | ||
179 | |||
180 | while (--count && !bb_got_signal) { | ||
181 | char *p; | ||
182 | int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2); | ||
183 | if (len < 0) | ||
184 | goto wait_more; | ||
185 | /* /proc/uptime has format "NNNNNN.MM NNNNNNN.MM" */ | ||
186 | /* we convert it to "NNNNNNMM\n" (using first value) */ | ||
187 | G.jiffy_line[len] = '\0'; | ||
188 | p = strchr(G.jiffy_line, '.'); | ||
189 | if (!p) | ||
190 | goto wait_more; | ||
191 | while (isdigit(*++p)) | ||
192 | p[-1] = *p; | ||
193 | p[-1] = '\n'; | ||
194 | p[0] = '\0'; | ||
195 | |||
196 | dump_file(proc_stat, "/proc/stat"); | ||
197 | dump_file(proc_diskstats, "/proc/diskstats"); | ||
198 | //dump_file(proc_netdev, "/proc/net/dev"); | ||
199 | if (dump_procs(proc_ps, look_for_login_process)) { | ||
200 | /* dump_procs saw a getty or {g,k,x}dm | ||
201 | * stop logging in 2 seconds: | ||
202 | */ | ||
203 | if (count > 2*1000*1000 / 200*1000) | ||
204 | count = 2*1000*1000 / 200*1000; | ||
205 | } | ||
206 | fflush_all(); | ||
207 | wait_more: | ||
208 | usleep(200*1000); | ||
209 | } | ||
210 | |||
211 | // [ -e kernel_pacct ] && accton off | ||
212 | } | ||
213 | |||
214 | static void finalize(char *tempdir) | ||
215 | { | ||
216 | //# Stop process accounting if configured | ||
217 | //local pacct= | ||
218 | //[ -e kernel_pacct ] && pacct=kernel_pacct | ||
219 | |||
220 | //( | ||
221 | // echo "version = $VERSION" | ||
222 | // echo "title = Boot chart for $( hostname | sed q ) ($( date ))" | ||
223 | // echo "system.uname = $( uname -srvm | sed q )" | ||
224 | // echo "system.release = $( sed q /etc/SuSE-release )" | ||
225 | // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)" | ||
226 | // echo "system.kernel.options = $( sed q /proc/cmdline )" | ||
227 | //) >> header | ||
228 | |||
229 | /* Package log files */ | ||
230 | system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct | ||
231 | /* Clean up (if we are not in detached tmpfs) */ | ||
232 | if (tempdir) { | ||
233 | unlink("header"); | ||
234 | unlink("proc_stat.log"); | ||
235 | unlink("proc_diskstats.log"); | ||
236 | //unlink("proc_netdev.log"); | ||
237 | unlink("proc_ps.log"); | ||
238 | rmdir(tempdir); | ||
239 | } | ||
240 | |||
241 | /* shell-based bootchartd tries to run /usr/bin/bootchart if $AUTO_RENDER=yes: | ||
242 | * /usr/bin/bootchart -o "$AUTO_RENDER_DIR" -f $AUTO_RENDER_FORMAT "$BOOTLOG_DEST" | ||
243 | */ | ||
244 | } | ||
245 | |||
246 | /* Usage: | ||
247 | * bootchartd start [PROG ARGS]: start logging in background, USR1 stops it. | ||
248 | * With PROG, runs PROG, then kills background logging. | ||
249 | * bootchartd stop: same as "killall -USR1 bootchartd" | ||
250 | * bootchartd init: start logging in background | ||
251 | * Stop when getty/gdm is seen (if AUTO_STOP_LOGGER = yes). | ||
252 | * Meant to be used from init scripts. | ||
253 | * bootchartd (pid==1): as init, but then execs $bootchart_init, /init, /sbin/init | ||
254 | * Meant to be used as kernel's init process. | ||
255 | */ | ||
256 | int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
257 | int bootchartd_main(int argc UNUSED_PARAM, char **argv) | ||
258 | { | ||
259 | pid_t parent_pid, logger_pid; | ||
260 | smallint cmd; | ||
261 | enum { | ||
262 | CMD_STOP = 0, | ||
263 | CMD_START, | ||
264 | CMD_INIT, | ||
265 | CMD_PID1, /* used to mark pid 1 case */ | ||
266 | }; | ||
267 | |||
268 | INIT_G(); | ||
269 | |||
270 | parent_pid = getpid(); | ||
271 | if (argv[1]) { | ||
272 | cmd = index_in_strings("stop\0""start\0""init\0", argv[1]); | ||
273 | if (cmd < 0) | ||
274 | bb_show_usage(); | ||
275 | if (cmd == CMD_STOP) { | ||
276 | pid_t *pidList = find_pid_by_name("bootchartd"); | ||
277 | while (*pidList != 0) { | ||
278 | if (*pidList != parent_pid) | ||
279 | kill(*pidList, SIGUSR1); | ||
280 | pidList++; | ||
281 | } | ||
282 | return EXIT_SUCCESS; | ||
283 | } | ||
284 | } else { | ||
285 | if (parent_pid != 1) | ||
286 | bb_show_usage(); | ||
287 | cmd = CMD_PID1; | ||
288 | } | ||
289 | |||
290 | /* Here we are in START or INIT state. Create logger child: */ | ||
291 | logger_pid = fork_or_rexec(argv); | ||
292 | |||
293 | if (logger_pid == 0) { /* child */ | ||
294 | char *tempdir; | ||
295 | |||
296 | bb_signals(0 | ||
297 | + (1 << SIGUSR1) | ||
298 | + (1 << SIGUSR2) | ||
299 | + (1 << SIGTERM) | ||
300 | + (1 << SIGQUIT) | ||
301 | + (1 << SIGINT) | ||
302 | + (1 << SIGHUP) | ||
303 | , record_signo); | ||
304 | |||
305 | if (DO_SIGNAL_SYNC) | ||
306 | /* Inform parent that we are ready */ | ||
307 | raise(SIGSTOP); | ||
308 | |||
309 | /* If we started by kernel, PATH might be not set. | ||
310 | * And in order to run tar we may need PATH to be set: | ||
311 | */ | ||
312 | if (cmd == CMD_PID1 && !getenv("PATH")) | ||
313 | putenv((char*)bb_PATH_root_path); | ||
314 | tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL); | ||
315 | do_logging(); | ||
316 | finalize(tempdir); | ||
317 | return EXIT_SUCCESS; | ||
318 | } | ||
319 | |||
320 | /* parent */ | ||
321 | |||
322 | if (DO_SIGNAL_SYNC) { | ||
323 | /* Wait for logger child to set handlers, then unpause it. | ||
324 | * Otherwise with short-lived PROG (e.g. "bootchartd start true") | ||
325 | * we might send SIGUSR1 before logger sets its handler. | ||
326 | */ | ||
327 | waitpid(logger_pid, NULL, WUNTRACED); | ||
328 | kill(logger_pid, SIGCONT); | ||
329 | } | ||
330 | |||
331 | if (cmd == CMD_PID1) { | ||
332 | char *bootchart_init = getenv("bootchart_init"); | ||
333 | if (bootchart_init) | ||
334 | execl(bootchart_init, bootchart_init, NULL); | ||
335 | execl("/init", "init", NULL); | ||
336 | execl("/sbin/init", "init", NULL); | ||
337 | bb_perror_msg_and_die("can't exec '%s'", "/sbin/init"); | ||
338 | } | ||
339 | |||
340 | if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ | ||
341 | pid_t pid = vfork(); | ||
342 | if (pid < 0) | ||
343 | bb_perror_msg_and_die("vfork"); | ||
344 | if (pid == 0) { /* child */ | ||
345 | argv += 2; | ||
346 | execvp(argv[0], argv); | ||
347 | bb_perror_msg_and_die("can't exec '%s'", argv[0]); | ||
348 | } | ||
349 | /* parent */ | ||
350 | waitpid(pid, NULL, 0); | ||
351 | kill(logger_pid, SIGUSR1); | ||
352 | } | ||
353 | |||
354 | return EXIT_SUCCESS; | ||
355 | } | ||