[systemd-commits] 5 commits - .gitignore Makefile.am TODO src/readahead units/systemd-readahead-collect.service.in units/systemd-readahead-replay.service.in

Lennart Poettering lennart at kemper.freedesktop.org
Thu Jun 21 15:09:40 PDT 2012


 .gitignore                                 |    4 
 Makefile.am                                |   25 ----
 TODO                                       |    2 
 src/readahead/readahead-analyze.c          |  101 ++++++++++--------
 src/readahead/readahead-collect.c          |  118 +--------------------
 src/readahead/readahead-common.h           |    9 +
 src/readahead/readahead-replay.c           |   97 +----------------
 src/readahead/readahead.c                  |  158 +++++++++++++++++++++++++++++
 units/systemd-readahead-collect.service.in |    2 
 units/systemd-readahead-replay.service.in  |    2 
 10 files changed, 247 insertions(+), 271 deletions(-)

New commits:
commit 3b0810c53c6adfa2f436540369b8969ae75d7fcf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jun 22 00:09:23 2012 +0200

    readahead: minor code style fixes

diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c
index 75f85b4..fb50ad3 100644
--- a/src/readahead/readahead-analyze.c
+++ b/src/readahead/readahead-analyze.c
@@ -32,19 +32,12 @@
 
 #include "readahead-common.h"
 
-int main_analyze(const char *pack_path)
-{
+int main_analyze(const char *pack_path) {
         char line[LINE_MAX];
-        char path[PATH_MAX];
         FILE *pack;
         int a;
         int missing = 0;
-        off_t size;
         off_t tsize = 0;
-        uint64_t inode;
-        uint32_t b;
-        uint32_t c;
-        struct stat st;
 
         if (!pack_path)
                 pack_path = "/.readahead";
@@ -72,10 +65,13 @@ int main_analyze(const char *pack_path)
                 goto fail;
         }
 
-        fprintf(stdout, "   pct  sections     size: path\n");
-        fprintf(stdout, "   ===  ========     ====: ====\n");
+        fputs("   pct  sections     size: path\n"
+              "   ===  ========     ====: ====\n", stdout);
 
-        while(true) {
+        for (;;) {
+                char path[PATH_MAX];
+                struct stat st;
+                uint64_t inode;
                 int pages = 0;
                 int sections = 0;
 
@@ -89,7 +85,9 @@ int main_analyze(const char *pack_path)
                         goto fail;
                 }
 
-                while (true) {
+                for (;;) {
+                        uint32_t b, c;
+
                         if (fread(&b, sizeof(b), 1, pack) != 1  ||
                             fread(&c, sizeof(c), 1, pack) != 1) {
                                 log_error("Pack file corrupt.");
@@ -99,7 +97,7 @@ int main_analyze(const char *pack_path)
                                 break;
 
                         /* Uncomment this to get all the chunks separately
-                        fprintf(stdout, " %d: %d %d\n", sections, b, c);
+                           printf(" %d: %d %d\n", sections, b, c);
                          */
 
                         pages += (c - b);
@@ -107,6 +105,8 @@ int main_analyze(const char *pack_path)
                 }
 
                 if (stat(path, &st) == 0) {
+                        off_t size;
+
                         if (sections == 0)
                                 size = st.st_size;
                         else
@@ -114,13 +114,13 @@ int main_analyze(const char *pack_path)
 
                         tsize += size;
 
-                        fprintf(stdout, "  %4d%% (%2d) %12ld: %s\n",
+                        printf("  %4d%% (%2d) %12ld: %s\n",
                                 sections ? (int)(size / st.st_size * 100.0) : 100,
                                 sections ? sections : 1,
                                 (unsigned long)size,
                                 path);
                 } else {
-                        fprintf(stdout, "  %4dp (%2d) %12s: %s (MISSING)\n",
+                        printf("  %4dp (%2d) %12s: %s (MISSING)\n",
                                 sections ? pages : -1,
                                 sections ? sections : 1,
                                 "???",
@@ -132,10 +132,14 @@ int main_analyze(const char *pack_path)
 
         fclose(pack);
 
-        fprintf(stdout, "\nHOST:    %s", line);
-        fprintf(stdout, "TYPE:    %c\n", a);
-        fprintf(stdout, "MISSING: %d\n", missing);
-        fprintf(stdout, "TOTAL:   %ld\n", tsize);
+        printf("\nHOST:    %s"
+               "TYPE:    %c\n"
+               "MISSING: %d\n"
+               "TOTAL:   %ld\n",
+               line,
+               a,
+               missing,
+               tsize);
 
         return EXIT_SUCCESS;
 

commit ebfb7506fee66c3bffb250fe557893634171e2c8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jun 22 00:03:25 2012 +0200

    readahead: make sure to close pack file before exiting, to be valgrind clean

diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c
index 42bf9db..75f85b4 100644
--- a/src/readahead/readahead-analyze.c
+++ b/src/readahead/readahead-analyze.c
@@ -34,13 +34,13 @@
 
 int main_analyze(const char *pack_path)
 {
-        char line[1024];
+        char line[LINE_MAX];
         char path[PATH_MAX];
         FILE *pack;
         int a;
         int missing = 0;
         off_t size;
-        long tsize = 0;
+        off_t tsize = 0;
         uint64_t inode;
         uint32_t b;
         uint32_t c;
@@ -52,22 +52,24 @@ int main_analyze(const char *pack_path)
         pack = fopen(pack_path, "re");
         if (!pack) {
                 log_error("Pack file missing.");
-                return EXIT_FAILURE;
+                goto fail;
         }
 
         if (!fgets(line, sizeof(line), pack)) {
                 log_error("Pack file corrupt.");
-                return EXIT_FAILURE;
+                goto fail;
         }
 
-        if (!strstr(line, READAHEAD_PACK_FILE_VERSION)) {
+        char_array_0(line);
+
+        if (!endswith(line, READAHEAD_PACK_FILE_VERSION)) {
                 log_error("Pack file version incompatible with this parser.");
-                return EXIT_FAILURE;
+                goto fail;
         }
 
         if ((a = getc(pack)) == EOF) {
                 log_error("Pack file corrupt.");
-                return EXIT_FAILURE;
+                goto fail;
         }
 
         fprintf(stdout, "   pct  sections     size: path\n");
@@ -84,14 +86,14 @@ int main_analyze(const char *pack_path)
 
                 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
                         log_error("Pack file corrupt.");
-                        return EXIT_FAILURE;
+                        goto fail;
                 }
 
                 while (true) {
                         if (fread(&b, sizeof(b), 1, pack) != 1  ||
                             fread(&c, sizeof(c), 1, pack) != 1) {
                                 log_error("Pack file corrupt.");
-                                return EXIT_FAILURE;
+                                goto fail;
                         }
                         if ((b == 0) && (c == 0))
                                 break;
@@ -128,10 +130,17 @@ int main_analyze(const char *pack_path)
 
         }
 
+        fclose(pack);
+
         fprintf(stdout, "\nHOST:    %s", line);
         fprintf(stdout, "TYPE:    %c\n", a);
         fprintf(stdout, "MISSING: %d\n", missing);
         fprintf(stdout, "TOTAL:   %ld\n", tsize);
 
         return EXIT_SUCCESS;
+
+
+fail:
+        fclose(pack);
+        return EXIT_FAILURE;
 }
diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c
index 6e6db60..7bd079a 100644
--- a/src/readahead/readahead-replay.c
+++ b/src/readahead/readahead-replay.c
@@ -155,7 +155,8 @@ static int replay(const char *root) {
                 goto finish;
         }
 
-        if ((!(pack = fopen(pack_fn, "re")))) {
+        pack = fopen(pack_fn, "re");
+        if (!pack) {
                 if (errno == ENOENT)
                         log_debug("No pack file found.");
                 else {

commit 97fa0e708f33cdd88b2d78a46963bed8dd873697
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jun 21 23:58:31 2012 +0200

    readahead: use log_error() for logging errors

diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c
index 9c328a5..42bf9db 100644
--- a/src/readahead/readahead-analyze.c
+++ b/src/readahead/readahead-analyze.c
@@ -49,24 +49,24 @@ int main_analyze(const char *pack_path)
         if (!pack_path)
                 pack_path = "/.readahead";
 
-        pack = fopen(pack_path, "r");
+        pack = fopen(pack_path, "re");
         if (!pack) {
-                fprintf(stderr, "Pack file missing\n");
+                log_error("Pack file missing.");
                 return EXIT_FAILURE;
         }
 
-        if (!(fgets(line, sizeof(line), pack))) {
-                fprintf(stderr, "Pack file corrupt\n");
+        if (!fgets(line, sizeof(line), pack)) {
+                log_error("Pack file corrupt.");
                 return EXIT_FAILURE;
         }
 
         if (!strstr(line, READAHEAD_PACK_FILE_VERSION)) {
-                fprintf(stderr, "Pack file version incompatible with this parser\n");
+                log_error("Pack file version incompatible with this parser.");
                 return EXIT_FAILURE;
         }
 
         if ((a = getc(pack)) == EOF) {
-                fprintf(stderr, "Pack file corrupt\n");
+                log_error("Pack file corrupt.");
                 return EXIT_FAILURE;
         }
 
@@ -83,14 +83,14 @@ int main_analyze(const char *pack_path)
                 path[strlen(path)-1] = 0;
 
                 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
-                        fprintf(stderr, "Pack file corrupt\n");
+                        log_error("Pack file corrupt.");
                         return EXIT_FAILURE;
                 }
 
                 while (true) {
                         if (fread(&b, sizeof(b), 1, pack) != 1  ||
                             fread(&c, sizeof(c), 1, pack) != 1) {
-                                fprintf(stderr, "Pack file corrupt\n");
+                                log_error("Pack file corrupt.");
                                 return EXIT_FAILURE;
                         }
                         if ((b == 0) && (c == 0))

commit a0bbec1ab0493963bacb5364304fa57afbd14277
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jun 21 23:56:03 2012 +0200

    readahead: make use of util.h's page_size() call

diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c
index 5a5b917..9c328a5 100644
--- a/src/readahead/readahead-analyze.c
+++ b/src/readahead/readahead-analyze.c
@@ -45,7 +45,6 @@ int main_analyze(const char *pack_path)
         uint32_t b;
         uint32_t c;
         struct stat st;
-        int pagesize = getpagesize();
 
         if (!pack_path)
                 pack_path = "/.readahead";
@@ -109,7 +108,7 @@ int main_analyze(const char *pack_path)
                         if (sections == 0)
                                 size = st.st_size;
                         else
-                                size = pages * pagesize;
+                                size = pages * page_size();
 
                         tsize += size;
 

commit 87ce22cc0d097d9cd0297d0141eadba6c573c299
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jun 21 23:53:20 2012 +0200

    readahead: merge three binaries into one
    
    since the binaries share much of the same code and we better load only
    one binary instead of two from disk at early boot let's merge the three
    readahead binaries into one. This also allows us to drop a lot of
    duplicated code.

diff --git a/.gitignore b/.gitignore
index abb7255..7d04930 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,8 +46,7 @@
 /systemd-user-sessions
 /systemd-shutdown
 /systemd-tmpfiles
-/systemd-readahead-collect
-/systemd-readahead-replay
+/systemd-readahead
 /systemd-reply-password
 /systemd-gnome-ask-password-agent
 /systemd-ask-password
@@ -123,4 +122,3 @@ stamp-*
 /v4l_id
 /test-libudev
 /test-udev
-/systemd-readahead-analyze
diff --git a/Makefile.am b/Makefile.am
index 4616b30..03e28e8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2377,39 +2377,24 @@ endif
 
 # ------------------------------------------------------------------------------
 if ENABLE_READAHEAD
-systemd_readahead_collect_SOURCES = \
+systemd_readahead_SOURCES = \
+	src/readahead/readahead.c \
 	src/readahead/readahead-collect.c \
-	src/readahead/readahead-common.c \
-	src/readahead/readahead-common.h
-
-systemd_readahead_collect_LDADD = \
-	libsystemd-shared.la \
-	libsystemd-daemon.la \
-	libudev.la
-
-systemd_readahead_replay_SOURCES = \
 	src/readahead/readahead-replay.c \
+	src/readahead/readahead-analyze.c \
 	src/readahead/readahead-common.c \
 	src/readahead/readahead-common.h
 
-systemd_readahead_replay_LDADD = \
+systemd_readahead_LDADD = \
 	libsystemd-shared.la \
 	libsystemd-daemon.la \
 	libudev.la
 
-systemd_readahead_analyze_SOURCES = \
-	src/readahead/readahead-analyze.c \
-	src/readahead/readahead-common.h
-
 pkginclude_HEADERS += \
 	src/systemd/sd-readahead.h
 
 rootlibexec_PROGRAMS += \
-	systemd-readahead-collect \
-	systemd-readahead-replay
-
-bin_PROGRAMS += \
-	systemd-readahead-analyze
+	systemd-readahead
 
 dist_systemunit_DATA += \
 	units/systemd-readahead-drop.service \
diff --git a/TODO b/TODO
index 630721c..908dadb 100644
--- a/TODO
+++ b/TODO
@@ -35,8 +35,6 @@ Features:
 
 * supprto rd.xxx wherever else makes sense
 
-* readahead: merge the three tools into one binary
-
 * systemctl: when stopping a service which has triggres and warning about it actually check the TriggeredBy= deps fields
 
 * journal: hook up with EFI firmware log, new kmsg logic
diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c
index 6ee3551..5a5b917 100644
--- a/src/readahead/readahead-analyze.c
+++ b/src/readahead/readahead-analyze.c
@@ -32,8 +32,7 @@
 
 #include "readahead-common.h"
 
-
-int main(int argc, char *argv[])
+int main_analyze(const char *pack_path)
 {
         char line[1024];
         char path[PATH_MAX];
@@ -48,30 +47,28 @@ int main(int argc, char *argv[])
         struct stat st;
         int pagesize = getpagesize();
 
-        if (argc != 2)
-                snprintf(path, PATH_MAX, "/.readahead");
-        else
-                snprintf(path, PATH_MAX, "%s", argv[1]);
+        if (!pack_path)
+                pack_path = "/.readahead";
 
-        pack = fopen(path, "r");
+        pack = fopen(pack_path, "r");
         if (!pack) {
                 fprintf(stderr, "Pack file missing\n");
-                exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
         }
 
         if (!(fgets(line, sizeof(line), pack))) {
                 fprintf(stderr, "Pack file corrupt\n");
-                exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
         }
 
         if (!strstr(line, READAHEAD_PACK_FILE_VERSION)) {
                 fprintf(stderr, "Pack file version incompatible with this parser\n");
-                exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
         }
 
         if ((a = getc(pack)) == EOF) {
                 fprintf(stderr, "Pack file corrupt\n");
-                exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
         }
 
         fprintf(stdout, "   pct  sections     size: path\n");
@@ -88,14 +85,14 @@ int main(int argc, char *argv[])
 
                 if (fread(&inode, sizeof(inode), 1, pack) != 1) {
                         fprintf(stderr, "Pack file corrupt\n");
-                        exit(EXIT_FAILURE);
+                        return EXIT_FAILURE;
                 }
 
                 while (true) {
                         if (fread(&b, sizeof(b), 1, pack) != 1  ||
                             fread(&c, sizeof(c), 1, pack) != 1) {
                                 fprintf(stderr, "Pack file corrupt\n");
-                                exit(EXIT_FAILURE);
+                                return EXIT_FAILURE;
                         }
                         if ((b == 0) && (c == 0))
                                 break;
@@ -137,5 +134,5 @@ int main(int argc, char *argv[])
         fprintf(stdout, "MISSING: %d\n", missing);
         fprintf(stdout, "TOTAL:   %ld\n", tsize);
 
-        exit(EXIT_SUCCESS);
+        return EXIT_SUCCESS;
 }
diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
index c4bcd4e..8dacf6a 100644
--- a/src/readahead/readahead-collect.c
+++ b/src/readahead/readahead-collect.c
@@ -62,10 +62,6 @@
  * - does ioprio_set work with fadvise()?
  */
 
-static unsigned arg_files_max = 16*1024;
-static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
-static usec_t arg_timeout = 2*USEC_PER_MINUTE;
-
 static ReadaheadShared *shared = NULL;
 
 /* Avoid collisions with the NULL pointer */
@@ -592,108 +588,10 @@ finish:
         return r;
 }
 
-static int help(void) {
-
-        printf("%s [OPTIONS...] [DIRECTORY]\n\n"
-               "Collect read-ahead data on early boot.\n\n"
-               "  -h --help                 Show this help\n"
-               "     --max-files=INT        Maximum number of files to read ahead\n"
-               "     --max-file-size=BYTES  Maximum size of files to read ahead\n"
-               "     --timeout=USEC         Maximum time to spend collecting data\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_FILES_MAX = 0x100,
-                ARG_FILE_SIZE_MAX,
-                ARG_TIMEOUT
-        };
-
-        static const struct option options[] = {
-                { "help",          no_argument,       NULL, 'h'                },
-                { "files-max",     required_argument, NULL, ARG_FILES_MAX      },
-                { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX  },
-                { "timeout",       required_argument, NULL, ARG_TIMEOUT        },
-                { NULL,            0,                 NULL, 0                  }
-        };
-
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
+int main_collect(const char *root) {
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
-
-                switch (c) {
-
-                case 'h':
-                        help();
-                        return 0;
-
-                case ARG_FILES_MAX:
-                        if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
-                                log_error("Failed to parse maximum number of files %s.", optarg);
-                                return -EINVAL;
-                        }
-                        break;
-
-                case ARG_FILE_SIZE_MAX: {
-                        unsigned long long ull;
-
-                        if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
-                                log_error("Failed to parse maximum file size %s.", optarg);
-                                return -EINVAL;
-                        }
-
-                        arg_file_size_max = (off_t) ull;
-                        break;
-                }
-
-                case ARG_TIMEOUT:
-                        if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
-                                log_error("Failed to parse timeout %s.", optarg);
-                                return -EINVAL;
-                        }
-
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
-                }
-        }
-
-        if (optind != argc &&
-            optind != argc-1) {
-                help();
-                return -EINVAL;
-        }
-
-        return 1;
-}
-
-int main(int argc, char *argv[]) {
-        int r;
-        const char *root;
-
-        log_set_target(LOG_TARGET_SAFE);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-
-        root = optind < argc ? argv[optind] : "/";
+        if (!root)
+                root = "/";
 
         /* Skip this step on read-only media. Note that we check the
          * underlying block device here, not he read-only flag of the
@@ -702,23 +600,23 @@ int main(int argc, char *argv[]) {
          * device is theoretically writable. */
         if (fs_on_read_only(root) > 0) {
                 log_info("Disabling readahead collector due to read-only media.");
-                return 0;
+                return EXIT_SUCCESS;
         }
 
         if (!enough_ram()) {
                 log_info("Disabling readahead collector due to low memory.");
-                return 0;
+                return EXIT_SUCCESS;
         }
 
         shared = shared_get();
         if (!shared)
-                return 1;
+                return EXIT_FAILURE;
 
         shared->collect = getpid();
         __sync_synchronize();
 
         if (collect(root) < 0)
-                return 1;
+                return EXIT_FAILURE;
 
-        return 0;
+        return EXIT_SUCCESS;
 }
diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h
index 3056a02..fd657a2 100644
--- a/src/readahead/readahead-common.h
+++ b/src/readahead/readahead-common.h
@@ -26,11 +26,16 @@
 #include <sys/types.h>
 
 #include "macro.h"
+#include "util.h"
 
 #define READAHEAD_FILE_SIZE_MAX (10*1024*1024)
 
 #define READAHEAD_PACK_FILE_VERSION ";VERSION=2\n"
 
+extern unsigned arg_files_max;
+extern off_t arg_file_size_max;
+extern usec_t arg_timeout;
+
 int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st);
 
 int fs_on_ssd(const char *p);
@@ -52,4 +57,8 @@ int block_bump_request_nr(const char *p);
 int block_get_readahead(const char *p, uint64_t *bytes);
 int block_set_readahead(const char *p, uint64_t bytes);
 
+int main_collect(const char *root);
+int main_replay(const char *root);
+int main_analyze(const char *pack_path);
+
 #endif
diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c
index fc2c33f..6e6db60 100644
--- a/src/readahead/readahead-replay.c
+++ b/src/readahead/readahead-replay.c
@@ -44,8 +44,6 @@
 #include "readahead-common.h"
 #include "virt.h"
 
-static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
-
 static ReadaheadShared *shared = NULL;
 
 static int unpack_file(FILE *pack) {
@@ -289,103 +287,25 @@ finish:
         return r;
 }
 
+int main_replay(const char *root) {
 
-static int help(void) {
-
-        printf("%s [OPTIONS...] [DIRECTORY]\n\n"
-               "Replay collected read-ahead data on early boot.\n\n"
-               "  -h --help                 Show this help\n"
-               "     --max-file-size=BYTES  Maximum size of files to read ahead\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_FILE_SIZE_MAX
-        };
-
-        static const struct option options[] = {
-                { "help",          no_argument,       NULL, 'h'                },
-                { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX  },
-                { NULL,            0,                 NULL, 0                  }
-        };
-
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
-
-                switch (c) {
-
-                case 'h':
-                        help();
-                        return 0;
-
-                case ARG_FILE_SIZE_MAX: {
-                        unsigned long long ull;
-
-                        if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
-                                log_error("Failed to parse maximum file size %s.", optarg);
-                                return -EINVAL;
-                        }
-
-                        arg_file_size_max = (off_t) ull;
-                        break;
-                }
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
-                }
-        }
-
-        if (optind != argc &&
-            optind != argc-1) {
-                help();
-                return -EINVAL;
-        }
-
-        return 1;
-}
-
-int main(int argc, char*argv[]) {
-        int r;
-        const char *root;
-
-        log_set_target(LOG_TARGET_SAFE);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-
-        root = optind < argc ? argv[optind] : "/";
+        if (!root)
+                root = "/";
 
         if (!enough_ram()) {
                 log_info("Disabling readahead replay due to low memory.");
-                return 0;
+                return EXIT_SUCCESS;
         }
 
         shared = shared_get();
         if (!shared)
-                return 1;
+                return EXIT_FAILURE;
 
         shared->replay = getpid();
         __sync_synchronize();
 
         if (replay(root) < 0)
-                return 1;
+                return EXIT_FAILURE;
 
-        return 0;
+        return EXIT_SUCCESS;
 }
diff --git a/src/readahead/readahead.c b/src/readahead/readahead.c
new file mode 100644
index 0000000..abeecc7
--- /dev/null
+++ b/src/readahead/readahead.c
@@ -0,0 +1,158 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "util.h"
+#include "def.h"
+#include "readahead-common.h"
+
+unsigned arg_files_max = 16*1024;
+off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
+usec_t arg_timeout = 2*USEC_PER_MINUTE;
+
+static int help(void) {
+
+        printf("%s [OPTIONS...] collect [DIRECTORY]\n\n"
+               "Collect read-ahead data on early boot.\n\n"
+               "  -h --help                 Show this help\n"
+               "     --max-files=INT        Maximum number of files to read ahead\n"
+               "     --file-size-max=BYTES  Maximum size of files to read ahead\n"
+               "     --timeout=USEC         Maximum time to spend collecting data\n\n\n",
+               program_invocation_short_name);
+
+        printf("%s [OPTIONS...] replay [DIRECTORY]\n\n"
+               "Replay collected read-ahead data on early boot.\n\n"
+               "  -h --help                 Show this help\n"
+               "     --file-size-max=BYTES  Maximum size of files to read ahead\n\n\n",
+               program_invocation_short_name);
+
+        printf("%s [OPTIONS...] analyze [PACK FILE]\n\n"
+               "Analyze collected read-ahead data.\n\n"
+               "  -h --help                 Show this help\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_FILES_MAX = 0x100,
+                ARG_FILE_SIZE_MAX,
+                ARG_TIMEOUT
+        };
+
+        static const struct option options[] = {
+                { "help",          no_argument,       NULL, 'h'                },
+                { "files-max",     required_argument, NULL, ARG_FILES_MAX      },
+                { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX  },
+                { "timeout",       required_argument, NULL, ARG_TIMEOUT        },
+                { NULL,            0,                 NULL, 0                  }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case ARG_FILES_MAX:
+                        if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) {
+                                log_error("Failed to parse maximum number of files %s.", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
+                case ARG_FILE_SIZE_MAX: {
+                        unsigned long long ull;
+
+                        if (safe_atollu(optarg, &ull) < 0 || ull <= 0) {
+                                log_error("Failed to parse maximum file size %s.", optarg);
+                                return -EINVAL;
+                        }
+
+                        arg_file_size_max = (off_t) ull;
+                        break;
+                }
+
+                case ARG_TIMEOUT:
+                        if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
+                                log_error("Failed to parse timeout %s.", optarg);
+                                return -EINVAL;
+                        }
+
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        if (optind != argc-1 &&
+            optind != argc-2) {
+                help();
+                return -EINVAL;
+        }
+
+        return 1;
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+
+        log_set_target(LOG_TARGET_SAFE);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+
+        if (streq(argv[optind], "collect"))
+                return main_collect(argv[optind+1]);
+        else if (streq(argv[optind], "replay"))
+                return main_replay(argv[optind+1]);
+        else if (streq(argv[optind], "analyze"))
+                return main_analyze(argv[optind+1]);
+
+        log_error("Unknown verb %s.", argv[optind]);
+        return EXIT_FAILURE;
+}
diff --git a/units/systemd-readahead-collect.service.in b/units/systemd-readahead-collect.service.in
index 55b6776..c597cdc 100644
--- a/units/systemd-readahead-collect.service.in
+++ b/units/systemd-readahead-collect.service.in
@@ -17,7 +17,7 @@ ConditionVirtualization=no
 
 [Service]
 Type=notify
-ExecStart=@rootlibexecdir@/systemd-readahead-collect
+ExecStart=@rootlibexecdir@/systemd-readahead collect
 RemainAfterExit=yes
 StandardOutput=null
 OOMScoreAdjust=1000
diff --git a/units/systemd-readahead-replay.service.in b/units/systemd-readahead-replay.service.in
index 7324ba3..eddf36d 100644
--- a/units/systemd-readahead-replay.service.in
+++ b/units/systemd-readahead-replay.service.in
@@ -16,7 +16,7 @@ ConditionVirtualization=no
 
 [Service]
 Type=notify
-ExecStart=@rootlibexecdir@/systemd-readahead-replay
+ExecStart=@rootlibexecdir@/systemd-readahead replay
 RemainAfterExit=yes
 StandardOutput=null
 OOMScoreAdjust=1000



More information about the systemd-commits mailing list