Add uname(1), from Thayne Harbaugh

diff --git a/utils/Makefile b/utils/Makefile
index 1404a58..dec78f0 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -7,7 +7,7 @@
 LIBS         = $(KLIBC) $(LIBGCC)
 PROGS       := chroot dd fstype mkdir mkfifo mount pivot_root umount \
 		true false sleep ln nuke minips run-init printf cat \
-		insmod
+		insmod uname
 STATICPROGS := $(patsubst %,static/%,$(PROGS))
 SHAREDPROGS := $(patsubst %,shared/%,$(PROGS))
 LIBOBJS	     = file_mode.o
diff --git a/utils/uname.c b/utils/uname.c
new file mode 100644
index 0000000..acc1362
--- /dev/null
+++ b/utils/uname.c
@@ -0,0 +1,165 @@
+/*
+ * uname.c, by tlh
+ *
+ * The uname program for system information: kernel name, kernel
+ * release, kernel release, machine, processor, platform, os and
+ * hostname.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+
+enum uname_fields {
+	UN_SYSNAME,
+	UN_NODENAME,
+	UN_RELEASE,
+	UN_VERSION,
+	UN_MACHINE,
+#if NOT_IMPLEMENTED_PROCESSOR
+	UN_PROCESSOR,
+#endif
+	UN_HARDWARE,
+#if NOT_IMPLEMENTED_OS
+	UN_OS,
+#endif
+	UN_NR_FIELDS
+};
+
+
+void usage(FILE *stream, const char *progname)
+{
+	fprintf(stream,
+		"Usage: %s [OPTION] . . .\n"
+		"Print system information,  No options defaults to -s.\n"
+		"\n"
+		"  -a   print all the information in the same order as follows below\n"
+		"  -s   kernel name\n"
+		"  -n   network node name (hostname)\n"
+		"  -r   kernel release\n"
+		"  -v   kernel version\n"
+		"  -m   machine hardware name\n"
+#if NOT_IMPLEMENTED_PROCESSOR
+		"  -p   processor type\n"
+#endif
+		"  -i   hardware platform\n"
+#if NOT_IMPLEMENTED_OS
+		"  -o   operating system\n"
+#endif
+		"\n"
+		"  -h   help/usage\n"
+		"\n",
+		progname);
+}
+
+
+char *make_hardware(const char *machine)
+{
+	char *hardware;
+
+	if (! (hardware = strdup(machine))) {
+		fprintf(stderr, "strdup() failed: %s\n",
+			strerror(errno));
+		goto end;
+	}
+	if (strlen(hardware) == 4
+	    && hardware[0] == 'i'
+	    && hardware[2] == '8'
+	    && hardware[3] == '6') {
+		hardware[1] = '3';
+	}
+ end:
+	return hardware;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int ec = 1;
+	int opt;
+	int i;
+	int nr_pr;
+	struct utsname buf;
+	char *uname_fields[UN_NR_FIELDS] = { NULL };
+
+	if (-1 == uname(&buf)) {
+		fprintf(stderr, "uname() failure: %s\n", strerror(errno));
+		goto end;
+	}
+
+	if (1 == argc)
+		/* no options given - default to -s */
+		uname_fields[UN_SYSNAME] = buf.sysname;
+
+	while ((opt = getopt(argc, argv, "asnrvmpioh")) != -1) {
+		switch (opt) {
+		case 'a':
+			uname_fields[UN_SYSNAME] = buf.sysname;
+			uname_fields[UN_NODENAME] = buf.nodename;
+			uname_fields[UN_RELEASE] = buf.release;
+			uname_fields[UN_VERSION] = buf.version;
+			uname_fields[UN_MACHINE] = buf.machine;
+			uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+			if (! uname_fields[UN_HARDWARE])
+				goto end;
+			break;
+		case 's':
+			uname_fields[UN_SYSNAME] = buf.sysname;
+			break;
+		case 'n':
+			uname_fields[UN_NODENAME] = buf.nodename;
+			break;
+		case 'r':
+			uname_fields[UN_RELEASE] = buf.release;
+			break;
+		case 'v':
+			uname_fields[UN_VERSION] = buf.version;
+			break;
+		case 'm':
+			uname_fields[UN_MACHINE] = buf.machine;
+			break;
+#if NOT_IMPLEMENTED_PROCESSOR
+		case 'p':
+			break;
+#endif
+		case 'i':
+			uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+			if (! uname_fields[UN_HARDWARE])
+				goto end;
+			break;
+#if NOT_IMPLEMENTED_OS
+		case 'o':
+			break;
+#endif
+		case 'h':
+			usage(stdout, argv[0]);
+			ec = 0;
+			goto end;
+			break;
+		default:
+			usage(stderr, argv[0]);
+			goto end;
+			break;
+		}
+	}
+
+	for (nr_pr = 0, i = UN_SYSNAME; i < UN_NR_FIELDS; i++) {
+		if (! uname_fields[i])
+			continue;
+		if (nr_pr)
+			fputc(' ', stdout);
+		fputs(uname_fields[i], stdout);
+		nr_pr++;
+	}
+	fputc('\n', stdout);
+
+	ec = 0;
+
+ end:
+	if (uname_fields[UN_HARDWARE])
+		free(uname_fields[UN_HARDWARE]);
+	return ec;
+}