Merge korg/donut into korg/master
diff --git a/init/builtins.c b/init/builtins.c
index bcdfee1..93ce6e8 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -127,7 +127,7 @@
 static void service_start_if_not_disabled(struct service *svc)
 {
     if (!(svc->flags & SVC_DISABLED)) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
 }
 
@@ -372,7 +372,7 @@
     struct service *svc;
     svc = service_find_by_name(args[1]);
     if (svc) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
@@ -393,7 +393,7 @@
     svc = service_find_by_name(args[1]);
     if (svc) {
         service_stop(svc);
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
diff --git a/init/devices.c b/init/devices.c
index e0b1f1f..60f9b9c 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -115,6 +115,7 @@
     { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 },
     { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 },
     { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 },
+    { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 },
     { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
     { "/dev/akm8976_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
     { "/dev/akm8976_pffd",  0640,   AID_COMPASS,    AID_SYSTEM,     0 },
@@ -126,10 +127,13 @@
     { "/dev/msm_audpre",    0660,   AID_SYSTEM,     AID_AUDIO,      0 },
     { "/dev/htc-acoustic",  0660,   AID_SYSTEM,     AID_AUDIO,      0 },
     { "/dev/smd0",          0640,   AID_RADIO,      AID_RADIO,      0 },
+    { "/dev/qemu_trace",    0666,   AID_SYSTEM,     AID_SYSTEM,     0 },
     { "/dev/qmi",           0640,   AID_RADIO,      AID_RADIO,      0 },
     { "/dev/qmi0",          0640,   AID_RADIO,      AID_RADIO,      0 },
     { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 },
     { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 },
+    { "/dev/ppp",           0660,   AID_RADIO,      AID_VPN,        0 },
+    { "/dev/tun",           0640,   AID_VPN,        AID_VPN,        0 },
     { NULL, 0, 0, 0, 0 },
 };
 
@@ -380,7 +384,10 @@
         } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
             base = "/dev/adsp/";
             mkdir(base, 0755);
-      } else if(!strncmp(uevent->subsystem, "input", 5)) {
+        } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
+            base = "/dev/msm_camera/";
+            mkdir(base, 0755);
+        } else if(!strncmp(uevent->subsystem, "input", 5)) {
             base = "/dev/input/";
             mkdir(base, 0755);
         } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
diff --git a/init/init.c b/init/init.c
index 1630155..dfc858a 100644
--- a/init/init.c
+++ b/init/init.c
@@ -156,7 +156,7 @@
     fcntl(fd, F_SETFD, 0);
 }
 
-void service_start(struct service *svc)
+void service_start(struct service *svc, const char *dynamic_args)
 {
     struct stat s;
     pid_t pid;
@@ -192,6 +192,13 @@
         return;
     }
 
+    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
+        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
+               svc->args[0]);
+        svc->flags |= SVC_DISABLED;
+        return;
+    }
+
     NOTICE("starting '%s'\n", svc->name);
 
     pid = fork();
@@ -248,8 +255,27 @@
             setuid(svc->uid);
         }
 
-        if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
-            ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
+        if (!dynamic_args)
+            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0)
+                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
+        else {
+            char *arg_ptrs[SVC_MAXARGS+1];
+            int arg_idx = svc->nargs;
+            char *tmp = strdup(dynamic_args);
+            char *next = tmp;
+            char *bword;
+
+            /* Copy the static arguments */
+            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
+
+            while((bword = strsep(&next, " "))) {
+                arg_ptrs[arg_idx++] = bword;
+                if (arg_idx == SVC_MAXARGS)
+                    break;
+            }
+            arg_ptrs[arg_idx] = '\0';
+            if (execve(svc->args[0], (char**) arg_ptrs, (char**) ENV) < 0)
+                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
         }
         _exit(127);
     }
@@ -381,7 +407,7 @@
 
     if (next_start_time <= gettime()) {
         svc->flags &= (~SVC_RESTARTING);
-        service_start(svc);
+        service_start(svc, NULL);
         return;
     }
 
@@ -407,13 +433,28 @@
 
 static void msg_start(const char *name)
 {
-    struct service *svc = service_find_by_name(name);
+    struct service *svc;
+    char *tmp = NULL;
+    char *args = NULL;
+
+    if (!strchr(name, ':'))
+        svc = service_find_by_name(name);
+    else {
+        tmp = strdup(name);
+        args = strchr(tmp, ':');
+        *args = '\0';
+        args++;
+
+        svc = service_find_by_name(tmp);
+    }
     
     if (svc) {
-        service_start(svc);
+        service_start(svc, args);
     } else {
         ERROR("no such service '%s'\n", name);
     }
+    if (tmp)
+        free(tmp);
 }
 
 static void msg_stop(const char *name)
@@ -423,7 +464,7 @@
     if (svc) {
         service_stop(svc);
     } else {
-        ERROR("no such service '%s'\n");
+        ERROR("no such service '%s'\n", name);
     }
 }
 
@@ -739,7 +780,7 @@
     svc = service_find_by_keychord(id);
     if (svc) {
         INFO("starting service %s from keychord\n", svc->name);
-        service_start(svc);   
+        service_start(svc, NULL);
     } else {
         ERROR("service for keychord %d not found\n", id);
     }
diff --git a/init/init.h b/init/init.h
index b686869..f306b7b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,7 +29,8 @@
 void log_init(void);
 void log_set_level(int level);
 void log_close(void);
-void log_write(int level, const char *fmt, ...);
+void log_write(int level, const char *fmt, ...)
+    __attribute__ ((format(printf, 2, 3)));
 
 #define ERROR(x...)   log_write(3, "<3>init: " x)
 #define NOTICE(x...)  log_write(5, "<5>init: " x)
@@ -115,6 +116,8 @@
 
 #define NR_SVC_SUPP_GIDS 6    /* six supplementary groups */
 
+#define SVC_MAXARGS 64
+
 struct service {
         /* list of all services */
     struct listnode slist;
@@ -136,15 +139,17 @@
     struct socketinfo *sockets;
     struct svcenvinfo *envvars;
 
-    int nargs;
-    char *args[1];
     struct action onrestart;  /* Actions to execute on restart. */
     
     /* keycodes for triggering this service via /dev/keychord */
     int *keycodes;
     int nkeycodes;
     int keychord_id;
-};
+
+    int nargs;
+    /* "MUST BE AT THE END OF THE STRUCT" */
+    char *args[1];
+}; /*     ^-------'args' MUST be at the end of this struct! */
 
 int parse_config_file(const char *fn);
 
@@ -157,7 +162,7 @@
 void service_for_each_flags(unsigned matchflags,
                             void (*func)(struct service *svc));
 void service_stop(struct service *svc);
-void service_start(struct service *svc);
+void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
 struct action *action_remove_queue_head(void);
diff --git a/init/parser.c b/init/parser.c
index 6a22d24..33c1a68 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -60,8 +60,6 @@
 #endif       
 }
 
-#define MAXARGS 64
-
 #define T_EOF 0
 #define T_TEXT 1
 #define T_NEWLINE 2
@@ -357,7 +355,7 @@
 static void parse_config(const char *fn, char *s)
 {
     struct parse_state state;
-    char *args[MAXARGS];
+    char *args[SVC_MAXARGS];
     int nargs;
 
     nargs = 0;
@@ -384,7 +382,7 @@
             }
             break;
         case T_TEXT:
-            if (nargs < MAXARGS) {
+            if (nargs < SVC_MAXARGS) {
                 args[nargs++] = state.text;
             }
             break;
@@ -536,7 +534,7 @@
             const char* name = act->name + strlen("property:");
             const char* equals = strchr(name, '=');
             if (equals) {
-                char* prop_name[PROP_NAME_MAX + 1];
+                char prop_name[PROP_NAME_MAX + 1];
                 const char* value;
                 int length = equals - name;
                 if (length > PROP_NAME_MAX) {
@@ -546,7 +544,7 @@
                     prop_name[length] = 0;
                     
                     /* does the property exist, and match the trigger value? */
-                    value = property_get((const char *)&prop_name[0]);
+                    value = property_get(prop_name);
                     if (value && !strcmp(equals + 1, value)) {
                         action_add_queue_tail(act);
                     }
diff --git a/init/property_service.c b/init/property_service.c
index 0bc6239..23a8821 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -67,6 +67,8 @@
     { "wlan.",		AID_SYSTEM },
     { "dhcp.",		AID_SYSTEM },
     { "dhcp.",		AID_DHCP },
+    { "vpn.",		AID_SYSTEM },
+    { "vpn.",		AID_VPN },
     { "debug.",		AID_SHELL },
     { "log.",		AID_SHELL },
     { "service.adb.root",	AID_SHELL },
@@ -296,7 +298,7 @@
         __futex_wake(&pa->serial, INT32_MAX);
     }
     /* If name starts with "net." treat as a DNS property. */
-    if (strncmp("net.", name, sizeof("net.") - 1) == 0)  {
+    if (strncmp("net.", name, strlen("net.")) == 0)  {
         if (strcmp("net.change", name) == 0) {
             return 0;
         }
@@ -307,7 +309,7 @@
         */
         property_set("net.change", name);
     } else if (persistent_properties_loaded &&
-            strncmp("persist.", name, sizeof("persist.") - 1) == 0) {
+            strncmp("persist.", name, strlen("persist.")) == 0) {
         /* 
          * Don't write properties to disk until after we have read all default properties
          * to prevent them from being overwritten by default values.
@@ -446,8 +448,7 @@
 
     if (dir) {
         while ((entry = readdir(dir)) != NULL) {
-            if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") ||
-                    strncmp("persist.", entry->d_name, sizeof("persist.") - 1))
+            if (strncmp("persist.", entry->d_name, strlen("persist.")))
                 continue;
 #if HAVE_DIRENT_D_TYPE
             if (entry->d_type != DT_REG)