bootchartd: added optional compat features
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 21 Jun 2010 05:17:23 +0000 (07:17 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 21 Jun 2010 05:17:23 +0000 (07:17 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
init/Config.src
init/bootchartd.c
procps/sysctl.c

index 22c72d9..5e962fd 100644 (file)
@@ -1125,6 +1125,7 @@ typedef struct parser_t {
 } parser_t;
 parser_t* config_open(const char *filename) FAST_FUNC;
 parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC;
 } parser_t;
 parser_t* config_open(const char *filename) FAST_FUNC;
 parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC;
+/* delims[0] is a comment char (use '\0' to disable), the rest are token delimiters */
 int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC;
 #define config_read(parser, tokens, max, min, str, flags) \
        config_read(parser, tokens, ((flags) | (((min) & 0xFF) << 8) | ((max) & 0xFF)), str)
 int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC;
 #define config_read(parser, tokens, max, min, str, flags) \
        config_read(parser, tokens, ((flags) | (((min) & 0xFF) << 8) | ((max) & 0xFF)), str)
index 2e92081..590e298 100644 (file)
@@ -122,18 +122,4 @@ config MESG
          Mesg controls access to your terminal by others. It is typically
          used to allow or disallow other users to write to your terminal
 
          Mesg controls access to your terminal by others. It is typically
          used to allow or disallow other users to write to your terminal
 
-config BOOTCHARTD
-       bool "bootchartd"
-       default y
-       help
-         bootchartd is commonly used to profile the boot process
-         for the purpose of speeding it up. In this case, it is started
-         by the kernel as the init process. This is configured by adding
-         the init=/sbin/bootchartd option to the kernel command line.
-
-         It can also be used to monitor the resource usage of a specific
-         application or the running system in general. In this case,
-         bootchartd is started interactively by running bootchartd start
-         and stopped using bootchartd stop.
-
 endmenu
 endmenu
index d1f9ed3..1ed4f99 100644 (file)
@@ -2,7 +2,58 @@
 /*
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 /*
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
+
+//config:config BOOTCHARTD
+//config:      bool "bootchartd"
+//config:      default y
+//config:      help
+//config:        bootchartd is commonly used to profile the boot process
+//config:        for the purpose of speeding it up. In this case, it is started
+//config:        by the kernel as the init process. This is configured by adding
+//config:        the init=/sbin/bootchartd option to the kernel command line.
+//config:
+//config:        It can also be used to monitor the resource usage of a specific
+//config:        application or the running system in general. In this case,
+//config:        bootchartd is started interactively by running bootchartd start
+//config:        and stopped using bootchartd stop.
+//config:
+//config:config FEATURE_BOOTCHARTD_BLOATED_HEADER
+//config:      bool "bootchartd"
+//config:      default y
+//config:      depends on BOOTCHARTD
+//config:      help
+//config:        Create extended header file compatible with "big" bootchartd.
+//config:        "Big" bootchartd is a shell script and it dumps some
+//config:        "convenient" info int the header, such as:
+//config:          title = Boot chart for `hostname` (`date`)
+//config:          system.uname = `uname -srvm`
+//config:          system.release = `cat /etc/DISTRO-release`
+//config:          system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
+//config:          system.kernel.options = `cat /proc/cmdline`
+//config:        This data is not mandatory for bootchart graph generation,
+//config:        and is considered bloat. Nevertheless, this option
+//config:        makes bootchartd applet to dump a subset of it.
+//config:
+//config:config FEATURE_BOOTCHARTD_CONFIG_FILE
+//config:      bool "bootchartd"
+//config:      default y
+//config:      depends on BOOTCHARTD
+//config:      help
+//config:        Create extended header file compatible with "big" bootchartd.
+//config:        "Big" bootchartd is a shell script and it dumps some
+//config:        "convenient" info int the header, such as:
+//config:          title = Boot chart for `hostname` (`date`)
+//config:          system.uname = `uname -srvm`
+//config:          system.release = `cat /etc/DISTRO-release`
+//config:          system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
+//config:          system.kernel.options = `cat /proc/cmdline`
+//config:        This data is not mandatory for bootchart graph generation,
+//config:        and is considered bloat. Nevertheless, this option
+//config:        makes bootchartd applet to dump a subset of it.
+
 #include "libbb.h"
 #include "libbb.h"
+/* After libbb.h, since it needs sys/types.h on some systems */
+#include <sys/utsname.h>
 #include <sys/mount.h>
 #ifndef MS_SILENT
 # define MS_SILENT      (1 << 15)
 #include <sys/mount.h>
 #ifndef MS_SILENT
 # define MS_SILENT      (1 << 15)
 #define DO_SIGNAL_SYNC 1
 
 
 #define DO_SIGNAL_SYNC 1
 
 
-//Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf
-
+//$PWD/bootchartd.conf and /etc/bootchartd.conf:
+//supported options:
+//# Sampling period (in seconds)
+//SAMPLE_PERIOD=0.2
+//
+//not yet supported:
 //# tmpfs size
 //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV)
 //TMPFS_SIZE=32m
 //
 //# tmpfs size
 //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV)
 //TMPFS_SIZE=32m
 //
-//# Sampling period (in seconds)
-//SAMPLE_PERIOD=0.2
-//
 //# Whether to enable and store BSD process accounting information.  The
 //# kernel needs to be configured to enable v3 accounting
 //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities
 //# Whether to enable and store BSD process accounting information.  The
 //# kernel needs to be configured to enable v3 accounting
 //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities
@@ -126,7 +178,7 @@ static int dump_procs(FILE *fp, int look_for_login_process)
        return found_login_process;
 }
 
        return found_login_process;
 }
 
-static char *make_tempdir(const char *prog)
+static char *make_tempdir(void)
 {
        char template[] = "/tmp/bootchart.XXXXXX";
        char *tempdir = xstrdup(mkdtemp(template));
 {
        char template[] = "/tmp/bootchart.XXXXXX";
        char *tempdir = xstrdup(mkdtemp(template));
@@ -151,18 +203,10 @@ static char *make_tempdir(const char *prog)
        } else {
                xchdir(tempdir);
        }
        } else {
                xchdir(tempdir);
        }
-       {
-               FILE *header_fp = xfopen("header", "w");
-               if (prog)
-                       fprintf(header_fp, "profile.process = %s\n", prog);
-               fputs("version = "BC_VERSION_STR"\n", header_fp);
-               fclose(header_fp);
-       }
-
        return tempdir;
 }
 
        return tempdir;
 }
 
-static void do_logging(void)
+static void do_logging(int sample_pariod_us)
 {
        //# Enable process accounting if configured
        //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
 {
        //# Enable process accounting if configured
        //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
@@ -205,26 +249,61 @@ static void do_logging(void)
                }
                fflush_all();
  wait_more:
                }
                fflush_all();
  wait_more:
-               usleep(200*1000);
+               usleep(sample_pariod_us);
        }
 
        // [ -e kernel_pacct ] && accton off
 }
 
        }
 
        // [ -e kernel_pacct ] && accton off
 }
 
-static void finalize(char *tempdir)
+static void finalize(char *tempdir, const char *prog)
 {
        //# Stop process accounting if configured
        //local pacct=
        //[ -e kernel_pacct ] && pacct=kernel_pacct
 
 {
        //# Stop process accounting if configured
        //local pacct=
        //[ -e kernel_pacct ] && pacct=kernel_pacct
 
-       //(
-       //      echo "version = $VERSION"
-       //      echo "title = Boot chart for $( hostname | sed q ) ($( date ))"
-       //      echo "system.uname = $( uname -srvm | sed q )"
-       //      echo "system.release = $( sed q /etc/SuSE-release )"
-       //      echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)"
-       //      echo "system.kernel.options = $( sed q /proc/cmdline )"
-       //) >> header
+       FILE *header_fp = xfopen("header", "w");
+
+       if (prog)
+               fprintf(header_fp, "profile.process = %s\n", prog);
+
+       fputs("version = "BC_VERSION_STR"\n", header_fp);
+
+       if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) {
+               char *hostname;
+               char *kcmdline;
+               time_t t;
+               struct tm tm_time;
+               /* x2 for possible localized data */
+               char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2];
+               struct utsname unamebuf;
+
+               hostname = safe_gethostname();
+               time(&t);
+               localtime_r(&t, &tm_time);
+               strftime(date_buf, sizeof(date_buf), "%a %b %e %H:%M:%S %Z %Y", &tm_time);
+               fprintf(header_fp, "title = Boot chart for %s (%s)\n", hostname, date_buf);
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       free(hostname);
+
+               uname(&unamebuf); /* never fails */
+               /* same as uname -srvm */
+               fprintf(header_fp, "system.uname = %s %s %s %s\n",
+                               unamebuf.sysname,
+                               unamebuf.release,
+                               unamebuf.version,
+                               unamebuf.machine
+               );
+
+               //system.release = `cat /etc/DISTRO-release`
+               //system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
+
+               kcmdline = xmalloc_open_read_close("/proc/cmdline", NULL);
+               /* kcmdline includes trailing "\n" */
+               fprintf(header_fp, "system.kernel.options = %s", kcmdline);
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       free(kcmdline);
+       }
+       fclose(header_fp);
 
        /* Package log files */
        system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct
 
        /* Package log files */
        system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct
@@ -256,6 +335,7 @@ static void finalize(char *tempdir)
 int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bootchartd_main(int argc UNUSED_PARAM, char **argv)
 {
 int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bootchartd_main(int argc UNUSED_PARAM, char **argv)
 {
+       int sample_pariod_us;
        pid_t parent_pid, logger_pid;
        smallint cmd;
        enum {
        pid_t parent_pid, logger_pid;
        smallint cmd;
        enum {
@@ -287,7 +367,23 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
                cmd = CMD_PID1;
        }
 
                cmd = CMD_PID1;
        }
 
-       /* Here we are in START or INIT state. Create logger child: */
+       /* Here we are in START or INIT state */
+
+       /* Read config file: */
+       sample_pariod_us = 200 * 1000;
+       if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) {
+               char* token[2];
+               parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read);
+               if (!parser)
+                       parser = config_open2("/etc/bootchartd.conf", fopen_for_read);
+               while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) {
+                       if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1])
+                               sample_pariod_us = atof(token[1]) * 1000000;
+               }
+               config_close(parser);
+       }
+
+       /* Create logger child: */
        logger_pid = fork_or_rexec(argv);
 
        if (logger_pid == 0) { /* child */
        logger_pid = fork_or_rexec(argv);
 
        if (logger_pid == 0) { /* child */
@@ -312,9 +408,9 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
                if (cmd == CMD_PID1 && !getenv("PATH"))
                        putenv((char*)bb_PATH_root_path);
 
                if (cmd == CMD_PID1 && !getenv("PATH"))
                        putenv((char*)bb_PATH_root_path);
 
-               tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL);
-               do_logging();
-               finalize(tempdir);
+               tempdir = make_tempdir();
+               do_logging(sample_pariod_us);
+               finalize(tempdir, cmd == CMD_START ? argv[2] : NULL);
                return EXIT_SUCCESS;
        }
 
                return EXIT_SUCCESS;
        }
 
index 7a5bf14..fc601d6 100644 (file)
@@ -212,6 +212,7 @@ static int sysctl_handle_preload_file(const char *filename)
 //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value
 // (but _whitespace_ from ends should be trimmed first (and we do it right))
 //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1")
 //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value
 // (but _whitespace_ from ends should be trimmed first (and we do it right))
 //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1")
+// can it be fixed by removing PARSE_COLLAPSE bit?
        while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) {
                char *tp;
                sysctl_dots_to_slashes(token[0]);
        while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) {
                char *tp;
                sysctl_dots_to_slashes(token[0]);