Merge changes 23694,23695,23696 into eclair

* changes:
  init.rc: Add dumpstate service
  init: Add support for enforcing setprop by caller's group.
  adb: "adb bugreport" now runs dumpstate via init rather than execing it in the shell.
diff --git a/adb/commandline.c b/adb/commandline.c
index 411bb82..6603452 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -929,7 +929,7 @@
 
     if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
             || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
-            || !strcmp(argv[0], "root")) {
+            || !strcmp(argv[0], "root") || !strcmp(argv[0], "bugreport")) {
         char command[100];
         if (argc > 1)
             snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
@@ -945,14 +945,6 @@
         return 1;
     }
 
-    if(!strcmp(argv[0], "bugreport")) {
-        if (argc != 1) {
-            return 1;
-        }
-        do_cmd(ttype, serial, "shell", "dumpstate", "-", 0);
-        return 0;
-    }
-
     /* adb_command() wrapper commands */
 
     if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
diff --git a/adb/services.c b/adb/services.c
index 2864ac9..447c11b 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -188,6 +188,43 @@
     adb_close(fd);
 }
 
+void bugreport_service(int fd, void *cookie)
+{
+    char    buffer[MAX_PAYLOAD];
+    int i, s;
+
+    /* start the dumpstate service */
+    property_set("ctl.start", "dumpstate");
+
+    /* socket will not be available until service starts */
+    for (i = 0; i < 10; i++) {
+        s = socket_local_client("dumpstate",
+                             ANDROID_SOCKET_NAMESPACE_RESERVED,
+                             SOCK_STREAM);
+        if (s >= 0)
+            break;
+        /* try again in 1 second */
+        sleep(1);
+    }
+
+    if (s < 0) {
+        const char* failed = "Failed to connect to dumpstate service\n";
+        writex(fd, failed, strlen(failed));
+        adb_close(fd);
+        return;
+    }
+
+    while (1) {
+        int length = adb_read(s, buffer, sizeof(buffer));
+        if (length <= 0)
+            break;
+        if (adb_write(fd, buffer, length) <= 0)
+            break;
+    }
+    adb_close(s);
+    adb_close(fd);
+}
+
 #endif
 
 #if 0
@@ -469,6 +506,8 @@
         ret = create_service_thread(restart_tcp_service, (void *)port);
     } else if(!strncmp(name, "usb:", 4)) {
         ret = create_service_thread(restart_usb_service, NULL);
+    } else if(!strncmp(name, "bugreport:", 10)) {
+        ret = create_service_thread(bugreport_service, NULL);
 #endif
 #if 0
     } else if(!strncmp(name, "echo:", 5)){
diff --git a/init/property_service.c b/init/property_service.c
index 35929f0..7db7c2c 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -52,31 +52,32 @@
 struct {
     const char *prefix;
     unsigned int uid;
+    unsigned int gid;
 } property_perms[] = {
-    { "net.rmnet0.",      AID_RADIO },
-    { "net.gprs.",        AID_RADIO },
-    { "net.ppp",          AID_RADIO },
-    { "ril.",             AID_RADIO },
-    { "gsm.",             AID_RADIO },
-    { "persist.radio",    AID_RADIO },
-    { "net.dns",          AID_RADIO },
-    { "net.",             AID_SYSTEM },
-    { "dev.",             AID_SYSTEM },
-    { "runtime.",         AID_SYSTEM },
-    { "hw.",              AID_SYSTEM },
-    { "sys.",             AID_SYSTEM },
-    { "service.",         AID_SYSTEM },
-    { "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 },
-    { "persist.sys.",     AID_SYSTEM },
-    { "persist.service.", AID_SYSTEM },
-    { NULL, 0 }
+    { "net.rmnet0.",      AID_RADIO,    0 },
+    { "net.gprs.",        AID_RADIO,    0 },
+    { "net.ppp",          AID_RADIO,    0 },
+    { "ril.",             AID_RADIO,    0 },
+    { "gsm.",             AID_RADIO,    0 },
+    { "persist.radio",    AID_RADIO,    0 },
+    { "net.dns",          AID_RADIO,    0 },
+    { "net.",             AID_SYSTEM,   0 },
+    { "dev.",             AID_SYSTEM,   0 },
+    { "runtime.",         AID_SYSTEM,   0 },
+    { "hw.",              AID_SYSTEM,   0 },
+    { "sys.",             AID_SYSTEM,   0 },
+    { "service.",         AID_SYSTEM,   0 },
+    { "wlan.",            AID_SYSTEM,   0 },
+    { "dhcp.",            AID_SYSTEM,   0 },
+    { "dhcp.",            AID_DHCP,     0 },
+    { "vpn.",             AID_SYSTEM,   0 },
+    { "vpn.",             AID_VPN,      0 },
+    { "debug.",           AID_SHELL,    0 },
+    { "log.",             AID_SHELL,    0 },
+    { "service.adb.root", AID_SHELL,    0 },
+    { "persist.sys.",     AID_SYSTEM,   0 },
+    { "persist.service.", AID_SYSTEM,   0 },
+    { NULL, 0, 0 }
 };
 
 /*
@@ -86,8 +87,10 @@
 struct {
     const char *service;
     unsigned int uid;
+    unsigned int gid;
 } control_perms[] = {
-     {NULL, 0 }
+    { "dumpstate",AID_SHELL, AID_LOG },
+     {NULL, 0, 0 }
 };
 
 typedef struct {
@@ -183,7 +186,7 @@
  *
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_control_perms(const char *name, int uid) {
+static int check_control_perms(const char *name, int uid, int gid) {
     int i;
     if (uid == AID_SYSTEM || uid == AID_ROOT)
         return 1;
@@ -191,8 +194,10 @@
     /* Search the ACL */
     for (i = 0; control_perms[i].service; i++) {
         if (strcmp(control_perms[i].service, name) == 0) {
-            if (control_perms[i].uid == uid)
+            if ((uid && control_perms[i].uid == uid) ||
+                (gid && control_perms[i].gid == gid)) {
                 return 1;
+            }
         }
     }
     return 0;
@@ -202,7 +207,7 @@
  * Checks permissions for setting system properties.
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_perms(const char *name, unsigned int uid)
+static int check_perms(const char *name, unsigned int uid, int gid)
 {
     int i;
     if (uid == 0)
@@ -215,7 +220,8 @@
         int tmp;
         if (strncmp(property_perms[i].prefix, name,
                     strlen(property_perms[i].prefix)) == 0) {
-            if (property_perms[i].uid == uid) {
+            if ((uid && property_perms[i].uid == uid) ||
+                (gid && property_perms[i].gid == gid)) {
                 return 1;
             }
         }
@@ -373,14 +379,14 @@
         msg.value[PROP_VALUE_MAX-1] = 0;
 
         if(memcmp(msg.name,"ctl.",4) == 0) {
-            if (check_control_perms(msg.value, cr.uid)) {
+            if (check_control_perms(msg.value, cr.uid, cr.gid)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
                 ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
                         msg.name + 4, msg.value, cr.uid, cr.pid);
             }
         } else {
-            if (check_perms(msg.name, cr.uid)) {
+            if (check_perms(msg.name, cr.uid, cr.gid)) {
                 property_set((char*) msg.name, (char*) msg.value);
             } else {
                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 03563c3..7d9869f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -352,3 +352,7 @@
     group keystore
     socket keystore stream 666
 
+service dumpstate /system/bin/dumpstate -s
+    socket dumpstate stream 0660 shell log
+    disabled
+    oneshot