Blame SOURCES/0010-Added-capability-to-register-and-deregister-collecti.patch

39593f
From 9c93f0540b2afe736a8633c0ac8ac6e4e425726d Mon Sep 17 00:00:00 2001
39593f
From: Jan Zeleny <jzeleny@redhat.com>
39593f
Date: Wed, 30 Jul 2014 09:03:35 +0200
39593f
Subject: [PATCH] Added capability to register and deregister collections
39593f
39593f
- scl register <col_path> creates record for the collection in the scl
39593f
  conf dir
39593f
- scl deregister <collection> removes the collection record from the
39593f
  scl conf dir
39593f
---
39593f
 scl.1    |  18 +++
39593f
 scl.bash |  11 +-
39593f
 scl.c    | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
39593f
 3 files changed, 427 insertions(+), 29 deletions(-)
39593f
39593f
diff --git a/scl.1 b/scl.1
39593f
index 9e13778..c9c2abe 100644
39593f
--- a/scl.1
39593f
+++ b/scl.1
39593f
@@ -8,6 +8,10 @@ scl \- Setup and run software from Software Collection environment
39593f
 \fBscl\fP \fI<action>\fR \fI<collection1>\fR [\fI<collection2> ...\fR] -- \fI<command>\fR
39593f
 .PP
39593f
 \fBscl\fP {\fB-l|--list\fP} [\fI<collection1> <collection2> ...\fR]
39593f
+.PP
39593f
+\fBscl register\fP \fI<path>\f
39593f
+.PP
39593f
+\fBscl deregister\fP \fI<collection>\fR [\fB--force\fP]
39593f
 .SH "DESCRIPTION"
39593f
 .PP
39593f
 This manual page documents \fBscl\fP, a
39593f
@@ -46,6 +50,14 @@ details may be found in the documentation of the particular collection.
39593f
 Lists all installed Software Collections on the system.
39593f
 .IP "\fB-l, --list\fP \fI<collection1> <collection2> ...\fR"
39593f
 If a collection name is specified then list of installed packages belonging to the collection is listed.
39593f
+.IP "\fBregister\fP \fI<path>\fR"
39593f
+If \fI<path>\fR leads to valid SCL file structure, \fBscl\fP will register that as a SCL.
39593f
+\fI<path>\fR directory needs to contain \fBenable\fR  scriptlet and \fBroot\fP directory,
39593f
+to be considered valid SCL.
39593f
+<path> needs to be an absolute path to the collection location.
39593f
+.IP "\fBderegister\fP \fI<collection>\fR [\fB--force\fP]"
39593f
+\fI<collection>\fR will no longer be considered SCL.
39593f
+If the \fI<collection>\fR was installed locally, then the use of \fB--force\fP is needed.i
39593f
 .SH "EXAMPLES"
39593f
 .TP
39593f
 scl enable example 'less --version'
39593f
@@ -63,6 +75,12 @@ list all installed collections
39593f
 .TP
39593f
 scl -l example
39593f
 list all packages within example collection
39593f
+scl register /foo/bar
39593f
+registers new collection with a name bar
39593f
+.TP
39593f
+scl deregister bar --force
39593f
+forces the deregistration of collection bar
39593f
+.TP
39593f
 .SH "AUTHOR"
39593f
 .PP
39593f
 \fBscl\fP was written by Jindrich Novy <jnovy@redhat.com> and Jan Zeleny
39593f
diff --git a/scl.bash b/scl.bash
39593f
index 7f77233..5fae09a 100644
39593f
--- a/scl.bash
39593f
+++ b/scl.bash
39593f
@@ -14,17 +14,18 @@ _scl()
39593f
     return 0
39593f
   fi
39593f
 
39593f
+  local collections=($(find /etc/scl/prefixes -maxdepth 1 -mindepth 1 -type f -exec basename {} \; | sort -u))
39593f
+
39593f
   # handle scriptlets; the first parameter must be a scriptlet if it is not an option
39593f
   if ((COMP_CWORD == 1)); then
39593f
     # get array of scriptlets found throughout collections
39593f
-    local collections=($(find /etc/scl/prefixes -maxdepth 1 -mindepth 1 -type f -exec basename {} \; | sort -u))
39593f
     local scriptlets=()
39593f
     for col in ${collections[@]}; do
39593f
         local prefix=`cat /etc/scl/prefixes/$col`
39593f
         scriptlets+=($(find $prefix/$col/* -maxdepth 1 -type f -exec basename {} \; | sort -u))
39593f
     done
39593f
     scriptlets_str=`echo ${scriptlets[@]} | sed 's/ /\n/g'| sort -u`
39593f
-    COMPREPLY=( $(compgen -W "$scriptlets_str" -- ${cur}) )
39593f
+    COMPREPLY=( $(compgen -W "$scriptlets_str register deregister" -- ${cur}) )
39593f
     return 0
39593f
   fi
39593f
 
39593f
@@ -35,7 +36,11 @@ _scl()
39593f
   fi
39593f
 
39593f
   # handle collections; if it is not an option or a command, it must be a collection
39593f
-  local collections=($(find /etc/scl/prefixes -maxdepth 1 -mindepth 1 -type f -exec basename {} \; | sort -u))
39593f
+  if [ $prev == "register" ]; then
39593f
+    compopt -o nospace
39593f
+    COMPREPLY=( $(compgen -A directory ${cur}) )
39593f
+    return 0
39593f
+  fi
39593f
   COMPREPLY=( $(compgen -W "${collections[*]}" -- ${cur}) )
39593f
   return 0
39593f
 }
39593f
diff --git a/scl.c b/scl.c
39593f
index fcdebcb..f8e2ed4 100644
39593f
--- a/scl.c
39593f
+++ b/scl.c
39593f
@@ -22,8 +22,10 @@
39593f
 #include <stdio.h>
39593f
 #include <stdlib.h>
39593f
 #include <stdarg.h>
39593f
+#include <stdbool.h>
39593f
 #include <unistd.h>
39593f
 #include <getopt.h>
39593f
+#include <ctype.h>
39593f
 #include <string.h>
39593f
 #include <dirent.h>
39593f
 #include <sys/types.h>
39593f
@@ -56,6 +58,8 @@ static void write_script( int tfd, char *s ) {
39593f
 static void print_usage( const char *name ) {
39593f
 	fprintf(stderr, "usage: %s <action> [<collection>...] <command>\n", name);
39593f
 	fprintf(stderr, "   or: %s -l|--list [<collection>...]\n", name);
39593f
+	fprintf(stderr, "   or: %s register <path>\n", name);
39593f
+	fprintf(stderr, "   or: %s deregister <collection> [--force]\n", name);
39593f
 
39593f
 	fprintf(stderr, "\nOptions:\n"
39593f
 				 "    -l, --list            list installed Software Collections or packages\n"
39593f
@@ -68,32 +72,121 @@ static void print_usage( const char *name ) {
39593f
 				 "\nUse '-' as <command> to read the command from standard input.\n");
39593f
 }
39593f
 
39593f
+static int check_directory(const char *dir_name, struct stat *sb, int *count, struct dirent ***nl) {
39593f
+    if (stat(dir_name, sb) == -1) {
39593f
+        fprintf(stderr, "%s does not exist\n", dir_name);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (!S_ISDIR(sb->st_mode)) {
39593f
+        fprintf(stderr, "%s is not a directory\n", dir_name);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if ((*count = scandir(dir_name, nl, 0, alphasort)) < 0) {
39593f
+        perror("scandir");
39593f
+        fprintf(stderr, "%s\n", dir_name);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+static int get_collection_dir_path(char *col_name, char **_col_dir) {
39593f
+    int i;
39593f
+    int fd = -1;
39593f
+    char *file_path = NULL;
39593f
+    char *col_dir = NULL;
39593f
+    struct stat st;
39593f
+    int ret = EXIT_FAILURE;
39593f
+    int col_name_len = strlen(col_name);
39593f
+    int col_dir_len;
39593f
+
39593f
+    file_path = (char *)malloc(sizeof(SCL_CONF_DIR) + col_name_len + 1);
39593f
+    if (file_path == NULL) {
39593f
+        fprintf(stderr, "Can't allocate memory.\n");
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    sprintf(file_path, "%s%s", SCL_CONF_DIR, col_name);
39593f
+
39593f
+    if (stat(file_path, &st) != 0) {
39593f
+        perror("Unable to get file status");
39593f
+        fprintf(stderr, "%s\n", file_path);
39593f
+        goto done;
39593f
+    }
39593f
+
39593f
+    fd = open(file_path, O_RDONLY);
39593f
+    if (fd < 0) {
39593f
+        perror("Unable to open file");
39593f
+        fprintf(stderr, "%s\n", file_path);
39593f
+        goto done;
39593f
+    }
39593f
+
39593f
+	/* One for slash, one for terminating zero*/
39593f
+    col_dir = (char *)calloc(st.st_size + col_name_len + 2, 1);
39593f
+    if (col_dir == NULL) {
39593f
+        fprintf(stderr, "Can't allocate memory.\n");
39593f
+        goto done;
39593f
+    }
39593f
+    if ((col_dir_len = read(fd, col_dir, st.st_size)) < 0) {
39593f
+        fprintf(stderr, "Unable to read from file.\n");
39593f
+        goto done;
39593f
+    }
39593f
+    for (i = col_dir_len-1; i > 0; i--) {
39593f
+        if (isspace(col_dir[i]) || col_dir[i] == '/') {
39593f
+            col_dir[i] = '\0';
39593f
+        } else {
39593f
+            break;
39593f
+        }
39593f
+    }
39593f
+    col_dir[i+1] = '/';
39593f
+    memcpy(col_dir + i + 2, col_name, col_name_len + 1);
39593f
+
39593f
+    *_col_dir = col_dir;
39593f
+
39593f
+    ret = EXIT_SUCCESS;
39593f
+done:
39593f
+    if (fd > 0) {
39593f
+        close(fd);
39593f
+    }
39593f
+    if (ret != EXIT_SUCCESS) {
39593f
+        free(col_dir);
39593f
+    }
39593f
+    free(file_path);
39593f
+    return ret;
39593f
+}
39593f
+
39593f
+static int col_available(char *col_name) {
39593f
+    char *col_dir = NULL;
39593f
+    int ret = 0;
39593f
+
39593f
+    if (get_collection_dir_path(col_name, &col_dir)) {
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    ret = access(col_dir, F_OK);
39593f
+    free(col_dir);
39593f
+    return ret;
39593f
+}
39593f
+
39593f
 static void list_collections() {
39593f
 	struct stat sb;
39593f
 	struct dirent **nl;
39593f
 	int n, i;
39593f
 
39593f
-	if (stat(SCL_CONF_DIR, &sb) == -1) {
39593f
-		fprintf(stderr, "%s does not exist\n", SCL_CONF_DIR);
39593f
-		exit(EXIT_FAILURE);
39593f
-	}
39593f
-
39593f
-	if (!S_ISDIR(sb.st_mode)) {
39593f
-		fprintf(stderr, "%s is not a directory\n", SCL_CONF_DIR);
39593f
-		exit(EXIT_FAILURE);
39593f
-	}
39593f
-
39593f
-	if ((n = scandir(SCL_CONF_DIR, &nl, 0, alphasort)) < 0) {
39593f
-		perror("scandir");
39593f
+	if (check_directory(SCL_CONF_DIR, &sb, &n, &nl)) {
39593f
 		exit(EXIT_FAILURE);
39593f
 	}
39593f
 
39593f
 	for (i=0; i
39593f
 		if (*nl[i]->d_name != '.') {
39593f
-			printf("%s\n", nl[i]->d_name);
39593f
+			if (col_available(nl[i]->d_name) == 0) {
39593f
+				printf("%s\n", nl[i]->d_name);
39593f
+			}
39593f
 		}
39593f
 	}
39593f
 
39593f
+	for (i = 0; i < n; i++) {
39593f
+		free(nl[i]);
39593f
+	}
39593f
 	free(nl);
39593f
 }
39593f
 
39593f
@@ -157,7 +250,7 @@ static char **read_script_output( char *ori_cmd ) {
39593f
 	return lines;
39593f
 }
39593f
 
39593f
-static int list_packages_in_collection( const char *colname) {
39593f
+static int list_packages_in_collection(const char *colname) {
39593f
 	struct stat sb;
39593f
 	struct dirent **nl;
39593f
 	int i, n, found, smax, ss;
39593f
@@ -165,18 +258,7 @@ static int list_packages_in_collection( const char *colname) {
39593f
 	char **srpms = NULL;
39593f
 	size_t cns;
39593f
 
39593f
-	if (stat(SCL_CONF_DIR, &sb) == -1) {
39593f
-		fprintf(stderr, "%s does not exist\n", SCL_CONF_DIR);
39593f
-		exit(EXIT_FAILURE);
39593f
-	}
39593f
-
39593f
-	if (!S_ISDIR(sb.st_mode)) {
39593f
-		fprintf(stderr, "%s is not a directory\n", SCL_CONF_DIR);
39593f
-		exit(EXIT_FAILURE);
39593f
-	}
39593f
-
39593f
-	if ((n = scandir(SCL_CONF_DIR, &nl, 0, alphasort)) < 0) {
39593f
-		perror("scandir");
39593f
+	if (check_directory(SCL_CONF_DIR, &sb, &n, &nl)) {
39593f
 		exit(EXIT_FAILURE);
39593f
 	}
39593f
 
39593f
@@ -246,6 +328,260 @@ static int list_packages_in_collection( const char *colname) {
39593f
 	return 0;
39593f
 }
39593f
 
39593f
+static int split_path(char *col_path, char **_col, char **_fname) {
39593f
+    char *name_start = NULL;
39593f
+    char *name_end = NULL;
39593f
+    char *col = NULL;
39593f
+    int col_path_len = strlen(col_path);
39593f
+
39593f
+    col = (char *)malloc(strlen(col_path) + 1);
39593f
+    if (col == NULL) {
39593f
+        fprintf(stderr, "Can't allocate memory.\n");
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    memcpy(col, col_path, col_path_len + 1);
39593f
+
39593f
+    name_end = col + col_path_len - 1;
39593f
+    while (name_end > col && *name_end == '/') {
39593f
+        *name_end = '\0';
39593f
+        name_end--;
39593f
+    }
39593f
+
39593f
+    name_start = strrchr(col, '/');
39593f
+    if (name_start == NULL) {
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    } else {
39593f
+        *name_start = '\0';
39593f
+        name_start++;
39593f
+    }
39593f
+
39593f
+    *_fname = name_start;
39593f
+    *_col = col;
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+static int get_collection_conf_path(char *col_name, char **_col_path) {
39593f
+    char *col_path = (char *)malloc(sizeof(SCL_CONF_DIR) + strlen(col_name) + 1);
39593f
+    if (col_path == NULL) {
39593f
+        fprintf(stderr, "Can't allocate memory.\n");
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    sprintf(col_path, "%s%s", SCL_CONF_DIR, col_name);
39593f
+    *_col_path = col_path;
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+static int check_valid_collection(char *col_dir) {
39593f
+    struct stat sb;
39593f
+    struct dirent **nl;
39593f
+    int n, i;
39593f
+    bool missing_root = true;
39593f
+    bool missing_enable = true;
39593f
+
39593f
+    if (check_directory(col_dir, &sb, &n, &nl)) {
39593f
+        exit(EXIT_FAILURE);
39593f
+    }
39593f
+
39593f
+    for (i=0; i
39593f
+        if (*nl[i]->d_name != '.') {
39593f
+            if (!strcmp(nl[i]->d_name, "root")) {
39593f
+                missing_root = false;
39593f
+            } else if (!strcmp(nl[i]->d_name, "enable")) {
39593f
+                missing_enable = false;
39593f
+            }
39593f
+        }
39593f
+        free(nl[i]);
39593f
+    }
39593f
+    free(nl);
39593f
+
39593f
+    return missing_root || missing_enable;
39593f
+}
39593f
+
39593f
+static int run_script(char *script_path, char *script_name) {
39593f
+    char *script = NULL;
39593f
+    char *cmd = NULL;
39593f
+    int status;
39593f
+    int ret = EXIT_FAILURE;
39593f
+
39593f
+    if (script_path[strlen(script_path) - 1] == '/') {
39593f
+        check_asprintf(&script, "%s%s", script_path, script_name);
39593f
+    } else {
39593f
+        check_asprintf(&script, "%s/%s", script_path, script_name);
39593f
+    }
39593f
+
39593f
+    if (!access(script, F_OK)) {
39593f
+        check_asprintf(&cmd, "/bin/bash %s", script);
39593f
+        status = system(cmd);
39593f
+        if (status == -1) {
39593f
+            perror("Unable to execute script\n");
39593f
+            fprintf(stderr, "%s\n", script);
39593f
+            goto done;
39593f
+        }
39593f
+        if (!WIFEXITED(status)) {
39593f
+            fprintf(stderr, "Script %s didn't terminate normally\n", script);
39593f
+            goto done;
39593f
+        }
39593f
+        if (WEXITSTATUS(status)) {
39593f
+            fprintf(stderr, "Script %s returned nonzero return code\n", script);
39593f
+            goto done;
39593f
+        }
39593f
+    }
39593f
+
39593f
+    ret = EXIT_SUCCESS;
39593f
+
39593f
+done:
39593f
+    free(script);
39593f
+    free(cmd);
39593f
+    return ret;
39593f
+}
39593f
+
39593f
+static int register_collection(char *col_path) {
39593f
+    FILE *f;
39593f
+    char *col = NULL;
39593f
+    char *name = NULL;
39593f
+    char *new_file = NULL;
39593f
+
39593f
+    if (col_path == NULL || col_path[0] != '/') {
39593f
+        fprintf(stderr, "Collection must be specified as an absolute path!\n");
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (access(col_path, F_OK)) {
39593f
+        perror("Directory doesn't exist");
39593f
+        fprintf(stderr, "%s\n", col_path);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (check_valid_collection(col_path)) {
39593f
+        fprintf(stderr, "Unable to register collection: %s is not a valid collection\n", col_path);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (split_path(col_path, &col, &name)) {
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (get_collection_conf_path(name, &new_file)) {
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (access(new_file, F_OK) == 0) {
39593f
+        fprintf(stderr, "Unable to register collection: Collection with the same name is already registered\n");
39593f
+        free(new_file);
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    f = fopen(new_file, "w+");
39593f
+    if (f == NULL) {
39593f
+        perror("Unable to open file");
39593f
+        fprintf(stderr, "%s\n", new_file);
39593f
+        free(col);
39593f
+        free(new_file);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    fprintf(f, "%s\n", col);
39593f
+    fclose(f);
39593f
+
39593f
+    if (run_script(col_path, "register")) {
39593f
+        fprintf(stderr, "Execution of register script failed\n");
39593f
+        if (unlink(new_file)) {
39593f
+            perror("Unable to remove file: ");
39593f
+            fprintf(stderr, "%s\n", new_file);
39593f
+            fprintf(stderr, "Remove this file manually before a new try to register collection!\n");
39593f
+        }
39593f
+        free(new_file);
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    printf("Collection succesfully registered.\n"
39593f
+           "The collection can now be enabled using 'scl enable %s <command>'\n", name);
39593f
+    free(new_file);
39593f
+    free(col);
39593f
+
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+static int check_package(char *file_path, int *_status) {
39593f
+    char *cmd = NULL;
39593f
+    int path_len = strlen(file_path);
39593f
+    char rpm_query[] = "rpm -qf %s > /dev/null 2> /dev/null";
39593f
+
39593f
+    cmd  = (char *)malloc(path_len + sizeof(rpm_query) - 1);
39593f
+    if (cmd == NULL) {
39593f
+        fprintf(stderr, "Can't allocate memory.\n");
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    sprintf(cmd, rpm_query, file_path);
39593f
+    *_status = system(cmd);
39593f
+    free(cmd);
39593f
+
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+static int deregister_collection(char *col_path, bool force) {
39593f
+    char *col = NULL;
39593f
+    char *col_name = NULL;
39593f
+	char *col_dir = NULL;
39593f
+
39593f
+    if (get_collection_conf_path(col_path, &col_name)) {
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (!force) {
39593f
+        int status;
39593f
+        if (check_package(col_name, &status)) {
39593f
+            free(col_name);
39593f
+            free(col);
39593f
+            return EXIT_FAILURE;
39593f
+        }
39593f
+
39593f
+        if (status == 0) {
39593f
+            fprintf(stderr, "Unable to deregister collection: "
39593f
+                    "Collection was installed as a package, please use --force to deregister it.\n");
39593f
+            free(col);
39593f
+            free(col_name);
39593f
+            return EXIT_FAILURE;
39593f
+        }
39593f
+    }
39593f
+
39593f
+    if (get_collection_dir_path(col_path, &col_dir)) {
39593f
+        free(col_name);
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (run_script(col_dir, "deregister")) {
39593f
+        fprintf(stderr, "Execution of deregister script failed\n");
39593f
+        free(col_dir);
39593f
+        free(col_name);
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+
39593f
+    if (remove(col_name)) {
39593f
+        perror("Unable to delete file");
39593f
+        fprintf(stderr, "%s\n", col_name);
39593f
+        free(col_dir);
39593f
+        free(col_name);
39593f
+        free(col);
39593f
+        return EXIT_FAILURE;
39593f
+    }
39593f
+    printf("Collection successfully deregistered.\n");
39593f
+	free(col_dir);
39593f
+    free(col_name);
39593f
+    free(col);
39593f
+    return EXIT_SUCCESS;
39593f
+}
39593f
+
39593f
+
39593f
+
39593f
+
39593f
 int main(int argc, char **argv) {
39593f
 	struct stat st;
39593f
 	char *path, *enablepath;
39593f
@@ -254,6 +590,7 @@ int main(int argc, char **argv) {
39593f
 	int i, tfd, ffd;
39593f
 	int separator_pos = 0;
39593f
 	char *command = NULL;
39593f
+	int failed = 0;
39593f
 
39593f
 	if (argc == 2 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h"))) {
39593f
 		print_usage(argv[0]);
39593f
@@ -270,6 +607,44 @@ int main(int argc, char **argv) {
39593f
 		exit(EXIT_SUCCESS);
39593f
 	}
39593f
 
39593f
+	if (argc > 2 && (!strcmp(argv[1], "register"))) {
39593f
+		failed = 0;
39593f
+		for (i = 2; i < argc; i++) {
39593f
+			if (register_collection(argv[i]) != 0) {
39593f
+				failed++;
39593f
+			}
39593f
+		}
39593f
+		if (failed > 0) {
39593f
+			fprintf(stderr, "Registration of %d collections failed!\n", failed);
39593f
+			exit(EXIT_FAILURE);
39593f
+		} else {
39593f
+			exit(EXIT_SUCCESS);
39593f
+		}
39593f
+	}
39593f
+	if (argc > 2 && (!(strcmp(argv[1], "deregister")))) {
39593f
+		bool force = false;
39593f
+		for (i = 2; i < argc; i++) {
39593f
+			if (!strcmp(argv[i], "--force")) {
39593f
+				force = true;
39593f
+				break;
39593f
+			}
39593f
+		}
39593f
+		for (i = 2; i < argc; i++) {
39593f
+			if (strcmp(argv[i], "--force") != 0) {
39593f
+				failed = 0;
39593f
+				if (deregister_collection(argv[i], force) != 0) {
39593f
+					failed++;
39593f
+				}
39593f
+			}
39593f
+		}
39593f
+		if (failed > 0) {
39593f
+			fprintf(stderr, "Deregistration of %d collections failed!\n", failed);
39593f
+			exit(EXIT_FAILURE);
39593f
+		} else {
39593f
+			exit(EXIT_SUCCESS);
39593f
+		}
39593f
+	}
39593f
+
39593f
 	for (i = 0; i < argc; i++) {
39593f
 		if (strcmp(argv[i], "--") == 0) {
39593f
 			break;
39593f
-- 
39593f
1.9.3
39593f