Port git to Fuchsia, add build files, etc

This provides a basic port of git and some subcommands to Fuchsia and
adds a GN build. This is sufficient to run basic local git commands and
clone repositories over https.

Change-Id: I2e0221e498f80f81be70e595500c1ba09bbedc4a
diff --git a/.gitignore b/.gitignore
index 833ef3b..c2a3cbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,7 +179,6 @@
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
-/common-cmds.h
 *.tar.gz
 *.dsc
 *.deb
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..77ab2e3
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,612 @@
+# Copyright 2017 The Fuchsia Authors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * 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.
+#    * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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.
+
+config("git_config") {
+  cflags = [
+    "-Wno-sign-compare",
+    "-Wno-missing-field-initializers",
+    "-Wno-pointer-bool-conversion",
+    "-Wno-tautological-compare",
+  ]
+  defines = [
+    "BINDIR=\"/bin\"",
+    "DEFAULT_PAGER=\"cat\"",
+    "ETC_GITATTRIBUTES=\"/etc/gitattributes\"",
+    "ETC_GITCONFIG=\"/etc/gitconfig\"",
+    "GAWK",
+    "GIT_EXEC_PATH=\"\"",
+    "GIT_HTML_PATH=\"/html\"",
+    "GIT_INFO_PATH=\"/info\"",
+    "GIT_LOCALE_PATH=\"/share/locale\"",
+    "GIT_MAN_PATH=\"/man\"",
+    "GIT_USER_AGENT=\"git\"",
+    "GIT_VERSION=\"\"",
+    "HAVE_CLOCK_GETTIME",
+    "HAVE_CLOCK_MONOTONIC",
+    "HAVE_GETDELIM",
+    "HAVE_SYS_IOCTL_H",
+    "NO_MBSUPPORT",
+    "NO_MMAP",
+    "NO_PERL",
+    "NO_REGEX",
+    "NO_SYS_POLL_H",
+    "PAGER_ENV=\"LESS=FRX LV=-c\"",
+    "PREFIX=\"/system/bin\"",
+  ]
+  include_dirs = [
+    ".",
+    "compat/regex",
+  ]
+}
+
+source_set("git_srcs") {
+  sources = [
+    "abspath.c",
+    "advice.c",
+    "advice.h",
+    "alias.c",
+    "alloc.c",
+    "apply.c",
+    "apply.h",
+    "archive-tar.c",
+    "archive-zip.c",
+    "archive.c",
+    "archive.h",
+    "argv-array.c",
+    "argv-array.h",
+    "attr.c",
+    "attr.h",
+    "base85.c",
+    "bisect.c",
+    "bisect.h",
+    "blob.c",
+    "blob.h",
+    "block-sha1/sha1.c",
+    "block-sha1/sha1.h",
+    "branch.c",
+    "branch.h",
+    "bulk-checkin.c",
+    "bulk-checkin.h",
+    "bundle.c",
+    "bundle.h",
+    "cache-tree.c",
+    "cache-tree.h",
+    "cache.h",
+
+    # "check-racy.c",
+    "color.c",
+    "color.h",
+    "column.c",
+    "column.h",
+    "combine-diff.c",
+    "commit-slab.h",
+    "commit.c",
+    "commit.h",
+    "common-main.c",
+    "compat/bswap.h",
+    "compat/fopen.c",
+    "compat/hstrerror.c",
+    "compat/memmem.c",
+    "compat/mkdir.c",
+    "compat/mkdtemp.c",
+    "compat/mmap.c",
+    "compat/obstack.c",
+    "compat/obstack.h",
+    "compat/poll/poll.c",
+    "compat/poll/poll.h",
+    "compat/pread.c",
+    "compat/qsort.c",
+    "compat/qsort_s.c",
+    "compat/regex/regex.c",
+    "compat/regex/regex.h",
+    "compat/setenv.c",
+    "compat/snprintf.c",
+    "compat/stat.c",
+    "compat/strcasestr.c",
+    "compat/strlcpy.c",
+    "compat/strtoimax.c",
+    "compat/strtoumax.c",
+    "compat/terminal.c",
+    "compat/terminal.h",
+    "config.c",
+    "connect.c",
+    "connect.h",
+    "connected.c",
+    "connected.h",
+    "convert.c",
+    "convert.h",
+    "copy.c",
+
+    # "credential-cache--daemon.c",
+    # "credential-cache.c",
+    # "credential-store.c",
+    "credential.c",
+    "credential.h",
+    "csum-file.c",
+    "csum-file.h",
+    "ctype.c",
+    "date.c",
+    "decorate.c",
+    "decorate.h",
+    "delta.h",
+    "diff-delta.c",
+    "diff-lib.c",
+    "diff-no-index.c",
+    "diff.c",
+    "diff.h",
+    "diffcore-break.c",
+    "diffcore-delta.c",
+    "diffcore-order.c",
+    "diffcore-pickaxe.c",
+    "diffcore-rename.c",
+    "diffcore.h",
+    "dir-iterator.c",
+    "dir-iterator.h",
+    "dir.c",
+    "dir.h",
+    "editor.c",
+    "entry.c",
+    "environment.c",
+    "ewah/bitmap.c",
+    "ewah/ewah_bitmap.c",
+    "ewah/ewah_io.c",
+    "ewah/ewah_rlw.c",
+    "ewah/ewok.h",
+    "ewah/ewok_rlw.h",
+    "exec_cmd.c",
+    "exec_cmd.h",
+
+    # "fast-import.c",
+    "fetch-pack.c",
+    "fetch-pack.h",
+    "fmt-merge-msg.h",
+    "fsck.c",
+    "fsck.h",
+    "gettext.c",
+    "gettext.h",
+    "git-compat-util.h",
+    "gpg-interface.c",
+    "gpg-interface.h",
+    "graph.c",
+    "graph.h",
+    "grep.c",
+    "grep.h",
+    "hash.h",
+    "hashmap.c",
+    "hashmap.h",
+    "help.c",
+    "help.h",
+    "hex.c",
+
+    "ident.c",
+
+    # "imap-send.c",
+    "iterator.h",
+    "khash.h",
+    "kwset.c",
+    "kwset.h",
+    "levenshtein.c",
+    "levenshtein.h",
+    "line-log.c",
+    "line-log.h",
+    "line-range.c",
+    "line-range.h",
+    "list-objects.c",
+    "list-objects.h",
+    "list.h",
+    "ll-merge.c",
+    "ll-merge.h",
+    "lockfile.c",
+    "lockfile.h",
+    "log-tree.c",
+    "log-tree.h",
+    "mailinfo.c",
+    "mailinfo.h",
+    "mailmap.c",
+    "mailmap.h",
+    "match-trees.c",
+    "merge-blobs.c",
+    "merge-blobs.h",
+    "merge-recursive.c",
+    "merge-recursive.h",
+    "merge.c",
+    "mergesort.c",
+    "mergesort.h",
+    "mru.c",
+    "mru.h",
+    "name-hash.c",
+    "notes-cache.c",
+    "notes-cache.h",
+    "notes-merge.c",
+    "notes-merge.h",
+    "notes-utils.c",
+    "notes-utils.h",
+    "notes.c",
+    "notes.h",
+    "object.c",
+    "object.h",
+    "oidset.c",
+    "oidset.h",
+    "pack-bitmap-write.c",
+    "pack-bitmap.c",
+    "pack-bitmap.h",
+    "pack-check.c",
+    "pack-objects.c",
+    "pack-objects.h",
+    "pack-revindex.c",
+    "pack-revindex.h",
+    "pack-write.c",
+    "pack.h",
+    "pager.c",
+    "parse-options-cb.c",
+    "parse-options.c",
+    "parse-options.h",
+    "patch-delta.c",
+    "patch-ids.c",
+    "patch-ids.h",
+    "path.c",
+    "pathspec.c",
+    "pathspec.h",
+    "pkt-line.c",
+    "pkt-line.h",
+    "preload-index.c",
+    "pretty.c",
+    "prio-queue.c",
+    "prio-queue.h",
+    "progress.c",
+    "progress.h",
+    "prompt.c",
+    "prompt.h",
+    "quote.c",
+    "quote.h",
+    "reachable.c",
+    "reachable.h",
+    "read-cache.c",
+    "ref-filter.c",
+    "ref-filter.h",
+    "reflog-walk.c",
+    "reflog-walk.h",
+    "refs.c",
+    "refs.h",
+    "refs/files-backend.c",
+    "refs/iterator.c",
+    "refs/refs-internal.h",
+
+    # "remote-testsvn.c",
+    "remote.c",
+    "remote.h",
+    "replace_object.c",
+    "rerere.c",
+    "rerere.h",
+    "resolve-undo.c",
+    "resolve-undo.h",
+    "revision.c",
+    "revision.h",
+    "run-command.c",
+    "run-command.h",
+    "send-pack.c",
+    "send-pack.h",
+    "sequencer.c",
+    "sequencer.h",
+    "server-info.c",
+    "setup.c",
+
+    # "sh-i18n--envsubst.c",
+    "sha1-array.c",
+    "sha1-array.h",
+    "sha1-lookup.c",
+    "sha1-lookup.h",
+    "sha1_file.c",
+    "sha1_name.c",
+    "shallow.c",
+
+    # "shell.c",
+    "shortlog.h",
+
+    # "show-index.c",
+    "sideband.c",
+    "sideband.h",
+    "sigchain.c",
+    "sigchain.h",
+    "split-index.c",
+    "split-index.h",
+    "strbuf.c",
+    "strbuf.h",
+    "streaming.c",
+    "streaming.h",
+    "string-list.c",
+    "string-list.h",
+    "submodule-config.c",
+    "submodule-config.h",
+    "submodule.c",
+    "submodule.h",
+    "symlinks.c",
+    "tag.c",
+    "tag.h",
+    "tar.h",
+    "tempfile.c",
+    "tempfile.h",
+    "thread-utils.c",
+    "thread-utils.h",
+    "tmp-objdir.c",
+    "tmp-objdir.h",
+    "trace.c",
+    "trace.h",
+    "trailer.c",
+    "trailer.h",
+    "transport-helper.c",
+    "transport.c",
+    "transport.h",
+    "tree-diff.c",
+    "tree-walk.c",
+    "tree-walk.h",
+    "tree.c",
+    "tree.h",
+    "unicode_width.h",
+    "unix-socket.c",
+    "unix-socket.h",
+    "unpack-trees.c",
+    "unpack-trees.h",
+    "url.c",
+    "url.h",
+    "urlmatch.c",
+    "urlmatch.h",
+    "usage.c",
+    "userdiff.c",
+    "userdiff.h",
+    "utf8.c",
+    "utf8.h",
+    "varint.c",
+    "varint.h",
+    "vcs-svn/fast_export.c",
+    "vcs-svn/fast_export.h",
+    "vcs-svn/line_buffer.c",
+    "vcs-svn/line_buffer.h",
+    "vcs-svn/repo_tree.c",
+    "vcs-svn/repo_tree.h",
+    "vcs-svn/sliding_window.c",
+    "vcs-svn/sliding_window.h",
+    "vcs-svn/svndiff.c",
+    "vcs-svn/svndiff.h",
+    "vcs-svn/svndump.c",
+    "vcs-svn/svndump.h",
+    "version.c",
+    "version.h",
+    "versioncmp.c",
+    "walker.c",
+    "walker.h",
+    "wildmatch.c",
+    "wildmatch.h",
+    "worktree.c",
+    "worktree.h",
+    "wrapper.c",
+    "write_or_die.c",
+    "ws.c",
+    "wt-status.c",
+    "wt-status.h",
+    "xdiff-interface.c",
+    "xdiff-interface.h",
+    "xdiff/xdiff.h",
+    "xdiff/xdiffi.c",
+    "xdiff/xdiffi.h",
+    "xdiff/xemit.c",
+    "xdiff/xemit.h",
+    "xdiff/xhistogram.c",
+    "xdiff/xinclude.h",
+    "xdiff/xmacros.h",
+    "xdiff/xmerge.c",
+    "xdiff/xpatience.c",
+    "xdiff/xprepare.c",
+    "xdiff/xprepare.h",
+    "xdiff/xtypes.h",
+    "xdiff/xutils.c",
+    "xdiff/xutils.h",
+    "zlib.c",
+  ]
+  public_deps = [
+    "//third_party/boringssl:crypto",
+    "//third_party/boringssl:ssl",
+    "//third_party/curl:libcurl",
+    "//third_party/expat",
+    "//third_party/zlib",
+  ]
+  public_configs = [ ":git_config" ]
+  libs = [ "launchpad" ]
+}
+
+executable("git-bin") {
+  output_name = "git"
+  sources = [
+    "builtin.h",
+    "builtin/add.c",
+    "builtin/am.c",
+    "builtin/annotate.c",
+    "builtin/apply.c",
+    "builtin/archive.c",
+    "builtin/bisect--helper.c",
+    "builtin/blame.c",
+    "builtin/branch.c",
+    "builtin/bundle.c",
+    "builtin/cat-file.c",
+    "builtin/check-attr.c",
+    "builtin/check-ignore.c",
+    "builtin/check-mailmap.c",
+    "builtin/check-ref-format.c",
+    "builtin/checkout-index.c",
+    "builtin/checkout.c",
+    "builtin/clean.c",
+    "builtin/clone.c",
+    "builtin/column.c",
+    "builtin/commit-tree.c",
+    "builtin/commit.c",
+    "builtin/config.c",
+    "builtin/count-objects.c",
+    "builtin/credential.c",
+    "builtin/describe.c",
+    "builtin/diff-files.c",
+    "builtin/diff-index.c",
+    "builtin/diff-tree.c",
+    "builtin/diff.c",
+    "builtin/difftool.c",
+    "builtin/fast-export.c",
+    "builtin/fetch-pack.c",
+    "builtin/fetch.c",
+    "builtin/fmt-merge-msg.c",
+    "builtin/for-each-ref.c",
+    "builtin/fsck.c",
+    "builtin/gc.c",
+    "builtin/get-tar-commit-id.c",
+    "builtin/grep.c",
+    "builtin/hash-object.c",
+    "builtin/help.c",
+    "builtin/index-pack.c",
+    "builtin/init-db.c",
+    "builtin/interpret-trailers.c",
+    "builtin/log.c",
+    "builtin/ls-files.c",
+    "builtin/ls-remote.c",
+    "builtin/ls-tree.c",
+    "builtin/mailinfo.c",
+    "builtin/mailsplit.c",
+    "builtin/merge-base.c",
+    "builtin/merge-file.c",
+    "builtin/merge-index.c",
+    "builtin/merge-ours.c",
+    "builtin/merge-recursive.c",
+    "builtin/merge-tree.c",
+    "builtin/merge.c",
+    "builtin/mktag.c",
+    "builtin/mktree.c",
+    "builtin/mv.c",
+    "builtin/name-rev.c",
+    "builtin/notes.c",
+    "builtin/pack-objects.c",
+    "builtin/pack-redundant.c",
+    "builtin/pack-refs.c",
+    "builtin/patch-id.c",
+    "builtin/prune-packed.c",
+    "builtin/prune.c",
+    "builtin/pull.c",
+    "builtin/push.c",
+    "builtin/read-tree.c",
+    "builtin/rebase--helper.c",
+    "builtin/receive-pack.c",
+    "builtin/reflog.c",
+    "builtin/remote-ext.c",
+    "builtin/remote-fd.c",
+    "builtin/remote.c",
+    "builtin/repack.c",
+    "builtin/replace.c",
+    "builtin/rerere.c",
+    "builtin/reset.c",
+    "builtin/rev-list.c",
+    "builtin/rev-parse.c",
+    "builtin/revert.c",
+    "builtin/rm.c",
+    "builtin/send-pack.c",
+    "builtin/shortlog.c",
+    "builtin/show-branch.c",
+    "builtin/show-ref.c",
+    "builtin/stripspace.c",
+    "builtin/submodule--helper.c",
+    "builtin/symbolic-ref.c",
+    "builtin/tag.c",
+    "builtin/unpack-file.c",
+    "builtin/unpack-objects.c",
+    "builtin/update-index.c",
+    "builtin/update-ref.c",
+    "builtin/update-server-info.c",
+    "builtin/upload-archive.c",
+    "builtin/var.c",
+    "builtin/verify-commit.c",
+    "builtin/verify-pack.c",
+    "builtin/verify-tag.c",
+    "builtin/worktree.c",
+    "builtin/write-tree.c",
+    "git.c",
+  ]
+  deps = [
+    ":git_srcs",
+  ]
+}
+
+template("gitprogram") {
+  executable("git-" + target_name) {
+    sources = [
+      invoker.target_name + ".c"
+    ]
+    if (defined(invoker.sources)) {
+      sources += invoker.sources
+    }
+    deps = [
+      ":git_srcs"
+    ]
+  }
+}
+
+gitprogram("daemon") {}
+gitprogram("http-backend") {}
+gitprogram("http-fetch") {
+  sources = [
+    "http-walker.c",
+    "http.c",
+    "http.h",
+  ]
+}
+gitprogram("http-push") {
+  sources = [
+    "http.c",
+    "http.h",
+  ]
+}
+gitprogram("upload-pack") {}
+
+executable("git-remote-http") {
+  sources = [
+    "remote-curl.c",
+    "http.c",
+    "http-walker.c",
+  ]
+  deps = [
+    ":git_srcs",
+  ]
+}
+
+group("git") {
+  deps = [
+    ":git-bin",
+    ":git-daemon",
+    ":git-http-backend",
+    ":git-http-fetch",
+    ":git-http-push",
+    ":git-remote-http",
+    ":git-upload-pack",
+  ]
+}
+
+
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f4b87c6..04d52ec 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1158,11 +1158,15 @@
 	use(20);
 
 	/* If input_fd is a file, we should have reached its end now. */
+#ifndef __Fuchsia__ // TODO: fstat(0, ...) seems to fail, oddly
 	if (fstat(input_fd, &st))
 		die_errno(_("cannot fstat packfile"));
 	if (S_ISREG(st.st_mode) &&
 			lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
 		die(_("pack has junk at the end"));
+#else
+    (void)st;
+#endif
 
 	for (i = 0; i < nr_objects; i++) {
 		struct object_entry *obj = &objects[i];
diff --git a/common-cmds.h b/common-cmds.h
new file mode 100644
index 0000000..4cd69f0
--- /dev/null
+++ b/common-cmds.h
@@ -0,0 +1,38 @@
+/* Automatically generated by ./generate-cmdlist.sh */
+struct cmdname_help {
+	char name[16];
+	char help[80];
+	unsigned char group;
+};
+
+static const char *common_cmd_groups[] = {
+	N_("start a working area (see also: git help tutorial)"),
+	N_("work on the current change (see also: git help everyday)"),
+	N_("examine the history and state (see also: git help revisions)"),
+	N_("grow, mark and tweak your common history"),
+	N_("collaborate (see also: git help workflows)"),
+};
+
+static struct cmdname_help common_cmds[] = {
+	{"add", N_("Add file contents to the index"), 1},
+	{"bisect", N_("Use binary search to find the commit that introduced a bug"), 2},
+	{"branch", N_("List, create, or delete branches"), 3},
+	{"checkout", N_("Switch branches or restore working tree files"), 3},
+	{"clone", N_("Clone a repository into a new directory"), 0},
+	{"commit", N_("Record changes to the repository"), 3},
+	{"diff", N_("Show changes between commits, commit and working tree, etc"), 3},
+	{"fetch", N_("Download objects and refs from another repository"), 4},
+	{"grep", N_("Print lines matching a pattern"), 2},
+	{"init", N_("Create an empty Git repository or reinitialize an existing one"), 0},
+	{"log", N_("Show commit logs"), 2},
+	{"merge", N_("Join two or more development histories together"), 3},
+	{"mv", N_("Move or rename a file, a directory, or a symlink"), 1},
+	{"pull", N_("Fetch from and integrate with another repository or a local branch"), 4},
+	{"push", N_("Update remote refs along with associated objects"), 4},
+	{"rebase", N_("Reapply commits on top of another base tip"), 3},
+	{"reset", N_("Reset current HEAD to the specified state"), 1},
+	{"rm", N_("Remove files from the working tree and from the index"), 1},
+	{"show", N_("Show various types of objects"), 2},
+	{"status", N_("Show the working tree status"), 2},
+	{"tag", N_("Create, list, delete or verify a tag object signed with GPG"), 3},
+};
diff --git a/compat/poll/poll.c b/compat/poll/poll.c
index b10adc7..b284407 100644
--- a/compat/poll/poll.c
+++ b/compat/poll/poll.c
@@ -279,7 +279,7 @@
       int r;
       int socket_errno;
 
-# if defined __MACH__ && defined __APPLE__
+# if defined __MACH__ && defined __APPLE__ || defined(__Fuchsia_)
       /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
 	 for some kinds of descriptors.  Detect if this descriptor is a
 	 connected socket, a server socket, or something else using a
diff --git a/exec_cmd.c b/exec_cmd.c
index fb94aeb..e48d3e4 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -106,7 +106,7 @@
 
 const char **prepare_git_cmd(struct argv_array *out, const char **argv)
 {
-	argv_array_push(out, "git");
+	argv_array_push(out, "/system/bin/git");
 	argv_array_pushv(out, argv);
 	return out->argv;
 }
diff --git a/run-command.c b/run-command.c
index 5227f78..a37450c 100644
--- a/run-command.c
+++ b/run-command.c
@@ -6,6 +6,10 @@
 #include "thread-utils.h"
 #include "strbuf.h"
 
+#ifdef __Fuchsia__
+#include <magenta/syscalls.h>
+#endif
+
 void child_process_init(struct child_process *child)
 {
 	memset(child, 0, sizeof(*child));
@@ -20,13 +24,39 @@
 }
 
 struct child_to_clean {
-	pid_t pid;
+	proc_t pid;
 	struct child_process *process;
 	struct child_to_clean *next;
 };
 static struct child_to_clean *children_to_clean;
 static int installed_child_cleanup_handler;
 
+static proc_t waitproc(proc_t proc, int* status, int options)
+{
+#if defined(__Fuchsia__)
+	mx_status_t st = mx_object_wait_one(proc,
+		MX_PROCESS_TERMINATED,
+		MX_TIME_INFINITE,
+		NULL);
+	if (st != NO_ERROR) {
+		fprintf(stderr, "Could not wait on proc: %d\n", st);
+		return -1;
+	}
+	mx_info_process_t proc_info;
+	st = mx_object_get_info(proc, MX_INFO_PROCESS,
+			&proc_info, sizeof(proc_info),
+			NULL, NULL);
+	if (st != NO_ERROR) {
+		fprintf(stderr, "Could not get info for proc: %d\n", st);
+		return -1;
+	}
+	*status = proc_info.return_code;
+	return 0;
+#else
+	return waitpid(proc, status, options);
+#endif
+}
+
 static void cleanup_children(int sig, int in_signal)
 {
 	struct child_to_clean *children_to_wait_for = NULL;
@@ -61,7 +91,7 @@
 		struct child_to_clean *p = children_to_wait_for;
 		children_to_wait_for = p->next;
 
-		while (waitpid(p->pid, NULL, 0) < 0 && errno == EINTR)
+		while (waitproc(p->pid, NULL, 0) < 0 && errno == EINTR)
 			; /* spin waiting for process exit or error */
 
 		if (!in_signal)
@@ -81,7 +111,7 @@
 	cleanup_children(SIGTERM, 0);
 }
 
-static void mark_child_for_cleanup(pid_t pid, struct child_process *process)
+static void mark_child_for_cleanup(proc_t pid, struct child_process *process)
 {
 	struct child_to_clean *p = xmalloc(sizeof(*p));
 	p->pid = pid;
@@ -96,7 +126,7 @@
 	}
 }
 
-static void clear_child_for_cleanup(pid_t pid)
+static void clear_child_for_cleanup(proc_t pid)
 {
 	struct child_to_clean **pp;
 
@@ -117,7 +147,7 @@
 	close(fd[1]);
 }
 
-#ifndef GIT_WINDOWS_NATIVE
+#if !defined(GIT_WINDOWS_NATIVE) && !defined(__Fuchsia__)
 static inline void dup_devnull(int to)
 {
 	int fd = open("/dev/null", O_RDWR);
@@ -220,7 +250,7 @@
 	return out->argv;
 }
 
-#ifndef GIT_WINDOWS_NATIVE
+#if !defined(GIT_WINDOWS_NATIVE) && !defined(__Fuchsia__)
 static int execv_shell_cmd(const char **argv)
 {
 	struct argv_array nargv = ARGV_ARRAY_INIT;
@@ -232,7 +262,7 @@
 }
 #endif
 
-#ifndef GIT_WINDOWS_NATIVE
+#if !defined(GIT_WINDOWS_NATIVE) && !defined(__Fuchsia__)
 static int child_notifier = -1;
 
 static void notify_parent(void)
@@ -253,13 +283,15 @@
 		fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 }
 
-static int wait_or_whine(pid_t pid, const char *argv0, int in_signal)
+static int wait_or_whine(proc_t pid, const char *argv0, int in_signal)
 {
 	int status, code = -1;
-	pid_t waiting;
+	proc_t waiting;
 	int failed_errno = 0;
 
-	while ((waiting = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
+	argv0 = "unknown"; // TODO: why is argv0 bogus?
+
+	while ((waiting = waitproc(pid, &status, 0)) < 0 && errno == EINTR)
 		;	/* nothing */
 	if (in_signal)
 		return 0;
@@ -267,8 +299,10 @@
 	if (waiting < 0) {
 		failed_errno = errno;
 		error_errno("waitpid for %s failed", argv0);
+#ifndef __Fuchsia__
 	} else if (waiting != pid) {
 		error("waitpid is confused (%s)", argv0);
+#endif
 	} else if (WIFSIGNALED(status)) {
 		code = WTERMSIG(status);
 		if (code != SIGINT && code != SIGQUIT && code != SIGPIPE)
@@ -369,7 +403,7 @@
 	trace_argv_printf(cmd->argv, "trace: run_command:");
 	fflush(NULL);
 
-#ifndef GIT_WINDOWS_NATIVE
+#if !defined(GIT_WINDOWS_NATIVE) && !defined(__Fuchsia__)
 {
 	int notify_pipe[2];
 	if (pipe(notify_pipe))
@@ -426,9 +460,12 @@
 			close(cmd->out);
 		}
 
+		char buf[4096];
+		getcwd(buf, sizeof(buf));
+
 		if (cmd->dir && chdir(cmd->dir))
 			die_errno("exec '%s': cd to '%s' failed", cmd->argv[0],
-			    cmd->dir);
+				cmd->dir);
 		if (cmd->env) {
 			for (; *cmd->env; cmd->env++) {
 				if (strchr(*cmd->env, '='))
@@ -476,6 +513,111 @@
 	}
 	close(notify_pipe[0]);
 }
+#elif defined(__Fuchsia__)
+{
+	int fherr = 2;
+
+	struct argv_array nargv = ARGV_ARRAY_INIT;
+	if (cmd->git_cmd)
+		prepare_git_cmd(&nargv, cmd->argv);
+	else if (cmd->use_shell)
+		prepare_shell_cmd(&nargv, cmd->argv);
+	else
+		argv_array_pushv(&nargv, cmd->argv);
+
+	launchpad_t* lp;
+	launchpad_create(0, nargv.argv[0], &lp);
+
+	char* path = system_path(nargv.argv[0]);
+	launchpad_load_from_file(lp, path);
+	free(path);
+	launchpad_set_args(lp, nargv.argc, nargv.argv);
+	argv_array_clear(&nargv);
+
+	char cwd_buf[4096];
+	getcwd(cwd_buf, sizeof(cwd_buf));
+	if (cmd->dir) {
+		chdir(cmd->dir);
+	}
+	launchpad_clone(lp, LP_CLONE_MXIO_CWD);
+	if (cmd->dir) {
+		chdir(cwd_buf);
+	}
+
+	// HACK - set the PWD environment variable for the child as that's the only way currently to
+	// make getcwd() work as expected in the child process.
+	argv_array_pushf(&(cmd->env_array), "PWD=%s", cwd_buf);
+	cmd->env = cmd->env_array.argv;
+	launchpad_set_environ(lp, cmd->env);
+
+	launchpad_clone(lp, LP_CLONE_MXIO_ROOT);
+	launchpad_clone(lp, LP_CLONE_DEFAULT_JOB);
+
+	if (cmd->no_stdin)
+		; //fhin = open("/dev/null", O_RDWR);
+	else if (need_in)
+		launchpad_clone_fd(lp, fdin[0], 0);
+		//fhin = dup(fdin[0]);
+	else if (cmd->in)
+		launchpad_clone_fd(lp, cmd->in, 0);
+		// fhin = dup(cmd->in);
+
+	if (cmd->no_stderr)
+		fherr = open("/dev/null", O_RDWR);
+	else if (need_err)
+		launchpad_clone_fd(lp, fderr[1], 2);
+		//fherr = dup(fderr[1]);
+	else if (cmd->err > 2)
+		launchpad_clone_fd(lp, cmd->err, 2);
+		//fherr = dup(cmd->err);
+	else  // so we can see stuff
+		launchpad_clone_fd(lp, 2, 2);
+
+	if (cmd->no_stdout)
+		; //fhout = open("/dev/null", O_RDWR);
+	else if (cmd->stdout_to_stderr)
+		launchpad_clone_fd(lp, fherr, 1);
+		//fhout = dup(fherr);
+	else if (need_out)
+		launchpad_clone_fd(lp, fdout[1], 1);
+		//fhout = dup(fdout[1]);
+	else if (cmd->out > 1)
+		launchpad_clone_fd(lp, cmd->out, 1);
+		//fhout = dup(cmd->out);
+
+	mx_handle_t proc;
+	const char* errmsg;
+	mx_status_t status = launchpad_go(lp, &proc, &errmsg);
+	if (status < 0) {
+		fprintf(stderr, "failed to create child: %s: %d\n", errmsg, status);
+		failed_errno = EINVAL;
+	}
+	cmd->pid = proc;
+	if (cmd->clean_on_exit && cmd->pid != MX_HANDLE_INVALID)
+		mark_child_for_cleanup(cmd->pid, cmd);
+
+
+/*
+	cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
+			cmd->dir, fhin, fhout, fherr);
+	failed_errno = errno;
+	if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
+		error_errno("cannot spawn %s", cmd->argv[0]);
+	if (cmd->clean_on_exit && cmd->pid >= 0)
+		mark_child_for_cleanup(cmd->pid, cmd);
+		*/
+
+	argv_array_clear(&nargv);
+	/*
+	cmd->argv = sargv;
+	if (fhin != 0)
+		close(fhin);
+	if (fhout != 1)
+		close(fhout);
+		*/
+	if (fherr != 2)
+		close(fherr);
+}
 #else
 {
 	int fhin = 0, fhout = 1, fherr = 2;
diff --git a/run-command.h b/run-command.h
index 4fa8f65..e7ef3c8 100644
--- a/run-command.h
+++ b/run-command.h
@@ -5,13 +5,23 @@
 #include <pthread.h>
 #endif
 
+#if defined(__Fuchsia__)
+#include <launchpad/launchpad.h>
+#endif
+
 #include "argv-array.h"
 
+#if defined(__Fuchsia__)
+#define proc_t mx_handle_t
+#else
+#define proc_t pid_t
+#endif
+
 struct child_process {
 	const char **argv;
 	struct argv_array args;
 	struct argv_array env_array;
-	pid_t pid;
+	proc_t pid;
 	/*
 	 * Using .in, .out, .err:
 	 * - Specify 0 for no redirections (child inherits stdin, stdout,
diff --git a/sideband.c b/sideband.c
index 1e4d684..7d76834 100644
--- a/sideband.c
+++ b/sideband.c
@@ -13,6 +13,9 @@
  * the remote died unexpectedly.  A flush() concludes the stream.
  */
 
+#ifdef PREFIX
+#undef PREFIX
+#endif
 #define PREFIX "remote: "
 
 #define ANSI_SUFFIX "\033[K"