Merge "Redirect debug output to logcat." into lmp-dev
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index f8d7306..8409c63 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -57,7 +57,7 @@
     char *sep;
     int ret;
 
-    f = fopen(file, "r");
+    f = fopen(file, "re");
     if (!f) {
         D("Can't open '%s'\n", file);
         return;
@@ -126,7 +126,7 @@
     FILE *f;
     int ret;
 
-    f = fopen("/dev/urandom", "r");
+    f = fopen("/dev/urandom", "re");
     if (!f)
         return 0;
 
@@ -257,6 +257,7 @@
         D("Failed to get adbd socket\n");
         return;
     }
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
 
     ret = listen(fd, 4);
     if (ret < 0) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index e6f64bb..7933858 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -183,18 +183,18 @@
     unsigned int timestamp = 0;
     int fd;
 
-    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     if(fd < 0 && errno == ENOENT) {
         if(mkdirs(path) != 0) {
             if(fail_errno(s))
                 return -1;
             fd = -1;
         } else {
-            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
         }
     }
     if(fd < 0 && errno == EEXIST) {
-        fd = adb_open_mode(path, O_WRONLY, mode);
+        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
     }
     if(fd < 0) {
         if(fail_errno(s))
@@ -388,7 +388,7 @@
     syncmsg msg;
     int fd, r;
 
-    fd = adb_open(path, O_RDONLY);
+    fd = adb_open(path, O_RDONLY | O_CLOEXEC);
     if(fd < 0) {
         if(fail_errno(s)) return -1;
         return 0;
diff --git a/adb/remount_service.c b/adb/remount_service.c
index fd81e28..72d15a1 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -40,7 +40,7 @@
     const char delims[] = "\n";
     char buf[4096];
 
-    fd = unix_open("/proc/mounts", O_RDONLY);
+    fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         return NULL;
 
@@ -93,7 +93,7 @@
     if (!dev)
         return -1;
 
-    fd = unix_open(dev, O_RDONLY);
+    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         return -1;
 
diff --git a/adb/services.c b/adb/services.c
index bff935c..2875ce0 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -190,7 +190,7 @@
     setsid();
 
     // Set OOM score adjustment to prevent killing
-    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY);
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
     if (fd >= 0) {
         adb_write(fd, "0", 1);
         adb_close(fd);
@@ -209,12 +209,11 @@
     char *devname;
     int ptm;
 
-    ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
+    ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
     if(ptm < 0){
         printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
         return -1;
     }
-    fcntl(ptm, F_SETFD, FD_CLOEXEC);
 
     if(grantpt(ptm) || unlockpt(ptm) ||
        ((devname = (char*) ptsname(ptm)) == 0)){
@@ -233,7 +232,7 @@
     if (*pid == 0) {
         init_subproc_child();
 
-        int pts = unix_open(devname, O_RDWR);
+        int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
         if (pts < 0) {
             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
             exit(-1);
@@ -418,7 +417,7 @@
 #endif
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
-        ret = unix_open(name + 4, O_RDWR);
+        ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
     } else if(!strncmp(name, "framebuffer:", 12)) {
         ret = create_service_thread(framebuffer_service, 0);
     } else if (!strncmp(name, "jdwp:", 5)) {
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 8ff753e..f16bdd0 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -170,7 +170,7 @@
             }
 
 //            DBGX("[ scanning %s ]\n", devname);
-            if((fd = unix_open(devname, O_RDONLY)) < 0) {
+            if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) {
                 continue;
             }
 
@@ -597,10 +597,10 @@
     usb->mark = 1;
     usb->reaper_thread = 0;
 
-    usb->desc = unix_open(usb->fname, O_RDWR);
+    usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
     if(usb->desc < 0) {
         /* if we fail, see if have read-only access */
-        usb->desc = unix_open(usb->fname, O_RDONLY);
+        usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
         if(usb->desc < 0) goto fail;
         usb->writeable = 0;
         D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
deleted file mode 100644
index dbdbd60..0000000
--- a/include/cutils/tztime.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CUTILS_TZTIME_H
-#define _CUTILS_TZTIME_H
-
-// TODO: fix both callers to just include <bionic_time.h> themselves.
-#include <bionic_time.h>
-
-#endif /* __CUTILS_TZTIME_H */ 
-
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
index 1f5421d..9a8b282 100644
--- a/include/netutils/ifc.h
+++ b/include/netutils/ifc.h
@@ -49,19 +49,8 @@
 extern int ifc_set_hwaddr(const char *name, const void *ptr);
 extern int ifc_clear_addresses(const char *name);
 
-/* This function is deprecated. Use ifc_add_route instead. */
-extern int ifc_add_host_route(const char *name, in_addr_t addr);
-extern int ifc_remove_host_routes(const char *name);
-extern int ifc_get_default_route(const char *ifname);
-/* This function is deprecated. Use ifc_add_route instead */
-extern int ifc_set_default_route(const char *ifname, in_addr_t gateway);
-/* This function is deprecated. Use ifc_add_route instead */
 extern int ifc_create_default_route(const char *name, in_addr_t addr);
 extern int ifc_remove_default_route(const char *ifname);
-extern int ifc_add_route(const char *name, const char *addr, int prefix_length,
-                         const char *gw);
-extern int ifc_remove_route(const char *ifname, const char *dst,
-                            int prefix_length, const char *gw);
 extern int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength,
                         unsigned *flags);
 
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 4d004f6..3f6c6b5 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -563,17 +563,7 @@
     return ret;
 }
 
-/* deprecated v4-only */
-int ifc_add_host_route(const char *name, in_addr_t dst)
-{
-    struct in_addr in_dst, in_gw;
-
-    in_dst.s_addr = dst;
-    in_gw.s_addr = 0;
-
-    return ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 32, in_gw);
-}
-
+// Needed by code in hidden partner repositories / branches, so don't delete.
 int ifc_enable(const char *ifname)
 {
     int result;
@@ -584,6 +574,7 @@
     return result;
 }
 
+// Needed by code in hidden partner repositories / branches, so don't delete.
 int ifc_disable(const char *ifname)
 {
     unsigned addr, count;
@@ -648,118 +639,6 @@
 }
 
 /*
- * Remove the routes associated with the named interface.
- */
-int ifc_remove_host_routes(const char *name)
-{
-    char ifname[64];
-    in_addr_t dest, gway, mask;
-    int flags, refcnt, use, metric, mtu, win, irtt;
-    struct rtentry rt;
-    FILE *fp;
-    struct in_addr addr;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL)
-        return -1;
-    /* Skip the header line */
-    if (fscanf(fp, "%*[^\n]\n") < 0) {
-        fclose(fp);
-        return -1;
-    }
-    ifc_init();
-    for (;;) {
-        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
-                           ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
-                           &mtu, &win, &irtt);
-        if (nread != 11) {
-            break;
-        }
-        if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
-                || strcmp(ifname, name) != 0) {
-            continue;
-        }
-        memset(&rt, 0, sizeof(rt));
-        rt.rt_dev = (void *)name;
-        init_sockaddr_in(&rt.rt_dst, dest);
-        init_sockaddr_in(&rt.rt_gateway, gway);
-        init_sockaddr_in(&rt.rt_genmask, mask);
-        addr.s_addr = dest;
-        if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
-            ALOGD("failed to remove route for %s to %s: %s",
-                 ifname, inet_ntoa(addr), strerror(errno));
-        }
-    }
-    fclose(fp);
-    ifc_close();
-    return 0;
-}
-
-/*
- * Return the address of the default gateway
- *
- * TODO: factor out common code from this and remove_host_routes()
- * so that we only scan /proc/net/route in one place.
- *
- * DEPRECATED
- */
-int ifc_get_default_route(const char *ifname)
-{
-    char name[64];
-    in_addr_t dest, gway, mask;
-    int flags, refcnt, use, metric, mtu, win, irtt;
-    int result;
-    FILE *fp;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL)
-        return 0;
-    /* Skip the header line */
-    if (fscanf(fp, "%*[^\n]\n") < 0) {
-        fclose(fp);
-        return 0;
-    }
-    ifc_init();
-    result = 0;
-    for (;;) {
-        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
-                           name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
-                           &mtu, &win, &irtt);
-        if (nread != 11) {
-            break;
-        }
-        if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
-                && dest == 0
-                && strcmp(ifname, name) == 0) {
-            result = gway;
-            break;
-        }
-    }
-    fclose(fp);
-    ifc_close();
-    return result;
-}
-
-/*
- * Sets the specified gateway as the default route for the named interface.
- * DEPRECATED
- */
-int ifc_set_default_route(const char *ifname, in_addr_t gateway)
-{
-    struct in_addr addr;
-    int result;
-
-    ifc_init();
-    addr.s_addr = gateway;
-    if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
-        ALOGD("failed to add %s as default route for %s: %s",
-             inet_ntoa(addr), ifname, strerror(errno));
-    }
-    ifc_close();
-    return result;
-}
-
-/*
  * Removes the default route for the named interface.
  */
 int ifc_remove_default_route(const char *ifname)
@@ -821,151 +700,3 @@
 
     return 0;
 }
-
-int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
-      struct in6_addr gw)
-{
-    struct in6_rtmsg rtmsg;
-    int result;
-    int ifindex;
-
-    memset(&rtmsg, 0, sizeof(rtmsg));
-
-    ifindex = if_nametoindex(ifname);
-    if (ifindex == 0) {
-        printerr("if_nametoindex() failed: interface %s\n", ifname);
-        return -ENXIO;
-    }
-
-    rtmsg.rtmsg_ifindex = ifindex;
-    rtmsg.rtmsg_dst = dst;
-    rtmsg.rtmsg_dst_len = prefix_length;
-    rtmsg.rtmsg_flags = RTF_UP;
-
-    if (prefix_length == 128) {
-        rtmsg.rtmsg_flags |= RTF_HOST;
-    }
-
-    if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) {
-        rtmsg.rtmsg_flags |= RTF_GATEWAY;
-        rtmsg.rtmsg_gateway = gw;
-    }
-
-    ifc_init6();
-
-    if (ifc_ctl_sock6 < 0) {
-        return -errno;
-    }
-
-    result = ioctl(ifc_ctl_sock6, action, &rtmsg);
-    if (result < 0) {
-        if (errno == EEXIST) {
-            result = 0;
-        } else {
-            result = -errno;
-        }
-    }
-    ifc_close6();
-    return result;
-}
-
-int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
-        const char *gw)
-{
-    int ret = 0;
-    struct sockaddr_in ipv4_dst, ipv4_gw;
-    struct sockaddr_in6 ipv6_dst, ipv6_gw;
-    struct addrinfo hints, *addr_ai, *gw_ai;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = AF_UNSPEC;  /* Allow IPv4 or IPv6 */
-    hints.ai_flags = AI_NUMERICHOST;
-
-    ret = getaddrinfo(dst, NULL, &hints, &addr_ai);
-
-    if (ret != 0) {
-        printerr("getaddrinfo failed: invalid address %s\n", dst);
-        return -EINVAL;
-    }
-
-    if (gw == NULL || (strlen(gw) == 0)) {
-        if (addr_ai->ai_family == AF_INET6) {
-            gw = "::";
-        } else if (addr_ai->ai_family == AF_INET) {
-            gw = "0.0.0.0";
-        }
-    }
-
-    if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
-            ((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
-        printerr("ifc_add_route: invalid prefix length");
-        freeaddrinfo(addr_ai);
-        return -EINVAL;
-    }
-
-    ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
-    if (ret != 0) {
-        printerr("getaddrinfo failed: invalid gateway %s\n", gw);
-        freeaddrinfo(addr_ai);
-        return -EINVAL;
-    }
-
-    if (addr_ai->ai_family != gw_ai->ai_family) {
-        printerr("ifc_add_route: different address families: %s and %s\n", dst, gw);
-        freeaddrinfo(addr_ai);
-        freeaddrinfo(gw_ai);
-        return -EINVAL;
-    }
-
-    if (addr_ai->ai_family == AF_INET6) {
-        memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
-        memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
-        ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
-                prefix_length, ipv6_gw.sin6_addr);
-    } else if (addr_ai->ai_family == AF_INET) {
-        memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
-        memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
-        ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
-                prefix_length, ipv4_gw.sin_addr);
-    } else {
-        printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
-                  addr_ai->ai_family);
-        ret = -EAFNOSUPPORT;
-    }
-
-    freeaddrinfo(addr_ai);
-    freeaddrinfo(gw_ai);
-    return ret;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
-      struct in_addr gw)
-{
-    int i =ifc_act_on_ipv4_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-    if (DBG) printerr("ifc_add_ipv4_route(%s, xx, %d, xx) = %d", ifname, prefix_length, i);
-    return i;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
-      struct in6_addr gw)
-{
-    return ifc_act_on_ipv6_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-}
-
-int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
-{
-    int i = ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-    if (DBG) printerr("ifc_add_route(%s, %s, %d, %s) = %d", ifname, dst, prefix_length, gw, i);
-    return i;
-}
-
-int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
-{
-    return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
-}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9b316d1..85756d5 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -284,21 +284,21 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         int size, consumed, max, payload;
-        char size_mult, consumed_mult;
+        char size_mult[2], consumed_mult[2];
         long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
         // NB: crash log can be very small, not hit a Kb of consumed space
         //     doubly lucky we are not including it.
-        if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed),"
+        if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed),"
                                 " max entry is %db, max payload is %db",
-                                &size, &size_mult, &consumed, &consumed_mult,
+                                &size, size_mult, &consumed, consumed_mult,
                                 &max, &payload)) {
             fprintf(stderr, "WARNING: Parse error: %s", buffer);
             continue;
         }
         full_size = size;
-        switch(size_mult) {
+        switch(size_mult[0]) {
         case 'G':
             full_size *= 1024;
             /* FALLTHRU */
@@ -307,10 +307,12 @@
             /* FALLTHRU */
         case 'K':
             full_size *= 1024;
+            /* FALLTHRU */
+        case 'b':
             break;
         }
         full_consumed = consumed;
-        switch(consumed_mult) {
+        switch(consumed_mult[0]) {
         case 'G':
             full_consumed *= 1024;
             /* FALLTHRU */
@@ -319,6 +321,8 @@
             /* FALLTHRU */
         case 'K':
             full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'b':
             break;
         }
         EXPECT_GT((full_size * 9) / 4, full_consumed);
@@ -477,6 +481,45 @@
     EXPECT_EQ(1, signals);
 }
 
+TEST(logcat, logrotate) {
+    static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+    char buf[sizeof(form)];
+    ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
+
+    static const char comm[] = "logcat -b radio -b events -b system -b main"
+                                     " -d -f %s/log.txt -n 7 -r 1";
+    char command[sizeof(buf) + sizeof(comm)];
+    sprintf(command, comm, buf);
+
+    int ret;
+    EXPECT_FALSE((ret = system(command)));
+    if (!ret) {
+        sprintf(command, "ls -s %s 2>/dev/null", buf);
+
+        FILE *fp;
+        EXPECT_TRUE(NULL != (fp = popen(command, "r")));
+        if (fp) {
+            char buffer[5120];
+            int count = 0;
+
+            while (fgets(buffer, sizeof(buffer), fp)) {
+                static const char match[] = "4 log.txt";
+                static const char total[] = "total ";
+
+                if (!strncmp(buffer, match, sizeof(match) - 1)) {
+                    ++count;
+                } else if (strncmp(buffer, total, sizeof(total) - 1)) {
+                    fprintf(stderr, "WARNING: Parse error: %s", buffer);
+                }
+            }
+            pclose(fp);
+            EXPECT_TRUE(count == 7 || count == 8);
+        }
+    }
+    sprintf(command, "rm -rf %s", buf);
+    EXPECT_FALSE(system(command));
+}
+
 static void caught_blocking_clear(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55C0000ULL;
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 2308f37..4e83ba4 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -102,7 +102,6 @@
     { "dhcp",   1, do_dhcp },
     { "up",     1, ifc_up },
     { "down",   1, ifc_down },
-    { "flhosts",  1, ifc_remove_host_routes },
     { "deldefault", 1, ifc_remove_default_route },
     { "hwaddr", 2, set_hwaddr },
     { 0, 0, 0 },
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bbce64f..8eef76b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -184,11 +184,12 @@
     # issued fs triggers have completed.
     trigger load_all_props_action
 
+    # Remove a file to wake up anything waiting for firmware.
+    trigger firmware_mounts_complete
+
     trigger early-boot
     trigger boot
 
-    # Remove a file to wake up anything waiting for firmware
-    trigger firmware_mounts_complete
 
 on post-fs
     # once everything is setup, no need to modify /
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index d3afcb1..587a4cd 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -20,6 +20,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <linux/fuse.h>
 #include <pthread.h>
@@ -828,7 +829,7 @@
     pthread_mutex_lock(&fuse->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
+    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
         parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -850,7 +851,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
-    TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
+    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
             hdr->nodeid, node ? node->name : "?");
     if (node) {
         __u64 n = req->nlookup;
@@ -870,7 +871,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
+    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -895,7 +896,7 @@
     pthread_mutex_lock(&fuse->lock);
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
+    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -960,7 +961,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -991,7 +992,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1040,7 +1041,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
+    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1069,7 +1070,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
+    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1107,7 +1108,7 @@
             old_parent_path, sizeof(old_parent_path));
     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
             new_parent_path, sizeof(new_parent_path));
-    TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
+    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
             old_name, new_name,
             hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
             req->newdir, new_parent_node ? new_parent_node->name : "?");
@@ -1191,7 +1192,7 @@
     pthread_mutex_lock(&fuse->lock);
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
             req->flags, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1233,8 +1234,8 @@
      * overlaps the request buffer and will clobber data in the request.  This
      * saves us 128KB per request handler thread at the cost of this scary comment. */
 
-    TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
-            h, h->fd, size, offset);
+    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
+            h, h->fd, size, (uint64_t) offset);
     if (size > MAX_READ) {
         return -EINVAL;
     }
@@ -1260,7 +1261,7 @@
         buffer = (const __u8*) aligned_buffer;
     }
 
-    TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
+    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
             h, h->fd, req->size, req->offset);
     res = pwrite64(h->fd, buffer, req->size, req->offset);
     if (res < 0) {
@@ -1355,7 +1356,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
+    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
             hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1556,7 +1557,7 @@
     }
 
     default: {
-        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
+        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
         return -ENOSYS;
     }
@@ -1659,7 +1660,7 @@
         }
     }
 
-    TRACE("read_package_list: found %d packages, %d with write_gid\n",
+    TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
             hashmapSize(fuse->package_to_appid),
             hashmapSize(fuse->appid_with_rw));
     fclose(file);
@@ -1856,6 +1857,7 @@
     bool split_perms = false;
     int i;
     struct rlimit rlim;
+    int fs_version;
 
     int opt;
     while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
@@ -1930,6 +1932,11 @@
         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
     }
 
+    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
+        ERROR("installd fs upgrade not yet complete. Waiting...\n");
+        sleep(1);
+    }
+
     res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
     return res < 0 ? 1 : 0;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index c53f17d..fb2c5c7 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -1,4 +1,17 @@
 LOCAL_PATH:= $(call my-dir)
+
+common_cflags := \
+    -std=gnu99 \
+    -Werror -Wno-unused-parameter \
+    -include bsd-compatibility.h \
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/kill/kill.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=kill_main
+LOCAL_MODULE := libtoolbox_kill
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
 include $(CLEAR_VARS)
 
 TOOLS := \
@@ -24,7 +37,6 @@
 	insmod \
 	ioctl \
 	ionice \
-	kill \
 	ln \
 	load_policy \
 	log \
@@ -79,7 +91,8 @@
 ALL_TOOLS = $(TOOLS)
 ALL_TOOLS += \
 	cp \
-	grep
+	grep \
+	kill \
 
 LOCAL_SRC_FILES := \
 	cp/cp.c \
@@ -94,10 +107,7 @@
 	toolbox.c \
 	uid_from_user.c \
 
-LOCAL_CFLAGS += \
-    -std=gnu99 \
-    -Werror -Wno-unused-parameter \
-    -include bsd-compatibility.h \
+LOCAL_CFLAGS += $(common_cflags)
 
 LOCAL_C_INCLUDES += external/openssl/include
 
@@ -111,6 +121,9 @@
 LOCAL_STATIC_LIBRARIES := \
     libusbhost \
 
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+    libtoolbox_kill \
+
 LOCAL_MODULE := toolbox
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
diff --git a/toolbox/cp/cp.c b/toolbox/cp/cp.c
index e666453..0ea206e 100644
--- a/toolbox/cp/cp.c
+++ b/toolbox/cp/cp.c
@@ -95,7 +95,7 @@
 
 static int copy(char *[], enum op, int);
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 static void
 progress(int sig __unused)
 {
@@ -112,9 +112,7 @@
 	int ch, fts_options, r, have_trailing_slash;
 	char *target, **src;
 
-#ifndef ANDROID
 	setprogname(argv[0]);
-#endif
 	(void)setlocale(LC_ALL, "");
 
 	Hflag = Lflag = Pflag = Rflag = 0;
@@ -222,7 +220,7 @@
 	/* Set end of argument list for fts(3). */
 	argv[argc] = NULL;
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	(void)signal(SIGINFO, progress);
 #endif
 
diff --git a/toolbox/cp/utils.c b/toolbox/cp/utils.c
index 9d0390f..12c3d67 100644
--- a/toolbox/cp/utils.c
+++ b/toolbox/cp/utils.c
@@ -42,7 +42,7 @@
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
 #include <sys/extattr.h>
 #endif
 
@@ -58,7 +58,7 @@
 
 #include "extern.h"
 
-#ifdef ANDROID
+#ifdef __ANDROID__
 #define MAXBSIZE 65536
 #endif
 
@@ -70,7 +70,7 @@
 {
     static struct timeval tv[2];
 
-#ifdef ANDROID
+#ifdef __ANDROID__
     tv[0].tv_sec = fs->st_atime;
     tv[0].tv_usec = 0;
     tv[1].tv_sec = fs->st_mtime;
@@ -198,7 +198,9 @@
 	 * There's no reason to do anything other than close the file
 	 * now if it's empty, so let's not bother.
 	 */
+#ifndef __ANDROID__ // Files in /proc report length 0. mmap will fail but we'll fall back to read.
 	if (fs->st_size > 0) {
+#endif
 		struct finfo fi;
 
 		fi.from = entp->fts_path;
@@ -273,9 +275,11 @@
 				rval = 1;
 			}
 		}
+#ifndef __ANDROID__
 	}
+#endif
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (pflag && (fcpxattr(from_fd, to_fd) != 0))
 		warn("%s: error copying extended attributes", to.p_path);
 #endif
@@ -381,9 +385,7 @@
 setfile(struct stat *fs, int fd)
 {
 	int rval = 0;
-#ifndef ANDROID
 	int islink = S_ISLNK(fs->st_mode);
-#endif
 
 	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
 
@@ -401,7 +403,7 @@
 		}
 		fs->st_mode &= ~(S_ISUID | S_ISGID);
 	}
-#ifdef ANDROID
+#ifdef __ANDROID__
         if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
 #else
         if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
@@ -410,7 +412,7 @@
                 rval = 1;
         }
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (!islink && !Nflag) {
 		unsigned long fflags = fs->st_flags;
 		/*
diff --git a/toolbox/kill.c b/toolbox/kill.c
deleted file mode 100644
index fa2f649..0000000
--- a/toolbox/kill.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <signal.h>
-
-static struct {
-    unsigned int number;
-    char *name;
-} signals[] = {
-#define _SIG(name) {SIG##name, #name}
-    /* Single Unix Specification signals */
-    _SIG(ABRT),
-    _SIG(ALRM),
-    _SIG(FPE),
-    _SIG(HUP),
-    _SIG(ILL),
-    _SIG(INT),
-    _SIG(KILL),
-    _SIG(PIPE),
-    _SIG(QUIT),
-    _SIG(SEGV),
-    _SIG(TERM),
-    _SIG(USR1),
-    _SIG(USR2),
-    _SIG(CHLD),
-    _SIG(CONT),
-    _SIG(STOP),
-    _SIG(TSTP),
-    _SIG(TTIN),
-    _SIG(TTOU),
-    _SIG(BUS),
-    _SIG(POLL),
-    _SIG(PROF),
-    _SIG(SYS),
-    _SIG(TRAP),
-    _SIG(URG),
-    _SIG(VTALRM),
-    _SIG(XCPU),
-    _SIG(XFSZ),
-    /* non-SUS signals */
-    _SIG(IO),
-    _SIG(PWR),
-#ifdef SIGSTKFLT
-    _SIG(STKFLT),
-#endif
-    _SIG(WINCH),
-#undef _SIG
-};
-
-/* To indicate a matching signal was not found */
-static const unsigned int SENTINEL = (unsigned int) -1;
-
-void list_signals()
-{
-    unsigned int sorted_signals[_NSIG];
-    unsigned int i;
-    unsigned int num;
-
-    memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
-
-    // Sort the signals
-    for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
-        sorted_signals[signals[i].number] = i;
-    }
-
-    num = 0;
-    for (i = 1; i < _NSIG; i++) {
-        unsigned int index = sorted_signals[i];
-        if (index == SENTINEL) {
-            continue;
-        }
-
-        fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
-
-        if ((num++ % 4) == 3) {
-            fprintf(stderr, "\n");
-        }
-    }
-
-    if ((num % 4) == 3) {
-        fprintf(stderr, "\n");
-    }
-}
-
-unsigned int name_to_signal(const char* name)
-{
-    unsigned int i;
-
-    for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
-        if (!strcasecmp(name, signals[i].name)) {
-            return signals[i].number;
-        }
-    }
-
-    return SENTINEL;
-}
-
-int kill_main(int argc, char **argv)
-{
-    unsigned int sig = SIGTERM;
-    int result = 0;
-
-    argc--;
-    argv++;
-
-    if (argc >= 1 && argv[0][0] == '-') {
-        char *endptr;
-        size_t arg_len = strlen(argv[0]);
-        if (arg_len < 2) {
-            fprintf(stderr, "invalid argument: -\n");
-            return -1;
-        }
-
-        char* arg = argv[0] + 1;
-        if (arg_len == 2 && *arg == 'l') {
-            list_signals();
-            return 0;
-        }
-
-        sig = strtol(arg, &endptr, 10);
-        if (*endptr != '\0') {
-            sig = name_to_signal(arg);
-            if (sig == SENTINEL) {
-                fprintf(stderr, "invalid signal name: %s\n", arg);
-                return -1;
-            }
-        }
-
-        argc--;
-        argv++;
-    }
-
-    while(argc > 0){
-        int pid = atoi(argv[0]);
-        int err = kill(pid, sig);
-        if (err < 0) {
-            result = err;
-            fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
-        }
-
-        argc--;
-        argv++;
-    }
-
-    return result;
-}
diff --git a/toolbox/start.c b/toolbox/start.c
index 0941e64..6c8a3f2 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -11,6 +11,7 @@
         property_set("ctl.start", argv[1]);
     } else {
         /* defaults to starting the common services stopped by stop.c */
+        property_set("ctl.start", "netd");
         property_set("ctl.start", "surfaceflinger");
         property_set("ctl.start", "zygote");
         property_set("ctl.start", "zygote_secondary");
diff --git a/toolbox/stop.c b/toolbox/stop.c
index ed9a293..5e3ce3c 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -12,6 +12,7 @@
         property_set("ctl.stop", "zygote_secondary");
         property_set("ctl.stop", "zygote");
         property_set("ctl.stop", "surfaceflinger");
+        property_set("ctl.stop", "netd");
     }
 
     return 0;
diff --git a/toolbox/upstream-netbsd/bin/kill/kill.c b/toolbox/upstream-netbsd/bin/kill/kill.c
new file mode 100644
index 0000000..0592577
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/kill/kill.c
@@ -0,0 +1,253 @@
+/* $NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if !defined(lint) && !defined(SHELL)
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)kill.c	8.4 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/ioctl.h>
+
+#ifdef SHELL            /* sh (aka ash) builtin */
+int killcmd(int, char *argv[]);
+#define main killcmd
+#include "../../bin/sh/bltin/bltin.h"
+#endif /* SHELL */ 
+
+__dead static void nosig(char *);
+static void printsignals(FILE *);
+static int signame_to_signum(char *);
+__dead static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	int errors;
+	intmax_t numsig, pid;
+	char *ep;
+
+	setprogname(argv[0]);
+	setlocale(LC_ALL, "");
+	if (argc < 2)
+		usage();
+
+	numsig = SIGTERM;
+
+	argc--, argv++;
+	if (strcmp(*argv, "-l") == 0) {
+		argc--, argv++;
+		if (argc > 1)
+			usage();
+		if (argc == 1) {
+			if (isdigit((unsigned char)**argv) == 0)
+				usage();
+			numsig = strtoimax(*argv, &ep, 10);
+			/* check for correctly parsed number */
+			if (*ep != '\0' || numsig == INTMAX_MIN || numsig == INTMAX_MAX) {
+				errx(EXIT_FAILURE, "illegal signal number: %s",
+						*argv);
+				/* NOTREACHED */
+			}
+			if (numsig >= 128)
+				numsig -= 128;
+			/* and whether it fits into signals range */
+			if (numsig <= 0 || numsig >= NSIG)
+				nosig(*argv);
+			printf("%s\n", sys_signame[(int) numsig]);
+			exit(0);
+		}
+		printsignals(stdout);
+		exit(0);
+	}
+
+	if (!strcmp(*argv, "-s")) {
+		argc--, argv++;
+		if (argc < 1) {
+			warnx("option requires an argument -- s");
+			usage();
+		}
+		if (strcmp(*argv, "0")) {
+			if ((numsig = signame_to_signum(*argv)) < 0)
+				nosig(*argv);
+		} else
+			numsig = 0;
+		argc--, argv++;
+	} else if (**argv == '-') {
+		char *sn = *argv + 1;
+		if (isalpha((unsigned char)*sn)) {
+			if ((numsig = signame_to_signum(sn)) < 0)
+				nosig(sn);
+		} else if (isdigit((unsigned char)*sn)) {
+			numsig = strtoimax(sn, &ep, 10);
+			/* check for correctly parsed number */
+			if (*ep || numsig == INTMAX_MIN || numsig == INTMAX_MAX ) {
+				errx(EXIT_FAILURE, "illegal signal number: %s",
+						sn);
+				/* NOTREACHED */
+			}
+			/* and whether it fits into signals range */
+			if (numsig < 0 || numsig >= NSIG)
+				nosig(sn);
+		} else
+			nosig(sn);
+		argc--, argv++;
+	}
+
+	if (argc == 0)
+		usage();
+
+	for (errors = 0; argc; argc--, argv++) {
+#ifdef SHELL
+		extern int getjobpgrp(const char *);
+		if (*argv[0] == '%') {
+			pid = getjobpgrp(*argv);
+			if (pid == 0) {
+				warnx("illegal job id: %s", *argv);
+				errors = 1;
+				continue;
+			}
+		} else 
+#endif
+		{
+			pid = strtoimax(*argv, &ep, 10);
+			/* make sure the pid is a number and fits into pid_t */
+			if (!**argv || *ep || pid == INTMAX_MIN ||
+				pid == INTMAX_MAX || pid != (pid_t) pid) {
+
+				warnx("illegal process id: %s", *argv);
+				errors = 1;
+				continue;
+			}
+		}
+		if (kill((pid_t) pid, (int) numsig) == -1) {
+			warn("%s", *argv);
+			errors = 1;
+		}
+#ifdef SHELL
+		/* Wakeup the process if it was suspended, so it can
+		   exit without an explicit 'fg'. */
+		if (numsig == SIGTERM || numsig == SIGHUP)
+			kill((pid_t) pid, SIGCONT);
+#endif
+	}
+
+	exit(errors);
+	/* NOTREACHED */
+}
+
+static int
+signame_to_signum(char *sig)
+{
+	int n;
+
+	if (strncasecmp(sig, "sig", 3) == 0)
+		sig += 3;
+	for (n = 1; n < NSIG; n++) {
+		if (!strcasecmp(sys_signame[n], sig))
+			return (n);
+	}
+	return (-1);
+}
+
+static void
+nosig(char *name)
+{
+
+	warnx("unknown signal %s; valid signals:", name);
+	printsignals(stderr);
+	exit(1);
+	/* NOTREACHED */
+}
+
+static void
+printsignals(FILE *fp)
+{
+	int sig;
+	int len, nl;
+	const char *name;
+	int termwidth = 80;
+
+	if (isatty(fileno(fp))) {
+		struct winsize win;
+		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
+			termwidth = win.ws_col;
+	}
+
+	for (len = 0, sig = 1; sig < NSIG; sig++) {
+		name = sys_signame[sig];
+		nl = 1 + strlen(name);
+
+		if (len + nl >= termwidth) {
+			fprintf(fp, "\n");
+			len = 0;
+		} else
+			if (len != 0)
+				fprintf(fp, " ");
+		len += nl;
+		fprintf(fp, "%s", name);
+	}
+	if (len != 0)
+		fprintf(fp, "\n");
+}
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
+	    "       %s -l [exit_status]\n"
+	    "       %s -signal_name pid ...\n"
+	    "       %s -signal_number pid ...\n",
+	    getprogname(), getprogname(), getprogname(), getprogname());
+	exit(1);
+	/* NOTREACHED */
+}