Add control over database location
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon, 8 Sep 2014 09:26:39 +0000 (10:26 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Mon, 8 Sep 2014 09:26:39 +0000 (10:26 +0100)
gl/.gitignore
gl/m4/.gitignore
gl/m4/gnulib-cache.m4
librazor/razor.h
librazor/root.c
src/main.c

index 4b5a26b..ddd53d3 100644 (file)
@@ -74,3 +74,7 @@
 /sys_types.in.h
 /unistd.c
 /wctype-h.c
+/getopt.c
+/getopt.in.h
+/getopt1.c
+/getopt_int.h
index 7ce22dd..f48d441 100644 (file)
@@ -71,3 +71,5 @@
 /ssize_t.m4
 /sys_socket_h.m4
 /sys_types_h.m4
+/getopt.m4
+/nocrash.m4
index daed511..b6e11d9 100644 (file)
@@ -27,7 +27,7 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=. --no-conditional-dependencies --libtool --macro-prefix=gl fnmatch fnmatch-posix fsync mkdir mkdtemp
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=. --no-conditional-dependencies --libtool --macro-prefix=gl fnmatch fnmatch-posix fsync getopt-gnu mkdir mkdtemp
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([])
@@ -35,6 +35,7 @@ gl_MODULES([
   fnmatch
   fnmatch-posix
   fsync
+  getopt-gnu
   mkdir
   mkdtemp
 ])
index 55bbe63..521f809 100644 (file)
@@ -555,6 +555,8 @@ struct razor_set *razor_set_create_from_rpmdb(void);
  **/
 struct razor_root;
 
+const char *razor_get_database_path();
+void razor_set_database_path(const char *database_path);
 int razor_root_create(const char *root, struct razor_error **error);
 struct razor_root *
 razor_root_open(const char *root, struct razor_error **error);
index 7db364a..9061bcc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
  * Copyright (C) 2008  Red Hat, Inc
- * Copyright (C) 2009, 2011, 2012  J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #define O_BINARY       0
 #endif
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
 static const char system_repo_filename[] = "system.rzdb";
 /*
  * system_lock_filename is chosen to be the same as the pre v0.3
@@ -50,11 +58,12 @@ static const char system_repo_filename[] = "system.rzdb";
  */
 static const char system_lock_filename[] = "system-next.rzdb";
 #ifdef MSWIN_API
-#define RAZOR_ROOT_PATH        NULL
+#define RAZOR_DATABASE_PATH    NULL
 #else
-#define RAZOR_ROOT_PATH        "/var/lib/razor"
+#define RAZOR_DATABASE_PATH    "/var/lib/razor"
 #endif
-static const char *razor_root_path = RAZOR_ROOT_PATH;
+static char *razor_database_path = RAZOR_DATABASE_PATH;
+static int razor_database_path_alloced = FALSE;
 
 struct razor_root {
        struct razor_set *system;
@@ -65,17 +74,41 @@ static void
 razor_root_init(void)
 {
 #ifdef MSWIN_API
-       static char root_path[MAX_PATH];
-       if (!razor_root_path) {
+       static char database_path[MAX_PATH];
+       if (!razor_database_path) {
                SHGetFolderPath(NULL,
                        CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
-                       root_path);
-               strcat(root_path, "\\Razor");
-               razor_root_path = root_path;
+                       database_path);
+               strcat(database_path, "\\Razor");
+               razor_database_path = database_path;
+               razor_database_path_alloced = FALSE;
        }
 #endif
 }
 
+RAZOR_EXPORT const char *
+razor_get_database_path()
+{
+       razor_root_init();
+
+       return razor_database_path;
+}
+
+RAZOR_EXPORT void
+razor_set_database_path(const char *database_path)
+{
+       if (razor_database_path_alloced)
+               free(razor_database_path);
+
+       if (database_path) {
+               razor_database_path = strdup(database_path);
+               razor_database_path_alloced = TRUE;
+       } else {
+               razor_database_path = RAZOR_DATABASE_PATH;
+               razor_database_path_alloced = FALSE;
+       }
+}
+
 RAZOR_EXPORT int
 razor_root_create(const char *root, struct razor_error **error)
 {
@@ -101,7 +134,8 @@ razor_root_create(const char *root, struct razor_error **error)
                return -1;
        }
 
-       file = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
+       file = razor_concat(razor_database_path, "/", system_repo_filename,
+                           NULL);
        path = razor_path_add_root(file, root);
        retval = !stat(path, &buf);
        if (retval) {
@@ -152,7 +186,7 @@ razor_root_open(const char *root, struct razor_error **error)
                return NULL;
        }
 
-       s = razor_concat(razor_root_path, "/", system_lock_filename, NULL);
+       s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
        lock_path = razor_path_add_root(s, root);
        free(s);
 
@@ -168,7 +202,7 @@ razor_root_open(const char *root, struct razor_error **error)
                return NULL;
        }
 
-       s = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
+       s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
        image->path = razor_path_add_root(s, root);
        free(s);
 
@@ -198,7 +232,7 @@ razor_root_open_read_only(const char *root, struct razor_error **error)
                return NULL;
        }
 
-       s = razor_concat(razor_root_path, "/", system_lock_filename, NULL);
+       s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
        path = razor_path_add_root(s, root);
        free(s);
 
@@ -212,7 +246,7 @@ razor_root_open_read_only(const char *root, struct razor_error **error)
 
        free(path);
 
-       s = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
+       s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
        path = razor_path_add_root(s, root);
        free(s);
 
index c307e89..d7e7f69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
  * Copyright (C) 2008  Red Hat, Inc
- * Copyright (C) 2009, 2011-2012  J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011-2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@
 #endif
 #include <fnmatch.h>
 #include <errno.h>
+#include <getopt.h>
 #include "razor.h"
 
 static const char system_repo_filename[] = "system.rzdb";
@@ -46,6 +47,14 @@ static const char *install_root = "";
 static const char *repo_filename = system_repo_filename;
 static const char *yum_url;
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
 static int
@@ -59,8 +68,110 @@ update_system(struct razor_root *root, struct razor_relocations *relocations,
              struct razor_transaction *trans, struct razor_set *next,
              const char *verb);
 
+static int command_help(int argc, char * const argv[]);
+
+struct razor_option {
+       char *name;
+       int has_arg;
+       int val;
+       char *description;
+       char *arg_description;
+};
+
+static void
+razor_usage(const char *command, int n_options, struct razor_option *options,
+           const char *parameter_string)
+{
+       int i, help_printed = FALSE;
+       char buf[19];
+
+       printf("Usage: razor %s [options] %s\n", command, parameter_string);
+       printf("(Specify the --help global option for a list of other "
+              "help options)\n");
+       printf("\nOptions:\n");
+
+       for(i = 0; i < n_options; i++) {
+               if (!help_printed && strcmp(options[i].name, "help") > 0) {
+                       printf("  --help              "
+                              "Show this help message and exit\n");
+                       help_printed = TRUE;
+               }
+
+               if (options[i].has_arg != no_argument)
+                       snprintf(buf, sizeof(buf), "%s=%s", options[i].name,
+                                options[i].arg_description);
+               else
+                       strncpy(buf, options[i].name, sizeof(buf));
+               buf[18] = '\0';
+
+               printf("  --%-18s%s\n", buf, options[i].description);
+       }
+
+       if (!help_printed)
+               printf("  --help              "
+                      "Show this help message and exit\n");
+}
+
+/**
+ * razor_getopt:
+ *
+ *
+ * Returns: The next option found or -2 on handled or -1 on error
+ *          or 0 on end of option list.
+ **/
+static int
+razor_getopt(int argc, char * const argv[], int n_options,
+            struct razor_option *options, const char *parameter_string,
+            const char **arg)
+{
+       int i, opt, do_help = 0, retval;
+       struct option *longopts;
+
+       longopts = calloc((n_options + 2), sizeof(*longopts));
+
+       for(i = 0; i < n_options; i++) {
+               longopts[i].name = options[i].name;
+               longopts[i].has_arg = options[i].has_arg;
+               longopts[i].flag = &retval;
+               longopts[i].val = options[i].val;
+       }
+
+       longopts[i].name = "help";
+       longopts[i].has_arg = no_argument;
+       longopts[i].flag = &do_help;
+       longopts[i].val = TRUE;
+
+       opterr = 0;
+
+       opt = getopt_long(argc, argv, "+", longopts, NULL);
+
+       switch (opt)
+       {
+               case 0:
+                       if (do_help) {
+                               razor_usage(argv[0], n_options, options,
+                                           parameter_string);
+                               retval = -2;
+                       } else if (arg)
+                               *arg = optarg;
+                       break;
+
+               case -1:
+                       retval = 0;
+                       break;
+
+               default:
+                       razor_usage(argv[0], n_options, options,
+                                   parameter_string);
+                       retval = -1;
+       }
+
+       free(longopts);
+       return retval;
+}
+
 static struct razor_package_iterator *
-create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
+create_iterator_from_argv(struct razor_set *set, int argc, char * const argv[])
 {
        struct razor_package_query *query;
        struct razor_package_iterator *iter;
@@ -117,18 +228,35 @@ list_packages(struct razor_package_iterator *iter, uint32_t flags)
 }
 
 static int
-command_list(int argc, const char *argv[])
+command_list(int argc, char * const argv[])
 {
+       int opt;
        struct razor_package_iterator *pi;
        struct razor_error *error = NULL;
        struct razor_set *set;
        uint32_t flags = 0;
-       int i = 0;
+       enum {
+               opt_only_names = 1,
+       };
+       static struct razor_option options[] = {
+               { .name = "only-names", .has_arg = no_argument,
+                 .val = opt_only_names,
+                 .description = "Only list package names" },
+       };
 
-       if (i < argc && strcmp(argv[i], "--only-names") == 0) {
-               flags |= LIST_PACKAGES_ONLY_NAMES;
-               i++;
-       }
+       do {
+               opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
+                                  "pattern ...", NULL);
+               switch (opt) {
+                       case -2:
+                               return 0;
+                       case -1:
+                               return 1;
+                       case opt_only_names:
+                               flags |= LIST_PACKAGES_ONLY_NAMES;
+                               break;
+               }
+       } while (opt);
 
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
@@ -137,7 +265,7 @@ command_list(int argc, const char *argv[])
                return 1;
        }
 
-       pi = create_iterator_from_argv(set, argc - i, argv + i);
+       pi = create_iterator_from_argv(set, argc - optind, argv + optind);
        list_packages(pi, flags);
        razor_package_iterator_destroy(pi);
        razor_set_unref(set);
@@ -183,7 +311,7 @@ list_package_properties(struct razor_set *set,
 }
 
 static int
-list_properties(int argc, const char *argv[], uint32_t type)
+list_properties(int argc, char * const argv[], uint32_t type)
 {
        struct razor_set *set;
        struct razor_error *error = NULL;
@@ -191,6 +319,13 @@ list_properties(int argc, const char *argv[], uint32_t type)
        struct razor_package_iterator *pi;
        const char *name, *version, *arch;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -198,7 +333,7 @@ list_properties(int argc, const char *argv[], uint32_t type)
                return 1;
        }
 
-       pi = create_iterator_from_argv(set, argc, argv);
+       pi = create_iterator_from_argv(set, argc - optind, argv + optind);
        while (razor_package_iterator_next(pi, &package,
                                           RAZOR_DETAIL_NAME, &name,
                                           RAZOR_DETAIL_VERSION, &version,
@@ -212,31 +347,31 @@ list_properties(int argc, const char *argv[], uint32_t type)
 }
 
 static int
-command_list_requires(int argc, const char *argv[])
+command_list_requires(int argc, char * const argv[])
 {
        return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
 }
 
 static int
-command_list_provides(int argc, const char *argv[])
+command_list_provides(int argc, char * const argv[])
 {
        return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
 }
 
 static int
-command_list_obsoletes(int argc, const char *argv[])
+command_list_obsoletes(int argc, char * const argv[])
 {
        return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
 }
 
 static int
-command_list_conflicts(int argc, const char *argv[])
+command_list_conflicts(int argc, char * const argv[])
 {
        return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
 }
 
 static int
-command_list_scripts(int argc, const char *argv[])
+command_list_scripts(int argc, char * const argv[])
 {
        struct razor_set *set;
        struct razor_error *error = NULL;
@@ -244,6 +379,13 @@ command_list_scripts(int argc, const char *argv[])
        struct razor_package_iterator *pi;
        const char *preunprog, *preun, *postunprog, *postun;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -251,7 +393,7 @@ command_list_scripts(int argc, const char *argv[])
                return 1;
        }
 
-       pi = create_iterator_from_argv(set, argc, argv);
+       pi = create_iterator_from_argv(set, argc - optind, argv + optind);
        while (razor_package_iterator_next(pi, &package,
                                           RAZOR_DETAIL_PREUNPROG, &preunprog,
                                           RAZOR_DETAIL_PREUN, &preun,
@@ -278,11 +420,23 @@ command_list_scripts(int argc, const char *argv[])
 }
 
 static int
-command_list_files(int argc, const char *argv[])
+command_list_files(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 1) {
+               razor_usage(argv[0], 0, NULL, "[pattern]");
+               return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -290,19 +444,31 @@ command_list_files(int argc, const char *argv[])
                return 1;
        }
 
-       razor_set_list_files(set, argv[0]);
+       razor_set_list_files(set, argv[optind]);
        razor_set_unref(set);
 
        return 0;
 }
 
 static int
-command_list_file_packages(int argc, const char *argv[])
+command_list_file_packages(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set;
        struct razor_package_iterator *pi;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind != 1) {
+               razor_usage(argv[0], 0, NULL, "pattern");
+               return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -310,7 +476,7 @@ command_list_file_packages(int argc, const char *argv[])
                return 1;
        }
 
-       pi = razor_package_iterator_create_for_file(set, argv[0]);
+       pi = razor_package_iterator_create_for_file(set, argv[optind]);
        list_packages(pi, 0);
        razor_package_iterator_destroy(pi);
 
@@ -320,7 +486,7 @@ command_list_file_packages(int argc, const char *argv[])
 }
 
 static int
-command_list_package_files(int argc, const char *argv[])
+command_list_package_files(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set;
@@ -328,6 +494,13 @@ command_list_package_files(int argc, const char *argv[])
        struct razor_package *package;
        const char *name, *version, *arch;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -335,7 +508,7 @@ command_list_package_files(int argc, const char *argv[])
                return 1;
        }
 
-       pi = create_iterator_from_argv(set, argc, argv);
+       pi = create_iterator_from_argv(set, argc - optind, argv + optind);
        while (razor_package_iterator_next(pi, &package,
                                           RAZOR_DETAIL_NAME, &name,
                                           RAZOR_DETAIL_VERSION, &version,
@@ -362,9 +535,6 @@ list_property_packages(const char *ref_name,
        const char *name, *version;
        uint32_t flags;
 
-       if (ref_name == NULL)
-               return 0;
-
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -398,16 +568,42 @@ list_property_packages(const char *ref_name,
 }
 
 static int
-command_what_requires(int argc, const char *argv[])
+command_what_requires(int argc, char * const argv[])
 {
-       return list_property_packages(argv[0], argv[1],
+       switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
+                            NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind < 1 || argc - optind > 2) {
+               razor_usage(argv[0], 0, NULL, "name [version-release]");
+               return 1;
+       }
+
+       return list_property_packages(argv[optind], argv[optind + 1],
                                      RAZOR_PROPERTY_REQUIRES);
 }
 
 static int
-command_what_provides(int argc, const char *argv[])
+command_what_provides(int argc, char * const argv[])
 {
-       return list_property_packages(argv[0], argv[1],
+       switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
+                            NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind < 1 || argc - optind > 2) {
+               razor_usage(argv[0], 0, NULL, "name [version-release]");
+               return 1;
+       }
+
+       return list_property_packages(argv[optind], argv[optind + 1],
                                      RAZOR_PROPERTY_PROVIDES);
 }
 
@@ -489,13 +685,25 @@ download_if_missing(const char *url, const char *file)
        "/pub/fedora/linux/development/i386/os"
 
 static int
-command_import_yum(int argc, const char *argv[])
+command_import_yum(int argc, char * const argv[])
 {
        int retval;
        struct razor_set *set;
        struct razor_atomic *atomic;
        char buffer[512];
 
+       switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 0) {
+               razor_usage(argv[0], 0, NULL, "");
+               return 1;
+       }
+
        printf("downloading from %s.\n", yum_url);
        snprintf(buffer, sizeof buffer,
                 "%s/repodata/primary.xml.gz", yum_url);
@@ -524,7 +732,7 @@ command_import_yum(int argc, const char *argv[])
 
 #if HAVE_RPMLIB
 static int
-command_import_rpmdb(int argc, const char *argv[])
+command_import_rpmdb(int argc, char * const argv[])
 {
        struct razor_set *set;
        struct razor_root *root;
@@ -532,6 +740,18 @@ command_import_rpmdb(int argc, const char *argv[])
        struct razor_atomic *atomic;
        int retval;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 0) {
+               razor_usage(argv[0], 0, NULL, "");
+               return 1;
+       }
+
        root = razor_root_open(install_root, &error);
        if (root == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -605,7 +825,7 @@ mark_packages_for_removal(struct razor_transaction *trans,
 }
 
 static int
-command_remove(int argc, const char *argv[])
+command_remove(int argc, char * const argv[])
 {
        struct razor_set *system, *upstream, *next;
        struct razor_transaction *trans;
@@ -613,6 +833,13 @@ command_remove(int argc, const char *argv[])
        struct razor_root *root;
        int i, retval;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
        root = razor_root_open(install_root, &error);
        if (root == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -624,7 +851,7 @@ command_remove(int argc, const char *argv[])
        upstream = razor_set_create_without_root();
        trans = razor_transaction_create(system, upstream);
        razor_set_unref(upstream);
-       for (i = 0; i < argc; i++) {
+       for (i = optind; i < argc; i++) {
                if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
                        fprintf(stderr, "no match for %s\n", argv[i]);
                        razor_transaction_destroy(trans);
@@ -667,11 +894,23 @@ print_diff(enum razor_diff_action action,
 }
 
 static int
-command_diff(int argc, const char *argv[])
+command_diff(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set, *updated;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 0) {
+               razor_usage(argv[0], 0, NULL, "");
+               return 1;
+       }
+
        set = razor_root_open_read_only(install_root, &error);
        if (set)
                updated = razor_set_open(rawhide_repo_filename, 0, &error);
@@ -694,7 +933,7 @@ command_diff(int argc, const char *argv[])
 }
 
 static int
-command_import_rpms(int argc, const char *argv[])
+command_import_rpms(int argc, char * const argv[])
 {
        DIR *dir;
        struct dirent *de;
@@ -705,14 +944,23 @@ command_import_rpms(int argc, const char *argv[])
        struct razor_atomic *atomic;
        int len, imported_count = 0;
        char filename[256];
-       const char *dirname = argv[0];
+       const char *dirname;
        int retval;
 
-       if (dirname == NULL) {
-               fprintf(stderr, "usage: razor import-rpms DIR\n");
-               return -1;
+       switch (razor_getopt(argc, argv, 0, NULL, "dir", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
        }
 
+       if (argc - optind != 1) {
+               razor_usage(argv[0], 0, NULL, "dir");
+               return 1;
+       }
+
+       dirname = argv[optind];
+
        dir = opendir(dirname);
        if (dir == NULL) {
                fprintf(stderr, "couldn't read dir %s\n", dirname);
@@ -1054,7 +1302,7 @@ update_system(struct razor_root *root, struct razor_relocations *relocations,
 }
 
 static int
-command_install_or_update(int argc, const char *argv[], int do_update)
+command_install_or_update(int argc, char * const argv[], int do_update)
 {
        struct razor_relocations *relocations = NULL;
        struct razor_set *system, *upstream, *next, *set;
@@ -1062,36 +1310,53 @@ command_install_or_update(int argc, const char *argv[], int do_update)
        struct razor_error *error = NULL;
        struct razor_atomic *atomic;
        struct razor_root *root;
-       int i, retval, len, dependencies = 1;
+       int opt, i, retval = 0, len, dependencies = 1;
        char *oldpath;
+       const char *arg;
+       enum {
+               opt_no_dependencies = 1,
+               opt_relocate = 2,
+       };
+       static struct razor_option options[] = {
+               { .name = "no-dependencies", .has_arg = no_argument,
+                 .val = opt_no_dependencies,
+                 .description = "Do not verify package dependencies" },
+               { .name = "relocate", .has_arg = required_argument,
+                 .val = opt_relocate,
+                 .description = "Relocate files from path OLD to NEW",
+                 .arg_description = "OLD=NEW" },
+       };
 
-       for (i = 0; i < argc; i++) {
-               if (strcmp(argv[i], "--no-dependencies") == 0)
-                       dependencies = 0;
-               else if (strcmp(argv[i], "--relocate") == 0) {
-                       i++;
-                       if (i >= argc || strchr(argv[i], '=') == NULL) {
-                               fprintf(stderr,
-                                   "Usage: razor %s [OPTION...] RPM\n",
-                                   do_update ? "update" : "install");
-                               fprintf(stderr, "Options:\n");
-                               fprintf(stderr, "    [--no-dependencies]\n");
-                               fprintf(stderr,
-                                   "    [--relocate OLDPATH=NEWPATH] RPM\n");
-                               return -1;
-                       }
-                       len = strchr(argv[i], '=') - argv[i];
-                       oldpath = malloc(len + 1);
-                       strncpy(oldpath, argv[i], len);
-                       oldpath[len] = '\0';
-                       if (!relocations)
-                              relocations = razor_relocations_create();
-                       razor_relocations_add(relocations, oldpath,
-                                             argv[i] + len + 1);
-                       free(oldpath);
-               } else
-                       break;
-       }
+       do {
+               opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
+                                  "rpm ...", &arg);
+               switch (opt) {
+                       case -2:
+                               return 0;
+                       case -1:
+                               return 1;
+                       case opt_no_dependencies:
+                               dependencies = 0;
+                               break;
+                       case opt_relocate:
+                               if (strchr(arg, '=') == NULL) {
+                                       razor_usage(argv[0],
+                                                   ARRAY_SIZE(options),
+                                                   options, "rpm ...");
+                                       return 1;
+                               }
+                               len = strchr(arg, '=') - arg;
+                               oldpath = malloc(len + 1);
+                               strncpy(oldpath, arg, len);
+                               oldpath[len] = '\0';
+                               if (!relocations)
+                                      relocations = razor_relocations_create();
+                               razor_relocations_add(relocations, oldpath,
+                                                     arg + len + 1);
+                               free(oldpath);
+                               break;
+               }
+       } while (opt);
 
        upstream = razor_set_open(rawhide_repo_filename, 0, &error);
        if (upstream == NULL) {
@@ -1132,9 +1397,9 @@ command_install_or_update(int argc, const char *argv[], int do_update)
        system = razor_root_get_system_set(root);
        trans = razor_transaction_create(system, upstream);
 
-       if (i == argc && do_update)
+       if (optind == argc && do_update)
                razor_transaction_update_all(trans);
-       for (; i < argc; i++) {
+       for (i = optind; i < argc; i++) {
                if (do_update &&
                    mark_packages_for_update(trans, system, argv[i]))
                        continue;
@@ -1207,23 +1472,35 @@ command_install_or_update(int argc, const char *argv[], int do_update)
 }
 
 static int
-command_update(int argc, const char *argv[])
+command_update(int argc, char * const argv[])
 {
        return command_install_or_update(argc, argv, 1);
 }
 
 static int
-command_install(int argc, const char *argv[])
+command_install(int argc, char * const argv[])
 {
        return command_install_or_update(argc, argv, 0);
 }
 
 static int
-command_init(int argc, const char *argv[])
+command_init(int argc, char * const argv[])
 {
        int retval;
        struct razor_error *error = NULL;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 0) {
+               razor_usage(argv[0], 0, NULL, "");
+               return 1;
+       }
+
        retval = razor_root_create(install_root, &error);
        if (retval) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -1235,17 +1512,31 @@ command_init(int argc, const char *argv[])
 }
 
 static int
-command_download(int argc, const char *argv[])
+command_download(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_atomic *atomic;
        struct razor_set *set;
        struct razor_package_iterator *pi;
        struct razor_package *package;
-       const char *pattern = argv[0], *name, *version, *arch;
+       const char *pattern, *name, *version, *arch;
        char url[256], file[256];
        int matches = 0;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 1) {
+               razor_usage(argv[0], 0, NULL, "[pattern]");
+               return 1;
+       }
+
+       pattern = argv[optind];
+
        set = razor_set_open(rawhide_repo_filename, 0, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -1300,15 +1591,29 @@ command_download(int argc, const char *argv[])
 }
 
 static int
-command_info(int argc, const char *argv[])
+command_info(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set;
        struct razor_package_iterator *pi;
        struct razor_package *package;
-       const char *pattern = argv[0], *name, *version, *arch;
+       const char *pattern, *name, *version, *arch;
        const char *summary, *description, *url, *license;
 
+       switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 1) {
+               razor_usage(argv[0], 0, NULL, "[pattern]");
+               return 1;
+       }
+
+       pattern = argv[optind];
+
        set = razor_root_open_read_only(install_root, &error);
        if (set == NULL) {
                fprintf(stderr, "%s\n", razor_error_get_msg(error));
@@ -1351,7 +1656,7 @@ command_info(int argc, const char *argv[])
 #define SEARCH_MAX 256
 
 static int
-command_search(int argc, const char *argv[])
+command_search(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
        struct razor_set *set;
@@ -1361,12 +1666,19 @@ command_search(int argc, const char *argv[])
        const char *name, *version, *arch;
        const char *summary, *description, *url, *license;
 
-       if (!argv[0]) {
-               fprintf(stderr, "must specify a search term\n");
+       switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc != 2) {
+               razor_usage(argv[0], 0, NULL, "pattern");
                return 1;
        }
 
-       snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
+       snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
 
        set = razor_set_open(rawhide_repo_filename, 0, &error);
        if (set == NULL) {
@@ -1400,52 +1712,86 @@ command_search(int argc, const char *argv[])
 static struct {
        const char *name;
        const char *description;
-       int (*func)(int argc, const char *argv[]);
+       int (*func)(int argc, char * const argv[]);
 } razor_commands[] = {
-       { "list", "list all packages", command_list },
-       { "list-requires", "list all requires for the given package", command_list_requires },
-       { "list-provides", "list all provides for the given package", command_list_provides },
-       { "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
-       { "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
-       { "list-scripts", "list all scripts for the given package", command_list_scripts },
-       { "list-files", "list files for package set", command_list_files },
-       { "list-file-packages", "list packages owning file", command_list_file_packages },
-       { "list-package-files", "list files in package", command_list_package_files },
-       { "what-requires", "list the packages that have the given requires", command_what_requires },
-       { "what-provides", "list the packages that have the given provides", command_what_provides },
-       { "import-yum", "import yum metadata files", command_import_yum },
+       { "diff", "Show diff between two package sets", command_diff },
+       { "download", "Download packages", command_download },
+       { "help", "List available commands", command_help },
 #if HAVE_RPMLIB
-       { "import-rpmdb", "import the system rpm database", command_import_rpmdb },
+       { "import-rpmdb", "Import the system rpm database",
+         command_import_rpmdb },
 #endif
-       { "import-rpms", "import rpms from the given directory", command_import_rpms },
-       { "update", "update all or specified packages", command_update },
-       { "remove", "remove specified packages", command_remove },
-       { "diff", "show diff between two package sets", command_diff },
-       { "install", "install rpm", command_install },
-       { "init", "init razor root", command_init },
-       { "download", "download packages", command_download },
-       { "info", "display package details", command_info },
-       { "search", "search package details", command_search }
+       { "import-rpms", "Import rpms from the given directory",
+         command_import_rpms },
+       { "import-yum", "Import yum metadata files", command_import_yum },
+       { "info", "Display package details", command_info },
+       { "init", "Init razor root", command_init },
+       { "install", "Install rpm", command_install },
+       { "list", "List all packages", command_list },
+       { "list-conflicts", "List all conflicts for the given package",
+         command_list_conflicts },
+       { "list-file-packages", "List packages owning file",
+         command_list_file_packages },
+       { "list-files", "List files for package set", command_list_files },
+       { "list-obsoletes", "List all obsoletes for the given package",
+         command_list_obsoletes },
+       { "list-package-files", "List files in package",
+         command_list_package_files },
+       { "list-provides", "List all provides for the given package",
+         command_list_provides },
+       { "list-requires", "List all requires for the given package",
+         command_list_requires },
+       { "list-scripts", "List all scripts for the given package",
+         command_list_scripts },
+       { "remove", "Remove specified packages", command_remove },
+       { "search", "Search package details", command_search },
+       { "update", "Update all or specified packages", command_update },
+       { "what-provides", "List the packages that have the given provides",
+         command_what_provides },
+       { "what-requires", "List the packages that have the given requires",
+         command_what_requires },
 };
 
 static int
-usage(void)
+command_help(int argc, char * const argv[])
 {
        int i;
 
-       printf("usage:\n");
+       printf("Available commands:\n");
        for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
                printf("  %-20s%s\n",
                       razor_commands[i].name, razor_commands[i].description);
+       printf("\nType \"razor --help\" for help about global options\n"
+              "or \"razor <command> --help\" for help about a particular "
+              "command's options.\n");
 
-       return 1;
+       return 0;
 }
 
 int
-main(int argc, const char *argv[])
+main(int argc, char *argv[])
 {
        char *repo, *root;
-       int i;
+       int i, opt, main_optind;
+       int do_help_commands = 0;
+       enum {
+               opt_database = 1,
+               opt_help,
+               opt_help_commands,
+               opt_root,
+               opt_url,
+       };
+       struct option options[] = {
+               { .name = "database", .has_arg = required_argument,
+                 .val = opt_database },
+               { .name = "help", .has_arg = no_argument, .val = opt_help },
+               { .name = "help-commands", .has_arg = no_argument,
+                 .flag = &do_help_commands, .val = TRUE },
+               { .name = "root", .has_arg = required_argument,
+                 .val = opt_root },
+               { .name = "url", .has_arg = required_argument, .val = opt_url },
+               { 0, }
+       };
 
        repo = getenv("RAZOR_REPO");
        if (repo != NULL)
@@ -1462,12 +1808,53 @@ main(int argc, const char *argv[])
        if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
                razor_disable_root_name_checks(1);
 
-       if (argc < 2)
-               return usage();
+       optind = 1;
+       opterr = 0;
+
+       while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
+               switch (opt) {
+                       case opt_database:
+                               razor_set_database_path(optarg);
+                               break;
+                       case opt_help:
+                       default:
+                               printf("Usage: razor [global-options] command "
+                                      "[command-options-and-arguments]\n\n");
+                               printf("Options:\n");
+                               printf("  --help              "
+                                      "Show this help message and exit\n");
+                               printf("  --help-commands     List commands\n");
+                               printf("  --database=PATH     "
+                                      "Use alternative database\n");
+                               printf("  --root=ROOT         "
+                                      "Use ROOT as top level directory\n");
+                               printf("  --url=URL           "
+                                      "Use URL as upstream repository\n");
+                               return opt != opt_help;
+                       case opt_root:
+                               install_root = optarg;
+                               break;
+                       case opt_url:
+                               yum_url = optarg;
+                               break;
+                       case 0:
+                               break;
+               }
+       }
+
+       main_optind = optind;
+       optind = 1;
+
+       if (do_help_commands || argc - main_optind < 1) {
+               command_help(argc - main_optind, argv + main_optind);
+               return 1;
+       }
 
        for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
-               if (strcmp(razor_commands[i].name, argv[1]) == 0)
-                       return razor_commands[i].func(argc - 2, argv + 2);
+               if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
+                       return razor_commands[i].func(argc - main_optind,
+                                                     argv + main_optind);
 
-       return usage();
+       command_help(argc - main_optind, argv + main_optind);
+       return 1;
 }