diff --git a/src/misc-progs/addonctrl.c b/src/misc-progs/addonctrl.c
index 14b4b1325..1687aac19 100644
--- a/src/misc-progs/addonctrl.c
+++ b/src/misc-progs/addonctrl.c
@@ -10,71 +10,346 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <errno.h>
 #include "setuid.h"
 
 #define BUFFER_SIZE 1024
 
+const char *enabled_path = "/etc/rc.d/rc3.d";
+const char *disabled_path = "/etc/rc.d/rc3.d/off";
+
+char errormsg[BUFFER_SIZE] = "";
+const char *usage = 
+    "Usage\n"
+    "  addonctrl <addon> (start|stop|restart|reload|enable|disable|status|boot-status|list-services) [<service>]\n"
+    "\n"
+    "Options:\n"
+    "  <addon>\t\tName of the addon to control\n"
+    "  <service>\t\tSpecific service of the addon to control (optional)\n"
+    "  \t\t\tBy default the requested action is performed on all related services. See also 'list-services'.\n"
+    "  start\t\t\tStart service(s) of the addon\n"
+    "  stop\t\t\tStop service(s) of the addon\n"
+    "  restart\t\tRestart service(s) of the addon\n"
+    "  enable\t\tEnable service(s) of the addon to start at boot\n"
+    "  disable\t\tDisable service(s) of the addon to start at boot\n"
+    "  status\t\tDisplay current state of addon service(s)\n"
+    "  boot-status\t\tDisplay wether service(s) is enabled on boot or not\n"
+    "  list-services\t\tDisplay a list of services related to the addon";
+
+// Find a file <path> using <filepattern> as glob pattern. 
+// Returns the found filename or NULL if not found
+char *find_file_in_dir(const char *path, const char *filepattern) 
+{
+    struct dirent *entry;
+    DIR *dp;
+    char *found = NULL;
+
+    if ((dp = opendir(path)) != NULL) {
+        while(found == NULL && (entry = readdir(dp)) != NULL)
+            if (fnmatch(filepattern, entry->d_name, FNM_PATHNAME) == 0)
+                found = strdup(entry->d_name);
+
+        closedir(dp);
+    }
+
+    return found;
+}
+
+// Reads Services metadata for <addon>.
+// Returns pointer to array of strings containing the services for <addon> 
+// and sets <servicescnt> to the number of found services
+char **get_addon_services(const char *addon, int *servicescnt, const char *filter) {
+    const char *metafile_prefix = "/opt/pakfire/db/installed/meta-";
+    const char *metadata_key = "Services";
+    const char *keyvalue_delim = ":";
+    const char *service_delim = " ";
+    char *token;
+    char **services = NULL;
+    char *service;
+    char *line = NULL;
+    size_t line_len = 0;
+    int i = 0;
+    char *metafile;
+ 
+    if (addon == NULL) {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    if (asprintf(&metafile, "%s%s", metafile_prefix, addon) == -1) {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    FILE *fp = fopen(metafile,"r");
+    if (fp != NULL) {
+        // Get initscript(s) for addon from meta-file
+        while (getline(&line, &line_len, fp) != -1 && services == NULL) {
+            // Strip newline
+            char *newline = strchr(line, '\n');
+            if (newline) *newline = 0;
+
+            // Parse key/value and look for required key.
+            token = strtok(line, keyvalue_delim);
+            if (token != NULL && strcmp(token, metadata_key) == 0) {
+                token = strtok(NULL, keyvalue_delim);
+                if (token != NULL) {
+                    // Put each service in services array
+                    service = strtok(token, service_delim);
+                    while (service != NULL) {
+                        // if filter is set, only select filtered service
+                        if ((filter != NULL && strcmp(filter, service) == 0) || 
+                            filter == NULL) {
+                            services = reallocarray(services ,i+1 ,sizeof (char *));
+                            if (services != NULL)
+                                services[i++] = strdup(service);
+                            else 
+                                break;
+                        }
+                        service = strtok(NULL, service_delim);
+                    }
+                }
+            }
+        }
+
+        free(line);
+        fclose(fp);
+    }  else {
+        snprintf(errormsg, BUFFER_SIZE - 1, "Addon '%s' not found.\n\n%s", addon, usage);
+    }
+
+    free(metafile);
+    *servicescnt = i;
+    return services;
+}
+
+// Calls initscript <service> with parameter <action>
+int initscript_action(const char *service, const char *action) {
+    const char *initd_path = "/etc/rc.d/init.d";
+    char *initscript;
+    char *argv[] = {
+        action,
+        NULL
+    };
+    int r = 0;
+
+    if ((r = asprintf(&initscript, "%s/%s", initd_path, service)) != -1) {
+        r = run(initscript, argv);
+        free(initscript);
+    } else {
+        errno = ENOMEM;
+    }
+
+    return r; 
+}
+
+// Move an initscript with filepattern from <src_path> to <dest_path>
+// Returns:
+//   -1: Error during move or memory allocation. Details in errno
+//   0: Success
+//   1: file was not moved, but is already in <dest_path>
+//   2: file does not exist in either in <src_path> or <dest_path>
+int move_initscript_by_pattern(const char *src_path, const char *dest_path, const char *filepattern) {
+    char *src = NULL;
+    char *dest = NULL;
+    int r = 1;
+    char *filename = NULL;
+
+    if ((filename = find_file_in_dir(src_path, filepattern)) != NULL) {
+        if ((r = asprintf(&src, "%s/%s", src_path, filename)) != -1 &&
+            (r = asprintf(&dest, "%s/%s", dest_path, filename) != -1)) {
+            // move initscript
+            r = rename(src, dest);
+        } else {
+            errno = ENOMEM;
+        }
+
+        if (src != NULL)
+            free(src);
+        if (dest != NULL)
+            free(dest);
+    } else {
+        if ((filename = find_file_in_dir(dest_path, filepattern)) == NULL) 
+            r = 2;
+    }
+
+    if (filename != NULL)
+        free(filename);
+
+    return r;
+}
+
+// Enable/Disable addon service(s) by moving initscript symlink from/to disabled_path
+int toggle_service(const char *service, const char *action) {
+    const char *src_path, *dest_path;
+    char *filepattern; 
+    int r = 0;
+    
+    if (asprintf(&filepattern, "S??%s", service) == -1) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    if (strcmp(action, "enable") == 0) {
+        src_path = disabled_path;
+        dest_path = enabled_path;
+    } else {
+        src_path = enabled_path;
+        dest_path = disabled_path;
+    }
+
+    // Ensure disabled_path exists
+    errno = 0;
+    if (mkdir(disabled_path, S_IRWXU + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH) == -1 && errno != EEXIST) {
+        r = 1;
+        snprintf(errormsg, BUFFER_SIZE -1, "Error creating %s. (Error: %d)", disabled_path, errno);
+    } else {
+        r = move_initscript_by_pattern(src_path, dest_path, filepattern);
+        if (r == -1 ) {
+            r = 1;
+            snprintf(errormsg, BUFFER_SIZE - 1, "Could not %s %s. (Error: %d)", action, service, errno);
+        } else if (r == 1) {
+            snprintf(errormsg, BUFFER_SIZE - 1, "Service %s is already %sd. Skipping...", service, action);
+        } else if (r == 2) {
+            snprintf(errormsg, BUFFER_SIZE - 1, "Unable to %s service %s. (Service has no valid symlink in %s).", action, service, src_path);
+        }
+    }
+
+    free(filepattern);
+    
+    return r;
+}
+
+// Print to stdout wether <service> is enabled or disabled on boot
+// Prints <service> as Not available when initscript is not found
+// in either enabled_path or disabled_path.
+void print_boot_status(char *service) {
+    char *filepattern;
+    if (asprintf(&filepattern, "S??%s", service) == -1) {
+        errno = ENOMEM;
+        return;
+    }
+
+    if (find_file_in_dir(enabled_path, filepattern) != NULL) 
+        fprintf(stdout, "%s is enabled on boot.\n", service);
+    else if (find_file_in_dir(disabled_path, filepattern) != NULL) 
+        fprintf(stdout, "%s is disabled on boot.\n", service);
+    else
+        fprintf(stdout, "%s is not available for boot. (Service has no valid symlink in either %s or %s).\n", service, enabled_path, disabled_path);
+
+    free(filepattern);
+}
+
 int main(int argc, char *argv[]) {
-	char command[BUFFER_SIZE];
-
-	if (!(initsetuid()))
-		exit(1);
-
-	if (argc < 3) {
-		fprintf(stderr, "\nMissing arguments.\n\naddonctrl addon (start|stop|restart|reload|enable|disable)\n\n");
-		exit(1);
-	}
-
-	const char* name = argv[1];
-
-	if (strlen(name) > 32) {
-	    fprintf(stderr, "\nString to large.\n\naddonctrl addon (start|stop|restart|reload|enable|disable)\n\n");
-	    exit(1);
-	}
-
-	// Check if the input argument is valid
-	if (!is_valid_argument_alnum(name)) {
-		fprintf(stderr, "Invalid add-on name: %s\n", name);
-		exit(2);
-	}
-
-	sprintf(command, "/opt/pakfire/db/installed/meta-%s", name);
-	FILE *fp = fopen(command,"r");
-	if ( fp ) {
-	    fclose(fp);
-	} else {
-	    fprintf(stderr, "\nAddon '%s' not found.\n\naddonctrl addon (start|stop|restart|reload|status|enable|disable)\n\n", name);
-	    exit(1);
-	}
-
-	if (strcmp(argv[2], "start") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "/etc/rc.d/init.d/%s start", name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "stop") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "/etc/rc.d/init.d/%s stop", name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "restart") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "/etc/rc.d/init.d/%s restart", name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "reload") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "/etc/rc.d/init.d/%s reload", name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "status") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "/etc/rc.d/init.d/%s status", name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "enable") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "mv -f /etc/rc.d/rc3.d/off/S??%s /etc/rc.d/rc3.d" , name);
-		safe_system(command);
-	} else if (strcmp(argv[2], "disable") == 0) {
-		snprintf(command, BUFFER_SIZE - 1, "mkdir -p /etc/rc.d/rc3.d/off");
-		safe_system(command);
-		snprintf(command, BUFFER_SIZE - 1, "mv -f /etc/rc.d/rc3.d/S??%s /etc/rc.d/rc3.d/off" , name);
-		safe_system(command);
-	} else {
-		fprintf(stderr, "\nBad argument given.\n\naddonctrl addon (start|stop|restart|reload|enable|disable)\n\n");
-		exit(1);
-	}
-
-	return 0;
+    char **services = NULL;
+    int servicescnt = 0;
+    char *addon = argv[1];
+    char *action = argv[2];
+    char *service_filter = NULL;
+    int r = 0;
+
+    if (!(initsetuid()))
+        exit(1);
+
+    if (argc < 3) {
+        fprintf(stderr, "\nMissing arguments.\n\n%s\n\n", usage);
+        exit(1);
+    }
+
+    if (argc == 4 && strcmp(action, "list-services") != 0)
+        service_filter = argv[3];
+
+    if (strlen(addon) > 32) {
+        fprintf(stderr, "\nString too large.\n\n%s\n\n", usage);
+        exit(1);
+    }
+
+    // Check if the input argument is valid
+    if (!is_valid_argument_alnum(addon)) {
+        fprintf(stderr, "Invalid add-on name: %s.\n", addon);
+        exit(2);
+    }
+
+    // Get initscript name(s) from addon metadata
+    errno = 0;
+    services = get_addon_services(addon, &servicescnt, service_filter);
+    if (services == NULL || *services == 0) {
+        if (errno != 0)
+            fprintf(stderr, "\nSystem error occured. (Error: %d)\n\n", errno);
+        else if (strcmp(errormsg, "") != 0)
+            fprintf(stderr, "\n%s\n\n", errormsg);
+        else if (service_filter != NULL)
+            fprintf(stderr, "\nNo service '%s' found for addon '%s'. Use 'list-services' to get a list of available services\n\n%s\n\n", service_filter, addon, usage);
+        else
+            fprintf(stderr, "\nAddon '%s' has no services.\n\n", addon);
+        exit(1);
+    }
+
+    // Handle requested action
+    if (strcmp(action, "start") == 0 ||
+        strcmp(action, "stop") == 0 ||
+        strcmp(action, "restart") == 0 ||
+        strcmp(action, "reload") == 0 ||
+        strcmp(action, "status") == 0) {
+
+        errno = 0;
+        for(int i = 0; i < servicescnt; i++) {
+            if (initscript_action(services[i], action) != 0) {
+                r = 1;
+                if (errno != 0) 
+                    fprintf(stderr, "\nSystem error occured. (Error: %d)\n\n", errno);
+                    break;
+            }
+        }
+
+    } else if (strcmp(action, "enable") == 0 ||
+               strcmp(action, "disable") == 0) {
+
+        errno = 0;
+        for(int i = 0; i < servicescnt; i++) {
+            if (toggle_service(services[i], action) == 0) {
+                fprintf(stdout, "%sd service %s\n", action, services[i]);
+            } else if (errno != 0) {
+                r = 1;
+                fprintf(stderr, "\nSystem error occured. (Error: %d)\n\n", errno);
+                break;
+            } else {
+                r = 1;
+                fprintf(stderr, "\n%s\n\n", errormsg);
+            }
+        }
+
+    } else if (strcmp(action, "boot-status") == 0) {
+        errno = 0;
+        for(int i = 0; i < servicescnt; i++) {
+            print_boot_status(services[i]);
+            if (errno != 0) {
+                r = 1;
+                fprintf(stderr, "\nSystem error occured. (Error: %d)\n\n", errno);
+                break;
+            }
+        }
+    
+    } else if (strcmp(action, "list-services") == 0) {
+        fprintf(stdout, "\nServices for addon %s:\n", addon);
+        for(int i = 0; i < servicescnt; i++) {
+            fprintf(stdout, "  %s\n", services[i]);
+        }
+        fprintf(stdout, "\n");
+
+    } else {
+        fprintf(stderr, "\nBad argument given.\n\n%s\n\n", usage);
+        r = 1;
+    }
+
+    // Cleanup
+    for(int i = 0; i < servicescnt; i++) 
+        free(services[i]);
+    free(services);
+
+    return r;
 }
