Merge "File header cleanup."
diff --git a/adb/.clang-format b/adb/.clang-format
index 2b83a1f..0395c8e 100644
--- a/adb/.clang-format
+++ b/adb/.clang-format
@@ -4,8 +4,8 @@
 
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
-IndentWidth: 2
+IndentWidth: 4
 PointerAlignment: Left
-TabWidth: 2
+TabWidth: 4
 UseTab: Never
 PenaltyExcessCharacter: 32
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 9cb002f..b9e957f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
 LOCAL_CONLYFLAGS += -std=gnu99
-LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -Wall -Wextra -Werror
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -53,9 +53,11 @@
 
 LOCAL_STATIC_LIBRARIES := \
     $(EXTRA_STATIC_LIBS) \
-    libzipfile \
+    libziparchive-host \
     libext4_utils_host \
     libsparse_host \
+    libutils \
+    liblog \
     libz
 
 ifneq ($(HOST_OS),windows)
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 04f3166..6dc7d34 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -45,7 +45,7 @@
 #include <unistd.h>
 
 #include <sparse/sparse.h>
-#include <zipfile/zipfile.h>
+#include <ziparchive/zip_archive.h>
 
 #include "bootimg_utils.h"
 #include "fastboot.h"
@@ -379,30 +379,26 @@
     return bdata;
 }
 
-static void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
+static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
 {
-    void *data;
-    zipentry_t entry;
-    unsigned datasz;
-
-    entry = lookup_zipentry(zip, name);
-    if (entry == NULL) {
-        fprintf(stderr, "archive does not contain '%s'\n", name);
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return 0;
     }
 
-    *sz = get_zipentry_size(entry);
+    *sz = zip_entry.uncompressed_length;
 
-    datasz = *sz * 1.001;
-    data = malloc(datasz);
-
-    if(data == 0) {
-        fprintf(stderr, "failed to allocate %d bytes\n", *sz);
+    uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
+    if (data == NULL) {
+        fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name);
         return 0;
     }
 
-    if (decompress_zipentry(entry, data, datasz)) {
-        fprintf(stderr, "failed to unzip '%s' from archive\n", name);
+    int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
         free(data);
         return 0;
     }
@@ -410,24 +406,28 @@
     return data;
 }
 
-static int unzip_to_file(zipfile_t zip, char *name)
-{
-    int fd = fileno(tmpfile());
-    if (fd < 0) {
+static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
+    FILE* fp = tmpfile();
+    if (fp == NULL) {
+        fprintf(stderr, "failed to create temporary file for '%s': %s\n",
+                entry_name, strerror(errno));
         return -1;
     }
 
-    unsigned sz;
-    void* data = unzip_file(zip, name, &sz);
-    if (data == 0) {
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return -1;
     }
 
-    if (write(fd, data, sz) != (ssize_t)sz) {
-        fd = -1;
+    int fd = fileno(fp);
+    int error = ExtractEntryToFile(zip, &zip_entry, fd);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
+        return -1;
     }
 
-    free(data);
     lseek(fd, 0, SEEK_SET);
     return fd;
 }
@@ -693,11 +693,10 @@
     flash_buf(pname, &buf);
 }
 
-void do_update_signature(zipfile_t zip, char *fn)
+void do_update_signature(ZipArchiveHandle zip, char *fn)
 {
-    void *data;
     unsigned sz;
-    data = unzip_file(zip, fn, &sz);
+    void* data = unzip_file(zip, fn, &sz);
     if (data == 0) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
@@ -709,23 +708,16 @@
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    unsigned zsize;
-    void* zdata = load_file(filename, &zsize);
-    if (zdata == 0) die("failed to load '%s': %s", filename, strerror(errno));
-
-    zipfile_t zip = init_zipfile(zdata, zsize);
-    if (zip == 0) die("failed to access zipdata in '%s'");
+    ZipArchiveHandle zip;
+    int error = OpenArchive(filename, &zip);
+    if (error != 0) {
+        die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
+    }
 
     unsigned sz;
     void* data = unzip_file(zip, "android-info.txt", &sz);
     if (data == 0) {
-            /* fallback for older zipfiles */
-        data = unzip_file(zip, "android-product.txt", &sz);
-        if ((data == 0) || (sz < 1)) {
-            die("update package has no android-info.txt or android-product.txt");
-        }
-        data = mkmsg("board=%sversion-baseband=0.66.04.19\n", reinterpret_cast<char*>(data));
-        sz = strlen(reinterpret_cast<char*>(data));
+        die("update package '%s' has no android-info.txt", filename);
     }
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
@@ -750,6 +742,8 @@
          * program exits.
          */
     }
+
+    CloseArchive(zip);
 }
 
 void do_send_signature(char *fn)
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index 10a84c1..5b97600 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -305,7 +305,10 @@
         return -1;
     }
 
-    fb_download_data_sparse_flush(usb);
+    r = fb_download_data_sparse_flush(usb);
+    if (r < 0) {
+        return -1;
+    }
 
     return _command_end(usb);
 }
diff --git a/init/init.cpp b/init/init.cpp
index e1c82a4..5a40fd3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
@@ -40,6 +41,8 @@
 #include <selinux/label.h>
 #include <selinux/android.h>
 
+#include <base/file.h>
+#include <base/stringprintf.h>
 #include <cutils/android_reboot.h>
 #include <cutils/fs.h>
 #include <cutils/iosched_policy.h>
@@ -47,6 +50,8 @@
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 
+#include <memory>
+
 #include "devices.h"
 #include "init.h"
 #include "log.h"
@@ -66,8 +71,6 @@
 
 static char console[32];
 static char bootmode[32];
-static char hardware[32];
-static unsigned revision = 0;
 static char qemu[32];
 
 static struct action *cur_action = NULL;
@@ -773,6 +776,8 @@
         { "ro.boot.mode", "ro.bootmode", "unknown", },
         { "ro.boot.baseband", "ro.baseband", "unknown", },
         { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+        { "ro.boot.hardware", "ro.hardware", "unknown", },
+        { "ro.boot.revision", "ro.revision", "0", },
     };
 
     for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
@@ -791,16 +796,6 @@
     property_get("ro.bootmode", tmp);
     strlcpy(bootmode, tmp, sizeof(bootmode));
 
-    /* if this was given on kernel command line, override what we read
-     * before (e.g. from /proc/cpuinfo), if anything */
-    ret = property_get("ro.boot.hardware", tmp);
-    if (ret)
-        strlcpy(hardware, tmp, sizeof(hardware));
-    property_set("ro.hardware", hardware);
-
-    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
-    property_set("ro.revision", tmp);
-
     /* TODO: these are obsolete. We should delete them */
     if (!strcmp(bootmode,"factory"))
         property_set("ro.factorytest", "1");
@@ -810,6 +805,40 @@
         property_set("ro.factorytest", "0");
 }
 
+static void process_kernel_dt(void)
+{
+    static const char android_dir[] = "/proc/device-tree/firmware/android";
+
+    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+
+    std::string dt_file;
+    android::base::ReadFileToString(file_name, &dt_file);
+    if (!dt_file.compare("android,firmware")) {
+        ERROR("firmware/android is not compatible with 'android,firmware'\n");
+        return;
+    }
+
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+    if (!dir)
+        return;
+
+    struct dirent *dp;
+    while ((dp = readdir(dir.get())) != NULL) {
+        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+            continue;
+
+        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
+
+        android::base::ReadFileToString(file_name, &dt_file);
+        std::replace(dt_file.begin(), dt_file.end(), ',', '.');
+
+        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        if (property_set(property_name.c_str(), dt_file.c_str())) {
+            ERROR("Could not set property %s to value %s", property_name.c_str(), dt_file.c_str());
+        }
+    }
+}
+
 static void process_kernel_cmdline(void)
 {
     /* don't expose the raw commandline to nonpriv processes */
@@ -822,11 +851,6 @@
     import_kernel_cmdline(0, import_kernel_nv);
     if (qemu[0])
         import_kernel_cmdline(1, import_kernel_nv);
-
-    /* now propogate the info given on command line to internal variables
-     * used by init as well as the current required properties
-     */
-    export_kernel_boot_props();
 }
 
 static int property_service_init_action(int nargs, char **args)
@@ -1014,10 +1038,17 @@
     klog_init();
     property_init();
 
-    get_hardware_name(hardware, &revision);
-
+    process_kernel_dt();
+    /* in case one is passing arguments both on the command line and in DT
+     * Properties set in DT always have priority over the command-line ones
+     */
     process_kernel_cmdline();
 
+    /* now propogate the kernel variables to internal variables
+     * used by init as well as the current required properties
+     */
+    export_kernel_boot_props();
+
     selinux_callback cb;
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index d56b91a..5af6e3d 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -30,28 +30,13 @@
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-
-static char hardware[32];
-static unsigned revision = 0;
-
-static void import_kernel_nv(char *name, int in_qemu)
-{
-    if (*name != '\0') {
-        char *value = strchr(name, '=');
-        if (value != NULL) {
-            *value++ = 0;
-            if (!strcmp(name,"androidboot.hardware"))
-            {
-                strlcpy(hardware, value, sizeof(hardware));
-            }
-        }
-    }
-}
+#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
     struct pollfd ufd;
     int nr;
+    char hardware[PROP_VALUE_MAX];
     char tmp[32];
 
     /*
@@ -83,12 +68,7 @@
 
     INFO("starting ueventd\n");
 
-    /* Respect hardware passed in through the kernel cmd line. Here we will look
-     * for androidboot.hardware param in kernel cmdline, and save its value in
-     * hardware[]. */
-    import_kernel_cmdline(0, import_kernel_nv);
-
-    get_hardware_name(hardware, &revision);
+    property_get("ro.hardware", hardware);
 
     ueventd_parse_config_file("/ueventd.rc");
 
diff --git a/init/util.cpp b/init/util.cpp
index c805083..8b238d4 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -400,39 +400,6 @@
     exit(1);
 }
 
-void get_hardware_name(char *hardware, unsigned int *revision) {
-  // Hardware string was provided on kernel command line.
-  if (hardware[0]) {
-    return;
-  }
-
-  FILE* fp = fopen("/proc/cpuinfo", "re");
-  if (fp == NULL) {
-    return;
-  }
-  char buf[1024];
-  while (fgets(buf, sizeof(buf), fp) != NULL) {
-    if (strncmp(buf, "Hardware", 8) == 0) {
-      const char* hw = strstr(buf, ": ");
-      if (hw) {
-        hw += 2;
-        size_t n = 0;
-        while (*hw) {
-          if (!isspace(*hw)) {
-            hardware[n++] = tolower(*hw);
-          }
-          hw++;
-          if (n == 31) break;
-        }
-        hardware[n] = 0;
-      }
-    } else if (strncmp(buf, "Revision", 8) == 0) {
-      sscanf(buf, "Revision : %ux", revision);
-    }
-  }
-  fclose(fp);
-}
-
 void import_kernel_cmdline(int in_qemu,
                            void (*import_kernel_nv)(char *name, int in_qemu))
 {
diff --git a/init/util.h b/init/util.h
index 77da3ac..e0b3c69 100644
--- a/init/util.h
+++ b/init/util.h
@@ -42,7 +42,6 @@
 void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void open_devnull_stdio(void);
-void get_hardware_name(char *hardware, unsigned int *revision);
 void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index aa614bc..697db25 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -62,6 +62,8 @@
 LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
 LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 # Really this should go away entirely or at least not depend on
diff --git a/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h
similarity index 100%
rename from include/pixelflinger/format.h
rename to libpixelflinger/include/pixelflinger/format.h
diff --git a/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
similarity index 100%
rename from include/pixelflinger/pixelflinger.h
rename to libpixelflinger/include/pixelflinger/pixelflinger.h
diff --git a/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
similarity index 100%
rename from include/private/pixelflinger/ggl_context.h
rename to libpixelflinger/include/private/pixelflinger/ggl_context.h
diff --git a/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
similarity index 100%
rename from include/private/pixelflinger/ggl_fixed.h
rename to libpixelflinger/include/private/pixelflinger/ggl_fixed.h
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 961f323..448d298 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -13,7 +13,7 @@
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger
+    $(LOCAL_PATH)/../../..
 
 LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
 
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index 8f62f09..d8f7e69 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -7,9 +7,6 @@
 
 LOCAL_SHARED_LIBRARIES :=
 
-LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger/codeflinger
-
 LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
 
 LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index bc07015..2f9ca2f 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -9,7 +9,7 @@
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../..
 
 LOCAL_MODULE:= test-opengl-codegen
 
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index f479fa1..75bd39e 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -7,7 +7,7 @@
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../../include
 
 LOCAL_MODULE:= test-pixelflinger-gglmul
 
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index baa30cd..65c09e0 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -101,26 +101,32 @@
 	return chunks;
 }
 
-static void sparse_file_write_block(struct output_file *out,
+static int sparse_file_write_block(struct output_file *out,
 		struct backed_block *bb)
 {
+	int ret = -EINVAL;
+
 	switch (backed_block_type(bb)) {
 	case BACKED_BLOCK_DATA:
-		write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
+		ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
 		break;
 	case BACKED_BLOCK_FILE:
-		write_file_chunk(out, backed_block_len(bb),
-				backed_block_filename(bb), backed_block_file_offset(bb));
+		ret = write_file_chunk(out, backed_block_len(bb),
+				       backed_block_filename(bb),
+				       backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FD:
-		write_fd_chunk(out, backed_block_len(bb),
-				backed_block_fd(bb), backed_block_file_offset(bb));
+		ret = write_fd_chunk(out, backed_block_len(bb),
+				     backed_block_fd(bb),
+				     backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FILL:
-		write_fill_chunk(out, backed_block_len(bb),
-				backed_block_fill_val(bb));
+		ret = write_fill_chunk(out, backed_block_len(bb),
+				       backed_block_fill_val(bb));
 		break;
 	}
+
+	return ret;
 }
 
 static int write_all_blocks(struct sparse_file *s, struct output_file *out)
@@ -128,6 +134,7 @@
 	struct backed_block *bb;
 	unsigned int last_block = 0;
 	int64_t pad;
+	int ret = 0;
 
 	for (bb = backed_block_iter_new(s->backed_block_list); bb;
 			bb = backed_block_iter_next(bb)) {
@@ -135,7 +142,9 @@
 			unsigned int blocks = backed_block_block(bb) - last_block;
 			write_skip_chunk(out, (int64_t)blocks * s->block_size);
 		}
-		sparse_file_write_block(out, bb);
+		ret = sparse_file_write_block(out, bb);
+		if (ret)
+			return ret;
 		last_block = backed_block_block(bb) +
 				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
 	}
@@ -230,6 +239,7 @@
 	struct backed_block *bb;
 	struct backed_block *start;
 	int64_t file_len = 0;
+	int ret;
 
 	/*
 	 * overhead is sparse file header, initial skip chunk, split chunk, end
@@ -249,7 +259,11 @@
 	for (bb = start; bb; bb = backed_block_iter_next(bb)) {
 		count = 0;
 		/* will call out_counter_write to update count */
-		sparse_file_write_block(out_counter, bb);
+		ret = sparse_file_write_block(out_counter, bb);
+		if (ret) {
+			bb = NULL;
+			goto out;
+		}
 		if (file_len + count > len) {
 			/*
 			 * If the remaining available size is more than 1/8th of the
@@ -260,16 +274,17 @@
 				backed_block_split(from->backed_block_list, bb, len - file_len);
 				last_bb = bb;
 			}
-			goto out;
+			goto move;
 		}
 		file_len += count;
 		last_bb = bb;
 	}
 
-out:
+move:
 	backed_block_list_move(from->backed_block_list,
 		to->backed_block_list, start, last_bb);
 
+out:
 	output_file_close(out_counter);
 
 	return bb;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index b822ea0..959dc22 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -60,7 +60,6 @@
     restorecon \
     route \
     runcon \
-    schedtop \
     sendevent \
     setprop \
     start \
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
deleted file mode 100644
index 2fccd2e..0000000
--- a/toolbox/schedtop.c
+++ /dev/null
@@ -1,330 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-struct thread_info {
-    int pid;
-    int tid;
-    char name[64];
-    unsigned long long exec_time;
-    unsigned long long delay_time;
-    unsigned long long run_count;
-};
-
-struct thread_table {
-    size_t allocated;
-    size_t active;
-    struct thread_info *data;
-};
-
-enum {
-    FLAG_BATCH = 1U << 0,
-    FLAG_HIDE_IDLE = 1U << 1,
-    FLAG_SHOW_THREADS = 1U << 2,
-    FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
-};
-
-static int time_dp = 9;
-static int time_div = 1;
-#define NS_TO_S_D(ns) \
-    (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
-
-struct thread_table processes;
-struct thread_table last_processes;
-struct thread_table threads;
-struct thread_table last_threads;
-
-static void grow_table(struct thread_table *table)
-{
-    size_t size = table->allocated;
-    struct thread_info *new_table;
-    if (size < 128)
-        size = 128;
-    else
-        size *= 2;
-    
-    new_table = realloc(table->data, size * sizeof(*table->data));
-    if (new_table == NULL) {
-        fprintf(stderr, "out of memory\n");
-        exit(1);
-    }
-    table->data = new_table;
-    table->allocated = size;
-}
-
-static struct thread_info *get_item(struct thread_table *table)
-{
-    if (table->active >= table->allocated)
-        grow_table(table);
-    return table->data + table->active;
-}
-
-static void commit_item(struct thread_table *table)
-{
-    table->active++;
-}
-
-static int read_line(char *line, size_t line_size)
-{
-    int fd;
-    int len;
-    fd = open(line, O_RDONLY);
-    if(fd == 0)
-        return -1;
-    len = read(fd, line, line_size - 1);
-    close(fd);
-    if (len <= 0)
-        return -1;
-    line[len] = '\0';
-    return 0;
-}
-
-static void add_thread(int pid, int tid, struct thread_info *proc_info)
-{
-    char line[1024];
-    char *name, *name_end;
-    size_t name_len;
-    struct thread_info *info;
-    if(tid == 0)
-        info = get_item(&processes);
-    else
-        info = get_item(&threads);
-    info->pid = pid;
-    info->tid = tid;
-
-    if(tid)
-        sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
-    else
-        sprintf(line, "/proc/%d/schedstat", pid);
-    if (read_line(line, sizeof(line)))
-        return;
-    if(sscanf(line, "%llu %llu %llu",
-              &info->exec_time, &info->delay_time, &info->run_count) != 3)
-        return;
-    if (proc_info) {
-        proc_info->exec_time += info->exec_time;
-        proc_info->delay_time += info->delay_time;
-        proc_info->run_count += info->run_count;
-    }
-
-    name = NULL;
-    if (!tid) {
-        sprintf(line, "/proc/%d/cmdline", pid);
-        if (read_line(line, sizeof(line)) == 0 && line[0]) {
-            name = line;
-            name_len = strlen(name);
-        }
-    }
-    if (!name) {
-        if (tid)
-            sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
-        else
-            sprintf(line, "/proc/%d/stat", pid);
-        if (read_line(line, sizeof(line)))
-            return;
-        name = strchr(line, '(');
-        if (name == NULL)
-            return;
-        name_end = strchr(name, ')');
-        if (name_end == NULL)
-            return;
-        name++;
-        name_len = name_end - name;
-    }
-    if (name_len >= sizeof(info->name))
-        name_len = sizeof(info->name) - 1;
-    memcpy(info->name, name, name_len);
-    info->name[name_len] = '\0';
-    if(tid == 0)
-        commit_item(&processes);
-    else
-        commit_item(&threads);
-}
-
-static void add_threads(int pid, struct thread_info *proc_info)
-{
-    char path[1024];
-    DIR *d;
-    struct dirent *de;
-    sprintf(path, "/proc/%d/task", pid);
-    d = opendir(path);
-    if(d == 0) return;
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int tid = atoi(de->d_name);
-            add_thread(pid, tid, proc_info);
-        }
-    }
-    closedir(d);
-}
-
-static void print_threads(int pid, uint32_t flags)
-{
-    size_t i, j;
-    for (i = 0; i < last_threads.active; i++) {
-        int epid = last_threads.data[i].pid;
-        int tid = last_threads.data[i].tid;
-        if (epid != pid)
-            continue;
-        for (j = 0; j < threads.active; j++)
-            if (tid == threads.data[j].tid)
-                break;
-        if (j == threads.active)
-            printf(" %5u died\n", tid);
-        else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
-            printf(" %5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu  %s\n", tid,
-                NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
-                NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
-                threads.data[j].run_count - last_threads.data[i].run_count,
-                NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
-                threads.data[j].run_count, threads.data[j].name);
-    }
-}
-
-static void update_table(DIR *d, uint32_t flags)
-{
-    size_t i, j;
-    struct dirent *de;
-    
-    rewinddir(d);
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int pid = atoi(de->d_name);
-            struct thread_info *proc_info;
-            add_thread(pid, 0, NULL);
-            proc_info = &processes.data[processes.active - 1];
-            proc_info->exec_time = 0;
-            proc_info->delay_time = 0;
-            proc_info->run_count = 0;
-            add_threads(pid, proc_info);
-        }
-    }
-    if (!(flags & FLAG_BATCH))
-        printf("\e[H\e[0J");
-    printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
-    switch (time_dp) {
-    case 3:
-        printf("   TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
-        printf("  PID  EXEC_T  DELAY SCHED EXEC_TIME DELAY_TIM   SCHED NAME\n");
-        break;
-    case 6:
-        printf("   TID ------ SINCE LAST -------    ------------ TOTAL -----------\n");
-        printf("  PID  EXEC_TIME DELAY_TIM SCHED    EXEC_TIME   DELAY_TIME   SCHED NAME\n");
-        break;
-    default:
-        printf("   TID    -------- SINCE LAST --------       ------------- TOTAL -------------\n");
-        printf("  PID     EXEC_TIME   DELAY_TIME SCHED       EXEC_TIME      DELAY_TIME   SCHED NAME\n");
-        break;
-    }
-    for (i = 0; i < last_processes.active; i++) {
-        int pid = last_processes.data[i].pid;
-        for (j = 0; j < processes.active; j++)
-            if (pid == processes.data[j].pid)
-                break;
-        if (j == processes.active)
-            printf("%5u died\n", pid);
-        else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
-            printf("%5u  %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", pid,
-                NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
-                NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
-                processes.data[j].run_count - last_processes.data[i].run_count,
-                NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
-                processes.data[j].run_count, processes.data[j].name);
-            if (flags & FLAG_SHOW_THREADS)
-                print_threads(pid, flags);
-        }
-    }
-
-    {
-        struct thread_table tmp;
-        tmp = last_processes;
-        last_processes = processes;
-        processes = tmp;
-        processes.active = 0;
-        tmp = last_threads;
-        last_threads = threads;
-        threads = tmp;
-        threads.active = 0;
-    }
-}
-
-void
-sig_abort(int signum)
-{
-    printf("\e[?47l");
-    exit(0);
-}
-
-
-int schedtop_main(int argc, char **argv)
-{
-    int c;
-    DIR *d;
-    uint32_t flags = 0;    
-    int delay = 3000000;
-    float delay_f;
-
-    while(1) {
-        c = getopt(argc, argv, "d:ibtamun");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'd':
-            delay_f = atof(optarg);
-            delay = delay_f * 1000000;
-            break;
-        case 'b':
-            flags |= FLAG_BATCH;
-            break;
-        case 'i':
-            flags |= FLAG_HIDE_IDLE;
-            break;
-        case 't':
-            flags |= FLAG_SHOW_THREADS;
-            break;
-        case 'a':
-            flags |= FLAG_USE_ALTERNATE_SCREEN;
-            break;
-        case 'm':
-            time_dp = 3;
-            time_div = 1000000;
-            break;
-        case 'u':
-            time_dp = 6;
-            time_div = 1000;
-            break;
-        case 'n':
-            time_dp = 9;
-            time_div = 1;
-            break;
-        }
-    }
-
-    d = opendir("/proc");
-    if(d == 0) return -1;
-
-    if (!(flags & FLAG_BATCH)) {
-        if(flags & FLAG_USE_ALTERNATE_SCREEN) {
-            signal(SIGINT, sig_abort);
-            signal(SIGPIPE, sig_abort);
-            signal(SIGTERM, sig_abort);
-            printf("\e7\e[?47h");
-        }
-        printf("\e[2J");
-    }
-    while (1) {
-        update_table(d, flags);
-        usleep(delay);
-    }
-    closedir(d);
-    return 0;
-}