aboutsummaryrefslogtreecommitdiff
path: root/init
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:08:20 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:08:20 +1000
commit6a6efd31038d7afe977e3059508ae863e65cbdf5 (patch)
tree5cd69a751e893b83176751c80fcea7a7afeed1ae /init
parenta6a2325ecf402054132daae169f71edb0fb849e3 (diff)
parent29082231d0cb1a5b327de5d515b16f332d4dbdaf (diff)
downloadbusybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.gz
busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.bz2
busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.zip
Merge branch 'origin/master' (early part)
Diffstat (limited to 'init')
-rw-r--r--init/Config.src14
-rw-r--r--init/bootchartd.c182
2 files changed, 134 insertions, 62 deletions
diff --git a/init/Config.src b/init/Config.src
index 2e9208150..590e29890 100644
--- a/init/Config.src
+++ b/init/Config.src
@@ -122,18 +122,4 @@ config MESG
122 Mesg controls access to your terminal by others. It is typically 122 Mesg controls access to your terminal by others. It is typically
123 used to allow or disallow other users to write to your terminal 123 used to allow or disallow other users to write to your terminal
124 124
125config BOOTCHARTD
126 bool "bootchartd"
127 default y
128 help
129 bootchartd is commonly used to profile the boot process
130 for the purpose of speeding it up. In this case, it is started
131 by the kernel as the init process. This is configured by adding
132 the init=/sbin/bootchartd option to the kernel command line.
133
134 It can also be used to monitor the resource usage of a specific
135 application or the running system in general. In this case,
136 bootchartd is started interactively by running bootchartd start
137 and stopped using bootchartd stop.
138
139endmenu 125endmenu
diff --git a/init/bootchartd.c b/init/bootchartd.c
index d1f9ed30e..dae2fe6e9 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -2,7 +2,49 @@
2/* 2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4 */ 4 */
5
6//config:config BOOTCHARTD
7//config: bool "bootchartd"
8//config: default y
9//config: help
10//config: bootchartd is commonly used to profile the boot process
11//config: for the purpose of speeding it up. In this case, it is started
12//config: by the kernel as the init process. This is configured by adding
13//config: the init=/sbin/bootchartd option to the kernel command line.
14//config:
15//config: It can also be used to monitor the resource usage of a specific
16//config: application or the running system in general. In this case,
17//config: bootchartd is started interactively by running bootchartd start
18//config: and stopped using bootchartd stop.
19//config:
20//config:config FEATURE_BOOTCHARTD_BLOATED_HEADER
21//config: bool "Compatible, bloated header"
22//config: default y
23//config: depends on BOOTCHARTD
24//config: help
25//config: Create extended header file compatible with "big" bootchartd.
26//config: "Big" bootchartd is a shell script and it dumps some
27//config: "convenient" info int the header, such as:
28//config: title = Boot chart for `hostname` (`date`)
29//config: system.uname = `uname -srvm`
30//config: system.release = `cat /etc/DISTRO-release`
31//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
32//config: system.kernel.options = `cat /proc/cmdline`
33//config: This data is not mandatory for bootchart graph generation,
34//config: and is considered bloat. Nevertheless, this option
35//config: makes bootchartd applet to dump a subset of it.
36//config:
37//config:config FEATURE_BOOTCHARTD_CONFIG_FILE
38//config: bool "Support bootchartd.conf"
39//config: default y
40//config: depends on BOOTCHARTD
41//config: help
42//config: Enable reading and parsing of $PWD/bootchartd.conf
43//config: and /etc/bootchartd.conf files.
44
5#include "libbb.h" 45#include "libbb.h"
46/* After libbb.h, since it needs sys/types.h on some systems */
47#include <sys/utsname.h>
6#include <sys/mount.h> 48#include <sys/mount.h>
7#ifndef MS_SILENT 49#ifndef MS_SILENT
8# define MS_SILENT (1 << 15) 50# define MS_SILENT (1 << 15)
@@ -19,15 +61,16 @@
19#define DO_SIGNAL_SYNC 1 61#define DO_SIGNAL_SYNC 1
20 62
21 63
22//Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf 64//$PWD/bootchartd.conf and /etc/bootchartd.conf:
23 65//supported options:
66//# Sampling period (in seconds)
67//SAMPLE_PERIOD=0.2
68//
69//not yet supported:
24//# tmpfs size 70//# tmpfs size
25//# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) 71//# (32 MB should suffice for ~20 minutes worth of log data, but YMMV)
26//TMPFS_SIZE=32m 72//TMPFS_SIZE=32m
27// 73//
28//# Sampling period (in seconds)
29//SAMPLE_PERIOD=0.2
30//
31//# Whether to enable and store BSD process accounting information. The 74//# Whether to enable and store BSD process accounting information. The
32//# kernel needs to be configured to enable v3 accounting 75//# kernel needs to be configured to enable v3 accounting
33//# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities 76//# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities
@@ -113,7 +156,7 @@ static int dump_procs(FILE *fp, int look_for_login_process)
113 continue; 156 continue;
114 p++; 157 p++;
115 strchrnul(p, ')')[0] = '\0'; 158 strchrnul(p, ')')[0] = '\0';
116 /* If is gdm, kdm or a getty? */ 159 /* Is it gdm, kdm or a getty? */
117 if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm') 160 if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm')
118 || strstr(p, "getty") 161 || strstr(p, "getty")
119 ) { 162 ) {
@@ -126,7 +169,7 @@ static int dump_procs(FILE *fp, int look_for_login_process)
126 return found_login_process; 169 return found_login_process;
127} 170}
128 171
129static char *make_tempdir(const char *prog) 172static char *make_tempdir(void)
130{ 173{
131 char template[] = "/tmp/bootchart.XXXXXX"; 174 char template[] = "/tmp/bootchart.XXXXXX";
132 char *tempdir = xstrdup(mkdtemp(template)); 175 char *tempdir = xstrdup(mkdtemp(template));
@@ -151,18 +194,10 @@ static char *make_tempdir(const char *prog)
151 } else { 194 } else {
152 xchdir(tempdir); 195 xchdir(tempdir);
153 } 196 }
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; 197 return tempdir;
163} 198}
164 199
165static void do_logging(void) 200static void do_logging(unsigned sample_period_us)
166{ 201{
167 //# Enable process accounting if configured 202 //# Enable process accounting if configured
168 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then 203 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
@@ -175,7 +210,7 @@ static void do_logging(void)
175 //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); 210 //FILE *proc_netdev = xfopen("proc_netdev.log", "w");
176 FILE *proc_ps = xfopen("proc_ps.log", "w"); 211 FILE *proc_ps = xfopen("proc_ps.log", "w");
177 int look_for_login_process = (getppid() == 1); 212 int look_for_login_process = (getppid() == 1);
178 unsigned count = 60*1000*1000 / (200*1000); /* ~1 minute */ 213 unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */
179 214
180 while (--count && !bb_got_signal) { 215 while (--count && !bb_got_signal) {
181 char *p; 216 char *p;
@@ -200,31 +235,65 @@ static void do_logging(void)
200 /* dump_procs saw a getty or {g,k,x}dm 235 /* dump_procs saw a getty or {g,k,x}dm
201 * stop logging in 2 seconds: 236 * stop logging in 2 seconds:
202 */ 237 */
203 if (count > 2*1000*1000 / (200*1000)) 238 if (count > 2*1000*1000 / sample_period_us)
204 count = 2*1000*1000 / (200*1000); 239 count = 2*1000*1000 / sample_period_us;
205 } 240 }
206 fflush_all(); 241 fflush_all();
207 wait_more: 242 wait_more:
208 usleep(200*1000); 243 usleep(sample_period_us);
209 } 244 }
210 245
211 // [ -e kernel_pacct ] && accton off 246 // [ -e kernel_pacct ] && accton off
212} 247}
213 248
214static void finalize(char *tempdir) 249static void finalize(char *tempdir, const char *prog)
215{ 250{
216 //# Stop process accounting if configured 251 //# Stop process accounting if configured
217 //local pacct= 252 //local pacct=
218 //[ -e kernel_pacct ] && pacct=kernel_pacct 253 //[ -e kernel_pacct ] && pacct=kernel_pacct
219 254
220 //( 255 FILE *header_fp = xfopen("header", "w");
221 // echo "version = $VERSION" 256
222 // echo "title = Boot chart for $( hostname | sed q ) ($( date ))" 257 if (prog)
223 // echo "system.uname = $( uname -srvm | sed q )" 258 fprintf(header_fp, "profile.process = %s\n", prog);
224 // echo "system.release = $( sed q /etc/SuSE-release )" 259
225 // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)" 260 fputs("version = "BC_VERSION_STR"\n", header_fp);
226 // echo "system.kernel.options = $( sed q /proc/cmdline )" 261 if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) {
227 //) >> header 262 char *hostname;
263 char *kcmdline;
264 time_t t;
265 struct tm tm_time;
266 /* x2 for possible localized weekday/month names */
267 char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2];
268 struct utsname unamebuf;
269
270 hostname = safe_gethostname();
271 time(&t);
272 localtime_r(&t, &tm_time);
273 strftime(date_buf, sizeof(date_buf), "%a %b %e %H:%M:%S %Z %Y", &tm_time);
274 fprintf(header_fp, "title = Boot chart for %s (%s)\n", hostname, date_buf);
275 if (ENABLE_FEATURE_CLEAN_UP)
276 free(hostname);
277
278 uname(&unamebuf); /* never fails */
279 /* same as uname -srvm */
280 fprintf(header_fp, "system.uname = %s %s %s %s\n",
281 unamebuf.sysname,
282 unamebuf.release,
283 unamebuf.version,
284 unamebuf.machine
285 );
286
287 //system.release = `cat /etc/DISTRO-release`
288 //system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
289
290 kcmdline = xmalloc_open_read_close("/proc/cmdline", NULL);
291 /* kcmdline includes trailing "\n" */
292 fprintf(header_fp, "system.kernel.options = %s", kcmdline);
293 if (ENABLE_FEATURE_CLEAN_UP)
294 free(kcmdline);
295 }
296 fclose(header_fp);
228 297
229 /* Package log files */ 298 /* Package log files */
230 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct 299 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct
@@ -243,19 +312,20 @@ static void finalize(char *tempdir)
243 */ 312 */
244} 313}
245 314
246/* Usage: 315//usage:#define bootchartd_trivial_usage
247 * bootchartd start [PROG ARGS]: start logging in background, USR1 stops it. 316//usage: "start [PROG ARGS]|stop|init"
248 * With PROG, runs PROG, then kills background logging. 317//usage:#define bootchartd_full_usage "\n\n"
249 * bootchartd stop: same as "killall -USR1 bootchartd" 318//usage: "Create /var/log/bootchart.tgz with boot chart data\n"
250 * bootchartd init: start logging in background 319//usage: "\nOptions:"
251 * Stop when getty/gdm is seen (if AUTO_STOP_LOGGER = yes). 320//usage: "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1"
252 * Meant to be used from init scripts. 321//usage: "\nstop: send USR1 to all bootchartd processes"
253 * bootchartd (pid==1): as init, but then execs $bootchart_init, /init, /sbin/init 322//usage: "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)"
254 * Meant to be used as kernel's init process. 323//usage: "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init"
255 */ 324
256int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 325int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int bootchartd_main(int argc UNUSED_PARAM, char **argv) 326int bootchartd_main(int argc UNUSED_PARAM, char **argv)
258{ 327{
328 unsigned sample_period_us;
259 pid_t parent_pid, logger_pid; 329 pid_t parent_pid, logger_pid;
260 smallint cmd; 330 smallint cmd;
261 enum { 331 enum {
@@ -287,7 +357,25 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
287 cmd = CMD_PID1; 357 cmd = CMD_PID1;
288 } 358 }
289 359
290 /* Here we are in START or INIT state. Create logger child: */ 360 /* Here we are in START, INIT or CMD_PID1 state */
361
362 /* Read config file: */
363 sample_period_us = 200 * 1000;
364 if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) {
365 char* token[2];
366 parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read);
367 if (!parser)
368 parser = config_open2("/etc/bootchartd.conf", fopen_for_read);
369 while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) {
370 if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1])
371 sample_period_us = atof(token[1]) * 1000000;
372 }
373 config_close(parser);
374 }
375 if ((int)sample_period_us <= 0)
376 sample_period_us = 1; /* prevent division by 0 */
377
378 /* Create logger child: */
291 logger_pid = fork_or_rexec(argv); 379 logger_pid = fork_or_rexec(argv);
292 380
293 if (logger_pid == 0) { /* child */ 381 if (logger_pid == 0) { /* child */
@@ -312,9 +400,9 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
312 if (cmd == CMD_PID1 && !getenv("PATH")) 400 if (cmd == CMD_PID1 && !getenv("PATH"))
313 putenv((char*)bb_PATH_root_path); 401 putenv((char*)bb_PATH_root_path);
314 402
315 tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL); 403 tempdir = make_tempdir();
316 do_logging(); 404 do_logging(sample_period_us);
317 finalize(tempdir); 405 finalize(tempdir, cmd == CMD_START ? argv[2] : NULL);
318 return EXIT_SUCCESS; 406 return EXIT_SUCCESS;
319 } 407 }
320 408
@@ -335,17 +423,15 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
335 execl(bootchart_init, bootchart_init, NULL); 423 execl(bootchart_init, bootchart_init, NULL);
336 execl("/init", "init", NULL); 424 execl("/init", "init", NULL);
337 execl("/sbin/init", "init", NULL); 425 execl("/sbin/init", "init", NULL);
338 bb_perror_msg_and_die("can't exec '%s'", "/sbin/init"); 426 bb_perror_msg_and_die("can't execute '%s'", "/sbin/init");
339 } 427 }
340 428
341 if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ 429 if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */
342 pid_t pid = vfork(); 430 pid_t pid = xvfork();
343 if (pid < 0)
344 bb_perror_msg_and_die("vfork");
345 if (pid == 0) { /* child */ 431 if (pid == 0) { /* child */
346 argv += 2; 432 argv += 2;
347 execvp(argv[0], argv); 433 execvp(argv[0], argv);
348 bb_perror_msg_and_die("can't exec '%s'", argv[0]); 434 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
349 } 435 }
350 /* parent */ 436 /* parent */
351 waitpid(pid, NULL, 0); 437 waitpid(pid, NULL, 0);