diff --git a/src/misc-progs/addonctrl.c b/src/misc-progs/addonctrl.c
index 14b4b1325..277bd1809 100644
--- a/src/misc-progs/addonctrl.c
+++ b/src/misc-progs/addonctrl.c
@@ -10,71 +10,333 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <fcntl.h>
+#include <dirent.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] = "";
+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";
+
+// Check if <text> matches <pattern>. Wildcard '?' matches any single character.
+// Returns 1 when found, 0 when not found
+int match(const char *pattern, const char *text) {
+    if (pattern[0] == '\0' && *text == '\0')
+        return 1;
+    if (*text != '\0' && (pattern[0]=='?' || pattern[0]==*text))
+        return match(pattern+1, text+1);
+    return 0;
+}
+
+// Find a file <path> using <filepattern> allowing the '?' wildcard.
+// Returns the found filename or NULL if not found
+char* find_file_in_dir(const char *path, const char *filepattern) 
+{
+    static struct dirent *entry;
+    DIR *dp;
+    int found = 0;
+
+    if ((dp = opendir(path)) != NULL) {
+        while(found == 0 && (entry = readdir(dp)) != NULL)
+            found = match(filepattern, entry->d_name);
+
+        closedir(dp);
+    }
+
+    if (! found) {
+        return NULL;
+    }
+
+    return entry->d_name;
+}
+
+// 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 *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[BUFFER_SIZE];
+    int i = 0;
+    char *metafile = malloc((strlen(metafile_prefix) + strlen(addon) + 1) * sizeof(char));
+ 
+    sprintf(metafile, "%s%s", metafile_prefix, addon);
+    FILE *fp = fopen(metafile,"r");
+    if ( fp ) {
+        // Get initscript(s) for addon from meta-file
+        while (!feof(fp) && services == NULL) {
+            if (fgets(line, BUFFER_SIZE - 1, fp) != 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) {
+                        services = malloc((strlen(token) + 1) * sizeof (char *));
+
+                        // Put each service in services array
+                        service = strtok(token, service_delim);
+                        while (service != NULL) {
+                            services[i] = malloc((strlen(service) + 1) * sizeof (char));
+                            strcpy(services[i++], service);
+
+                            service = strtok(NULL, service_delim);
+                        }
+                    }
+                }
+            } else {
+                snprintf(errormsg, BUFFER_SIZE - 1, "Could not read '%s' metadata for addon '%s'.", metadata_key, addon);
+            }
+        }
+        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 *command = malloc((strlen(initd_path) + 1 + strlen(service) + 1) * sizeof(char));
+    int r = 0;
+
+    sprintf(command, "%s/%s %s", initd_path, service, action);
+    r = safe_system(command);
+    free(command);
+
+    return r; 
+}
+
+// Move an initscript with filepattern from <src_path> to <dest_path>
+// Returns:
+//   -1: Error during move. Details in errno (returned by C rename function)
+//   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, *dest;
+    int r = 1;
+    char *filename = find_file_in_dir(src_path, filepattern);
+
+    if ( filename != NULL ) {
+        src = malloc((strlen(src_path) + 1 + strlen(filename) + 1) * sizeof(char));
+        dest = malloc((strlen(dest_path) + 1 + strlen(filename) + 1) * sizeof(char));
+        sprintf(src, "%s/%s", src_path, filename);
+        sprintf(dest, "%s/%s", dest_path, filename);
+
+        r = rename(src, dest);
+
+        free(src);
+        free(dest);
+    } else {
+        filename = find_file_in_dir(dest_path, filepattern);
+        if (filename == NULL)
+            r = 2;
+    }
+
+    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 = malloc((3 + strlen(service) + 1) * sizeof(char));
+    int r = 0;
+    
+    sprintf(filepattern, "S??%s", service);
+
+    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
+    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 = malloc((3 + strlen(service) + 1) * sizeof(char));
+    sprintf(filepattern, "S??%s", service);
+    char *enabled = find_file_in_dir(enabled_path, filepattern);
+    char *disabled = find_file_in_dir(disabled_path, filepattern);
+
+    if (enabled != NULL) 
+        fprintf(stdout, "%s is enabled on boot.\n", service);
+    else if (disabled != 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;
+    char **services_ptr = NULL;
+    int servicescnt = 0;
+    char *addon = argv[1];
+    char *action = argv[2];
+    char *service_filter = NULL;
+    int actioned = 0;
+    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) 
+        service_filter = argv[3];
+
+    if (strlen(addon) > 32) {
+        fprintf(stderr, "\nString to 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
+    services_ptr = get_addon_services(addon, &servicescnt);
+    services = services_ptr;
+    if (services == NULL || *services == 0) {
+        if (strcmp(errormsg, "") != 0)
+            fprintf(stderr, "\n%s\n\n", errormsg);
+        else
+            fprintf(stderr, "\nAddon '%s' has no services.\n\n", addon);
+        exit(1);
+    }
+
+    if (strcmp(action, "start") == 0 ||
+        strcmp(action, "stop") == 0 ||
+        strcmp(action, "restart") == 0 ||
+        strcmp(action, "reload") == 0 ||
+        strcmp(action, "status") == 0) {
+
+        while (*services != 0) {
+            if ((service_filter != NULL && strcmp(service_filter, *services) == 0) || 
+                 service_filter == NULL) {
+                if (initscript_action(*services, action) != 0) 
+                    r = 1;
+                ++actioned;
+            }
+            ++services;
+        }
+
+    } else if (strcmp(action, "enable") == 0 ||
+               strcmp(action, "disable") == 0) {
+
+        while (*services != 0) {
+            if ((service_filter != NULL && strcmp(service_filter, *services) == 0) || 
+                 service_filter == NULL) {
+                if (toggle_service(*services, action) == 0) {
+                    fprintf(stdout, "%sd service %s\n", action, *services);
+                }
+                else {
+                    r = 1;
+                    fprintf(stderr, "\n%s\n\n", errormsg);
+                }
+                
+                ++actioned;
+            }
+            ++services;
+        }
+
+    } else if (strcmp(action, "boot-status") == 0) {
+        while(*services != 0) {
+            if ((service_filter != NULL && strcmp(service_filter, *services) == 0) || 
+                 service_filter == NULL) {
+                print_boot_status(*services);
+                ++actioned;
+            }
+            ++services;
+        }
+    
+    } else if (strcmp(action, "list-services") == 0) {
+        fprintf(stdout, "\nServices for addon %s:\n", addon);
+        while (*services != 0) {
+            fprintf(stdout, "  %s\n", *services);
+            ++actioned;
+            ++services;
+        }
+        fprintf(stdout, "\n");
+
+    } else {
+        fprintf(stderr, "\nBad argument given.\n\n%s\n\n", usage);
+        r = 1;
+    }
+
+    if (r == 0 && service_filter != NULL && actioned == 0) {
+        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);
+        r = 1;
+    }
+
+    // Cleanup
+    for(int i = 0; i < servicescnt; i++) 
+        free(services_ptr[i]);
+    free(services_ptr);
+
+    return r;
 }
