]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/nash/nash.c
git-svn-id: http://svn.ipfire.org/svn/ipfire/IPFire/source@16 ea5c0bd1-69bd-2848...
[people/pmueller/ipfire-2.x.git] / src / nash / nash.c
diff --git a/src/nash/nash.c b/src/nash/nash.c
new file mode 100644 (file)
index 0000000..cfde50c
--- /dev/null
@@ -0,0 +1,1230 @@
+/*\r
+ * nash.c\r
+ * \r
+ * Simple code to load modules, mount root, and get things going. Uses\r
+ * dietlibc to keep things small.\r
+ *\r
+ * Erik Troan (ewt@redhat.com)\r
+ *\r
+ * Copyright 2002 Red Hat Software \r
+ *\r
+ * This software may be freely redistributed under the terms of the GNU\r
+ * public license.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ *\r
+ */\r
+\r
+/* We internalize losetup, mount, raidautorun, and echo commands. Other\r
+   commands are run from the filesystem. Comments and blank lines work as \r
+   well, argument parsing is screwy. */\r
+\r
+#include <ctype.h>\r
+#include <dirent.h>\r
+#include <errno.h>\r
+#include <fcntl.h>\r
+#include <net/if.h>\r
+#include <signal.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <sys/ioctl.h>\r
+#include <sys/mount.h>\r
+#include <sys/socket.h>\r
+#include <sys/stat.h>\r
+#include <sys/time.h>\r
+#include <sys/types.h>\r
+#include <sys/un.h>\r
+#include <sys/wait.h>\r
+#include <unistd.h>\r
+#include <sys/ioctl.h>\r
+#include <sys/reboot.h>\r
+#include <termios.h>\r
+\r
+#include <asm/unistd.h>\r
+\r
+#include "mount_by_label.h"\r
+\r
+/* Need to tell loop.h what the actual dev_t type is. */\r
+#undef dev_t\r
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))\r
+#define dev_t unsigned int\r
+#else\r
+#define dev_t unsigned short\r
+#endif\r
+#include <linux/loop.h>\r
+#undef dev_t\r
+#define dev_t dev_t\r
+\r
+#define syslog klogctl\r
+\r
+#include <linux/cdrom.h>\r
+#define MD_MAJOR 9\r
+#include <linux/raid/md_u.h>\r
+\r
+#ifndef RAID_AUTORUN\r
+#define RAID_AUTORUN           _IO (MD_MAJOR, 0x14)\r
+#endif\r
+\r
+#ifndef MS_REMOUNT\r
+#define MS_REMOUNT      32\r
+#endif\r
+\r
+#ifdef USE_DIET\r
+static inline _syscall2(int,pivot_root,const char *,one,const char *,two)\r
+#endif\r
+\r
+#define MAX(a, b) ((a) > (b) ? a : b)\r
+\r
+int testing = 0, quiet = 0;\r
+\r
+#define PATH "/usr/bin:/bin:/sbin:/usr/sbin"\r
+\r
+char * env[] = {\r
+    "PATH=" PATH,\r
+    NULL\r
+};\r
+\r
+int smartmknod(char * device, mode_t mode, dev_t dev) {\r
+    char buf[256];\r
+    char * end;\r
+\r
+    strcpy(buf, device);\r
+\r
+    end = buf;\r
+    while (*end) {\r
+       if (*end == '/') {\r
+           *end = '\0';\r
+           if (access(buf, F_OK) && errno == ENOENT) \r
+               mkdir(buf, 0700);\r
+           *end = '/';\r
+       }\r
+\r
+       end++;\r
+    }\r
+\r
+    return mknod(device, mode, dev);\r
+}\r
+\r
+char * getArg(char * cmd, char * end, char ** arg) {\r
+    char quote = '\0';\r
+\r
+    if (cmd >= end) return NULL;\r
+\r
+    while (isspace(*cmd) && cmd < end) cmd++;\r
+    if (cmd >= end) return NULL;\r
+\r
+    if (*cmd == '"')\r
+       cmd++, quote = '"';\r
+    else if (*cmd == '\'')\r
+       cmd++, quote = '\'';\r
+\r
+    if (quote) {\r
+       *arg = cmd;\r
+\r
+       /* This doesn't support \ escapes */\r
+       while (cmd < end && *cmd != quote) cmd++;\r
+\r
+       if (cmd == end) {\r
+           printf("error: quote mismatch for %s\n", *arg);\r
+           return NULL;\r
+       }\r
+\r
+       *cmd = '\0';\r
+       cmd++;\r
+    } else {\r
+       *arg = cmd;\r
+       while (!isspace(*cmd) && cmd < end) cmd++;\r
+       *cmd = '\0';\r
+    }\r
+\r
+    cmd++;\r
+\r
+    while (isspace(*cmd)) cmd++;\r
+\r
+    return cmd;\r
+}\r
+\r
+int mountCommand(char * cmd, char * end) {\r
+    char * fsType = NULL;\r
+    char * device;\r
+    char * mntPoint;\r
+    char * deviceDir;\r
+    char * options = NULL;\r
+    int mustRemove = 0;\r
+    int mustRemoveDir = 0;\r
+    int rc;\r
+    int flags = MS_MGC_VAL;\r
+    char * newOpts;\r
+\r
+    cmd = getArg(cmd, end, &device);\r
+    if (!cmd) {\r
+       printf("usage: mount [--ro] [-o <opts>] -t <type> <device> <mntpoint>\n");\r
+       return 1;\r
+    }\r
+\r
+    while (cmd && *device == '-') {\r
+       if (!strcmp(device, "--ro")) {\r
+           flags |= MS_RDONLY;\r
+       } else if (!strcmp(device, "-o")) {\r
+           cmd = getArg(cmd, end, &options);\r
+           if (!cmd) {\r
+               printf("mount: -o requires arguments\n");\r
+               return 1;\r
+           }\r
+       } else if (!strcmp(device, "-t")) {\r
+           if (!(cmd = getArg(cmd, end, &fsType))) {\r
+               printf("mount: missing filesystem type\n");\r
+               return 1;\r
+           }\r
+       }\r
+\r
+       cmd = getArg(cmd, end, &device);\r
+    }\r
+\r
+    if (!cmd) {\r
+       printf("mount: missing device\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!(cmd = getArg(cmd, end, &mntPoint))) {\r
+       printf("mount: missing mount point\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!fsType) {\r
+       printf("mount: filesystem type expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("mount: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    /* need to deal with options */ \r
+    if (options) {\r
+       char * end;\r
+       char * start = options;\r
+\r
+       newOpts = alloca(strlen(options) + 1);\r
+       *newOpts = '\0';\r
+\r
+       while (*start) {\r
+           end = strchr(start, ',');\r
+           if (!end) {\r
+               end = start + strlen(start);\r
+           } else {\r
+               *end = '\0';\r
+               end++;\r
+           }\r
+\r
+           if (!strcmp(start, "ro"))\r
+               flags |= MS_RDONLY;\r
+           else if (!strcmp(start, "rw"))\r
+               flags &= ~MS_RDONLY;\r
+           else if (!strcmp(start, "nosuid"))\r
+               flags |= MS_NOSUID;\r
+           else if (!strcmp(start, "suid"))\r
+               flags &= ~MS_NOSUID;\r
+           else if (!strcmp(start, "nodev"))\r
+               flags |= MS_NODEV;\r
+           else if (!strcmp(start, "dev"))\r
+               flags &= ~MS_NODEV;\r
+           else if (!strcmp(start, "noexec"))\r
+               flags |= MS_NOEXEC;\r
+           else if (!strcmp(start, "exec"))\r
+               flags &= ~MS_NOEXEC;\r
+           else if (!strcmp(start, "sync"))\r
+               flags |= MS_SYNCHRONOUS;\r
+           else if (!strcmp(start, "async"))\r
+               flags &= ~MS_SYNCHRONOUS;\r
+           else if (!strcmp(start, "nodiratime"))\r
+               flags |= MS_NODIRATIME;\r
+           else if (!strcmp(start, "diratime"))\r
+               flags &= ~MS_NODIRATIME;\r
+           else if (!strcmp(start, "noatime"))\r
+               flags |= MS_NOATIME;\r
+           else if (!strcmp(start, "atime"))\r
+               flags &= ~MS_NOATIME;\r
+           else if (!strcmp(start, "remount"))\r
+               flags |= MS_REMOUNT;\r
+           else if (!strcmp(start, "defaults"))\r
+               ;\r
+           else {\r
+               if (*newOpts)\r
+                   strcat(newOpts, ",");\r
+               strcat(newOpts, start);\r
+           }\r
+\r
+           start = end;\r
+       }\r
+\r
+       options = newOpts;\r
+    }\r
+\r
+    if (!strncmp("LABEL=", device, 6)) {\r
+       int major, minor;\r
+       char * devName;\r
+       char * ptr;\r
+       int i;\r
+\r
+       devName = get_spec_by_volume_label(device + 6, &major, &minor);\r
+\r
+       if (devName) {\r
+           device = devName;\r
+           if (access(device, F_OK)) {\r
+               ptr = device;\r
+               i = 0;\r
+               while (*ptr)\r
+                   if (*ptr++ == '/')\r
+                       i++;\r
+               if (i > 2) {\r
+                   deviceDir = alloca(strlen(device) + 1);\r
+                   strcpy(deviceDir, device);\r
+                   ptr = deviceDir + (strlen(device) - 1);\r
+                   while (*ptr != '/')\r
+                       *ptr-- = '\0';\r
+                   if (mkdir(deviceDir, 0644)) {\r
+                     printf("mkdir: cannot create directory %s\n", deviceDir);\r
+                   } else {\r
+                     mustRemoveDir = 1;\r
+                   }\r
+               }\r
+               if (smartmknod(device, S_IFBLK | 0600, makedev(major, minor))) {\r
+                   printf("mount: cannot create device %s (%d,%d)\n",\r
+                          device, major, minor);\r
+                   return 1;\r
+               }\r
+               mustRemove = 1;\r
+           }\r
+       }\r
+    }\r
+\r
+    if (testing) {\r
+       printf("mount %s%s%s-t '%s' '%s' '%s' (%s%s%s%s%s%s%s)\n", \r
+               options ? "-o '" : "",  \r
+               options ? options : "", \r
+               options ? "\' " : "",   \r
+               fsType, device, mntPoint,\r
+               (flags & MS_RDONLY) ? "ro " : "",\r
+               (flags & MS_NOSUID) ? "nosuid " : "",\r
+               (flags & MS_NODEV) ? "nodev " : "",\r
+               (flags & MS_NOEXEC) ? "noexec " : "",\r
+               (flags & MS_SYNCHRONOUS) ? "sync " : "",\r
+               (flags & MS_REMOUNT) ? "remount " : "",\r
+               (flags & MS_NOATIME) ? "noatime " : ""\r
+           );\r
+    } else {\r
+       if (mount(device, mntPoint, fsType, flags, options)) {\r
+           printf("mount: error %d mounting %s\n", errno, fsType);\r
+           rc = 1;\r
+       }\r
+    }\r
+\r
+    if (mustRemove) unlink(device);\r
+    if (mustRemoveDir) rmdir(deviceDir);\r
+\r
+    return rc;\r
+}\r
+\r
+int otherCommand(char * bin, char * cmd, char * end, int doFork) {\r
+    char * args[128];\r
+    char ** nextArg;\r
+    int pid;\r
+    int status;\r
+    char fullPath[255];\r
+    const static char * sysPath = PATH;\r
+    const char * pathStart;\r
+    const char * pathEnd;\r
+    char * stdoutFile = NULL;\r
+    int stdoutFd = 0;\r
+\r
+    nextArg = args;\r
+\r
+    if (!strchr(bin, '/')) {\r
+       pathStart = sysPath;\r
+       while (*pathStart) {\r
+           pathEnd = strchr(pathStart, ':');\r
+\r
+           if (!pathEnd) pathEnd = pathStart + strlen(pathStart);\r
+\r
+           strncpy(fullPath, pathStart, pathEnd - pathStart);\r
+           fullPath[pathEnd - pathStart] = '/';\r
+           strcpy(fullPath + (pathEnd - pathStart + 1), bin); \r
+\r
+           pathStart = pathEnd;\r
+           if (*pathStart) pathStart++;\r
+\r
+           if (!access(fullPath, X_OK)) {\r
+               bin = fullPath;\r
+               break;\r
+           }\r
+       }\r
+    }\r
+\r
+    *nextArg = bin;\r
+\r
+    while (cmd && cmd < end) {\r
+       nextArg++;\r
+       cmd = getArg(cmd, end, nextArg);\r
+    }\r
+       \r
+    if (cmd) nextArg++;\r
+    *nextArg = NULL;\r
+\r
+    /* if the next-to-last arg is a >, redirect the output properly */\r
+    if (((nextArg - args) >= 2) && !strcmp(*(nextArg - 2), ">")) {\r
+       stdoutFile = *(nextArg - 1);\r
+       *(nextArg - 2) = NULL;\r
+\r
+       stdoutFd = open(stdoutFile, O_CREAT | O_RDWR | O_TRUNC, 0600);\r
+       if (stdoutFd < 0) {\r
+           printf("nash: failed to open %s: %d\n", stdoutFile, errno);\r
+           return 1;\r
+       }\r
+    }\r
+\r
+    if (testing) {\r
+       printf("%s ", bin);\r
+       nextArg = args + 1;\r
+       while (*nextArg)\r
+           printf(" '%s'", *nextArg++);\r
+       if (stdoutFile)\r
+           printf(" (> %s)", stdoutFile);\r
+       printf("\n");\r
+    } else {\r
+       if (!doFork || !(pid = fork())) {\r
+           /* child */\r
+           dup2(stdoutFd, 1);\r
+           execve(args[0], args, env);\r
+           printf("ERROR: failed in exec of %s\n", args[0]);\r
+           return 1;\r
+       }\r
+\r
+       close(stdoutFd);\r
+\r
+       wait4(-1, &status, 0, NULL);\r
+       if (!WIFEXITED(status) || WEXITSTATUS(status)) {\r
+           printf("ERROR: %s exited abnormally!\n", args[0]);\r
+           return 1;\r
+       }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int execCommand(char * cmd, char * end) {\r
+    char * bin;\r
+\r
+    if (!(cmd = getArg(cmd, end, &bin))) {\r
+       printf("exec: argument expected\n");\r
+       return 1;\r
+    }\r
+\r
+    return otherCommand(bin, cmd, end, 0);\r
+}\r
+\r
+int losetupCommand(char * cmd, char * end) {\r
+    char * device;\r
+    char * file;\r
+    int fd;\r
+    struct loop_info loopInfo;\r
+    int dev;\r
+\r
+    if (!(cmd = getArg(cmd, end, &device))) {\r
+       printf("losetup: missing device\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!(cmd = getArg(cmd, end, &file))) {\r
+       printf("losetup: missing file\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("losetup: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    if (testing) {\r
+       printf("losetup '%s' '%s'\n", device, file);\r
+    } else {\r
+       dev = open(device, O_RDWR, 0);\r
+       if (dev < 0) {\r
+           printf("losetup: failed to open %s: %d\n", device, errno);\r
+           return 1;\r
+       }\r
+\r
+       fd = open(file, O_RDWR, 0);\r
+       if (fd < 0) {\r
+           printf("losetup: failed to open %s: %d\n", file, errno);\r
+           close(dev);\r
+           return 1;\r
+       }\r
+\r
+       if (ioctl(dev, LOOP_SET_FD, (long) fd)) {\r
+           printf("losetup: LOOP_SET_FD failed: %d\n", errno);\r
+           close(dev);\r
+           close(fd);\r
+           return 1;\r
+       }\r
+\r
+       close(fd);\r
+\r
+       memset(&loopInfo, 0, sizeof(loopInfo));\r
+       strcpy(loopInfo.lo_name, file);\r
+\r
+       if (ioctl(dev, LOOP_SET_STATUS, &loopInfo)) \r
+           printf("losetup: LOOP_SET_STATUS failed: %d\n", errno);\r
+\r
+       close(dev);\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int raidautorunCommand(char * cmd, char * end) {\r
+    char * device;\r
+    int fd;\r
+\r
+    if (!(cmd = getArg(cmd, end, &device))) {\r
+       printf("raidautorun: raid device expected as first argument\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("raidautorun: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    fd = open(device, O_RDWR, 0);\r
+    if (fd < 0) {\r
+       printf("raidautorun: failed to open %s: %d\n", device, errno);\r
+       return 1;\r
+    }\r
+\r
+    if (ioctl(fd, RAID_AUTORUN, 0)) {\r
+       printf("raidautorun: RAID_AUTORUN failed: %d\n", errno);\r
+       close(fd);\r
+       return 1;\r
+    }\r
+\r
+    close(fd);\r
+    return 0;\r
+}\r
+\r
+static int my_pivot_root(char * one, char * two) {\r
+#ifdef USE_DIET\r
+    return pivot_root(one, two);\r
+#else\r
+    return syscall(__NR_pivot_root, one, two);\r
+#endif\r
+}\r
+\r
+int pivotrootCommand(char * cmd, char * end) {\r
+    char * new;\r
+    char * old;\r
+\r
+    if (!(cmd = getArg(cmd, end, &new))) {\r
+       printf("pivotroot: new root mount point expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!(cmd = getArg(cmd, end, &old))) {\r
+       printf("pivotroot: old root mount point expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("pivotroot: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    if (my_pivot_root(new, old)) {\r
+       printf("pivotroot: pivot_root(%s,%s) failed: %d\n", new, old, errno);\r
+       return 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int echoCommand(char * cmd, char * end) {\r
+    char * args[256];\r
+    char ** nextArg = args;\r
+    int outFd = 1;\r
+    int num = 0;\r
+    int i;\r
+\r
+    if (testing && !quiet) {\r
+       printf("(echo) ");\r
+       fflush(stdout);\r
+    }\r
+\r
+    while ((cmd = getArg(cmd, end, nextArg)))\r
+       nextArg++, num++;\r
+\r
+    if ((nextArg - args >= 2) && !strcmp(*(nextArg - 2), ">")) {\r
+       outFd = open(*(nextArg - 1), O_RDWR | O_CREAT | O_TRUNC, 0644);\r
+       if (outFd < 0) {\r
+           printf("echo: cannot open %s for write: %d\n", \r
+                   *(nextArg - 1), errno);\r
+           return 1;\r
+       }\r
+\r
+       num -= 2;\r
+    }\r
+\r
+    for (i = 0; i < num;i ++) {\r
+       if (i)\r
+           write(outFd, " ", 1);\r
+       write(outFd, args[i], strlen(args[i]));\r
+    }\r
+\r
+    write(outFd, "\n", 1);\r
+\r
+    if (outFd != 1) close(outFd);\r
+\r
+    return 0;\r
+}\r
+\r
+int umountCommand(char * cmd, char * end) {\r
+    char * path;\r
+\r
+    if (!(cmd = getArg(cmd, end, &path))) {\r
+       printf("umount: path expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("umount: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    if (umount(path)) {\r
+       printf("umount %s failed: %d\n", path, errno);\r
+       return 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int mkrootdevCommand(char * cmd, char * end) {\r
+    char * path;\r
+    char * start, * chptr;\r
+    unsigned int devNum = 0;\r
+    int fd;\r
+    int i;\r
+    char buf[1024];\r
+    int major, minor;\r
+\r
+    if (!(cmd = getArg(cmd, end, &path))) {\r
+       printf("mkrootdev: path expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("mkrootdev: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    fd = open("/proc/cmdline", O_RDONLY, 0);\r
+    if (fd < 0) {\r
+       printf("mkrootdev: failed to open /proc/cmdline: %d\n", errno);\r
+       return 1;\r
+    }\r
+\r
+    i = read(fd, buf, sizeof(buf));\r
+    if (i < 0) {\r
+       printf("mkrootdev: failed to read /proc/cmdline: %d\n", errno);\r
+       close(fd);\r
+       return 1;\r
+    }\r
+\r
+    close(fd);\r
+    buf[i - 1] = '\0';\r
+\r
+    start = buf;\r
+    while (*start && isspace(*start)) start++;\r
+    while (*start && strncmp(start, "root=", 5)) {\r
+       while (*start && !isspace(*start)) start++;\r
+       while (*start && isspace(*start)) start++;\r
+    }\r
+\r
+    start += 5;\r
+    chptr = start;\r
+    while (*chptr && !isspace(*chptr)) chptr++;\r
+    *chptr = '\0';\r
+\r
+    if (!strncmp(start, "LABEL=", 6)) {\r
+       if (get_spec_by_volume_label(start + 6, &major, &minor)) {\r
+           if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {\r
+               printf("mount: cannot create device %s (%d,%d)\n",\r
+                      path, major, minor);\r
+               return 1;\r
+           }\r
+\r
+           return 0;\r
+       }\r
+\r
+       printf("mkrootdev: label %s not found\n", start + 6);\r
+\r
+       return 1;\r
+    }\r
+\r
+    fd = open("/proc/sys/kernel/real-root-dev", O_RDONLY, 0);\r
+    if (fd < 0) {\r
+       printf("mkrootdev: failed to open /proc/sys/kernel/real-root-dev: %d\n", errno);\r
+       return 1;\r
+    }\r
+\r
+    i = read(fd, buf, sizeof(buf));\r
+    if (i < 0) {\r
+       printf("mkrootdev: failed to read real-root-dev: %d\n", errno);\r
+       close(fd);\r
+       return 1;\r
+    }\r
+\r
+    close(fd);\r
+    buf[i - 1] = '\0';\r
+\r
+    devNum = atoi(buf);\r
+    if (devNum < 0) {\r
+       printf("mkrootdev: bad device %s\n", buf);\r
+       return 1;\r
+    }\r
+\r
+    if (smartmknod(path, S_IFBLK | 0700, devNum)) {\r
+       printf("mkrootdev: mknod failed: %d\n", errno);\r
+       return 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int mkdirCommand(char * cmd, char * end) {\r
+    char * dir;\r
+    int ignoreExists = 0;\r
+\r
+    cmd = getArg(cmd, end, &dir);\r
+\r
+    if (cmd && !strcmp(dir, "-p")) {\r
+       ignoreExists = 1;\r
+       cmd = getArg(cmd, end, &dir);\r
+    }\r
+\r
+    if (!cmd) {\r
+       printf("mkdir: directory expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (mkdir(dir, 0755)) {\r
+       if (!ignoreExists && errno == EEXIST) {\r
+           printf("mkdir: failed to create %s: %d\n", dir, errno);\r
+           return 1;\r
+       }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int accessCommand(char * cmd, char * end) {\r
+    char * permStr;\r
+    int perms = 0;\r
+    char * file;\r
+\r
+    cmd = getArg(cmd, end, &permStr);\r
+    if (cmd) cmd = getArg(cmd, end, &file);\r
+\r
+    if (!cmd || *permStr != '-') {\r
+       printf("usage: access -[perm] file\n");\r
+       return 1;\r
+    }\r
+\r
+    permStr++;\r
+    while (*permStr) {\r
+       switch (*permStr) {\r
+         case 'r': perms |= R_OK; break;\r
+         case 'w': perms |= W_OK; break;\r
+         case 'x': perms |= X_OK; break;\r
+         case 'f': perms |= F_OK; break;\r
+         default:\r
+           printf("perms must be -[r][w][x][f]\n");\r
+           return 1;\r
+       }\r
+\r
+       permStr++;\r
+    }\r
+\r
+    if (access(file, perms))\r
+       return 1;\r
+\r
+    return 0;\r
+}\r
+\r
+int sleepCommand(char * cmd, char * end) {\r
+    char *delaystr;\r
+    int delay;\r
+\r
+    if (!(cmd = getArg(cmd, end, &delaystr))) {\r
+       printf("sleep: delay expected\n");\r
+       return 1;\r
+    }\r
+\r
+    delay = atoi(delaystr);\r
+    sleep(delay);\r
+\r
+    return 0;\r
+}\r
+\r
+int readlinkCommand(char * cmd, char * end) {\r
+    char * path;\r
+    char * buf, * respath, * fullpath;\r
+    struct stat sb;\r
+\r
+    if (!(cmd = getArg(cmd, end, &path))) {\r
+        printf("readlink: file expected\n");\r
+        return 1;\r
+    }\r
+\r
+    if (lstat(path, &sb) == -1) {\r
+        fprintf(stderr, "unable to stat %s: %d\n", path, errno);\r
+        return 1;\r
+    }\r
+\r
+    if (!S_ISLNK(sb.st_mode)) {\r
+        printf("%s\n", path);\r
+        return 0;\r
+    }\r
+    \r
+    buf = malloc(512);\r
+    if (readlink(path, buf, 512) == -1) {\r
+       fprintf(stderr, "error readlink %s: %d\n", path, errno);\r
+       return 1;\r
+    }\r
+\r
+    /* symlink is absolute */\r
+    if (buf[0] == '/') {\r
+        printf("%s\n", buf);\r
+        return 0;\r
+    } \r
+   \r
+    /* nope, need to handle the relative symlink case too */\r
+    respath = strrchr(path, '/');\r
+    if (respath) {\r
+        *respath = '\0';\r
+    }\r
+\r
+    fullpath = malloc(512);\r
+    /* and normalize it */\r
+    snprintf(fullpath, 512, "%s/%s", path, buf);\r
+    respath = malloc(PATH_MAX);\r
+    if (!(respath = realpath(fullpath, respath))) {\r
+        fprintf(stderr, "error realpath %s: %d\n", fullpath, errno);\r
+        return 1;\r
+    }\r
+\r
+    printf("%s\n", respath);\r
+    return 0;\r
+}\r
+\r
+int doFind(char * dirName, char * name) {\r
+    struct stat sb;\r
+    DIR * dir;\r
+    struct dirent * d;\r
+    char * strBuf = alloca(strlen(dirName) + 1024);\r
+\r
+    if (!(dir = opendir(dirName))) {\r
+       fprintf(stderr, "error opening %s: %d\n", dirName, errno);\r
+       return 0;\r
+    }\r
+\r
+    errno = 0;\r
+    while ((d = readdir(dir))) {\r
+       errno = 0;\r
+\r
+       strcpy(strBuf, dirName);\r
+       strcat(strBuf, "/");\r
+       strcat(strBuf, d->d_name);\r
+\r
+       if (!strcmp(d->d_name, name))\r
+           printf("%s\n", strBuf);\r
+\r
+       if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {\r
+           errno = 0;\r
+           continue;\r
+       }\r
+\r
+       if (lstat(strBuf, &sb)) {\r
+           fprintf(stderr, "failed to stat %s: %d\n", strBuf, errno);\r
+           errno = 0;\r
+           continue;\r
+       }\r
+\r
+       if (S_ISDIR(sb.st_mode))\r
+           doFind(strBuf, name);\r
+    }\r
+\r
+    if (errno) {\r
+       closedir(dir);\r
+       printf("error reading from %s: %d\n", dirName, errno);\r
+       return 1;\r
+    }\r
+\r
+    closedir(dir);\r
+\r
+    return 0;\r
+}\r
+\r
+int findCommand(char * cmd, char * end) {\r
+    char * dir;\r
+    char * name;\r
+\r
+    cmd = getArg(cmd, end, &dir);\r
+    if (cmd) cmd = getArg(cmd, end, &name);\r
+    if (cmd && strcmp(name, "-name")) {\r
+       printf("usage: find [path] -name [file]\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd) cmd = getArg(cmd, end, &name);\r
+    if (!cmd) {\r
+       printf("usage: find [path] -name [file]\n");\r
+       return 1;\r
+    }\r
+\r
+    return doFind(dir, name);\r
+}\r
+\r
+int findlodevCommand(char * cmd, char * end) {\r
+    char devName[20];\r
+    int devNum;\r
+    int fd;\r
+    struct loop_info loopInfo;\r
+    char separator[2] = "";\r
+\r
+    if (*end != '\n') {\r
+       printf("usage: findlodev\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!access("/dev/.devfsd", X_OK))\r
+       strcpy(separator, "/");\r
+\r
+    for (devNum = 0; devNum < 256; devNum++) {\r
+       sprintf(devName, "/dev/loop%s%d", separator, devNum);\r
+       if ((fd = open(devName, O_RDONLY)) < 0) return 0;\r
+\r
+       if (ioctl(fd, LOOP_GET_STATUS, &loopInfo)) {\r
+           close(fd);\r
+           printf("%s\n", devName);\r
+           return 0;\r
+       }\r
+\r
+       close(fd);\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int mknodCommand(char * cmd, char * end) {\r
+    char * path, * type;\r
+    char * majorStr, * minorStr;\r
+    int major;\r
+    int minor;\r
+    char * chptr;\r
+    mode_t mode;\r
+\r
+    cmd = getArg(cmd, end, &path);\r
+    cmd = getArg(cmd, end, &type);\r
+    cmd = getArg(cmd, end, &majorStr);\r
+    cmd = getArg(cmd, end, &minorStr);\r
+    if (!minorStr) {\r
+       printf("mknod: usage mknod <path> [c|b] <major> <minor>\n");\r
+       return 1;\r
+    }\r
+\r
+    if (!strcmp(type, "b")) {\r
+       mode = S_IFBLK;\r
+    } else if (!strcmp(type, "c")) {\r
+       mode = S_IFCHR;\r
+    } else {\r
+       printf("mknod: invalid type\n");\r
+       return 1;\r
+    }\r
+\r
+    major = strtol(majorStr, &chptr, 10);\r
+    if (*chptr) {\r
+       printf("invalid major number\n");\r
+       return 1;\r
+    }\r
+\r
+    minor = strtol(minorStr, &chptr, 10);\r
+    if (*chptr) {\r
+       printf("invalid minor number\n");\r
+       return 1;\r
+    }\r
+\r
+    if (smartmknod(path, mode | 0600, makedev(major, minor))) {\r
+       printf("mknod: failed to create %s: %d\n", path, errno);\r
+       return 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int mkdevicesCommand(char * cmd, char * end) {\r
+    int fd;\r
+    char buf[32768];\r
+    int i;\r
+    char * start, * chptr;\r
+    int major, minor;\r
+    char old;\r
+    char devName[128];\r
+    char * prefix;\r
+\r
+    if (!(cmd = getArg(cmd, end, &prefix))) {\r
+       printf("mkdevices: path expected\n");\r
+       return 1;\r
+    }\r
+\r
+    if (cmd < end) {\r
+       printf("mkdevices: unexpected arguments\n");\r
+       return 1;\r
+    }\r
+\r
+    if ((fd = open("/proc/partitions", O_RDONLY)) < 0) {\r
+       printf("mkrootdev: failed to open /proc/partitions: %d\n", errno);\r
+       return 1;\r
+    }\r
+\r
+    i = read(fd, buf, sizeof(buf));\r
+    if (i < 1) {\r
+       close(fd);\r
+       printf("failed to read /proc/partitions: %d\n", errno);\r
+       return 1;\r
+    }\r
+    buf[i] = '\0';\r
+    close(fd);\r
+\r
+    start = strchr(buf, '\n');\r
+    if (start) {\r
+       start++;\r
+       start = strchr(buf, '\n');\r
+    }\r
+    if (!start) return 1;\r
+\r
+    start = start + 1;\r
+    while (*start) {\r
+       while (*start && isspace(*start)) start++;\r
+       major = strtol(start, &chptr, 10);\r
+\r
+       if (start != chptr) {\r
+           start = chptr;\r
+           while (*start && isspace(*start)) start++;\r
+           minor = strtol(start, &chptr, 10);\r
+\r
+           if (start != chptr) {\r
+               start = chptr;\r
+               while (*start && isspace(*start)) start++;\r
+               while (*start && !isspace(*start)) start++;\r
+               while (*start && isspace(*start)) start++;\r
+\r
+               if (*start) {\r
+\r
+                   chptr = start;\r
+                   while (!isspace(*chptr)) chptr++;\r
+                   old = *chptr;\r
+                   *chptr = '\0';\r
+\r
+                   if (testing) {\r
+                       printf("% 3d % 3d %s\n", major, minor, start);\r
+                   } else {\r
+                       char * ptr, * deviceDir;\r
+                       int i;\r
+\r
+                       sprintf(devName, "%s/%s", prefix, start);\r
+                       unlink(devName);\r
+\r
+                       ptr = devName;\r
+                       i = 0;\r
+                       while (*ptr)\r
+                           if (*ptr++ == '/')\r
+                               i++;\r
+                       if (i > 2) {\r
+                           deviceDir = alloca(strlen(devName) + 1);\r
+                           strcpy(deviceDir, devName);\r
+                           ptr = deviceDir + (strlen(devName) - 1);\r
+                           while (*ptr != '/')\r
+                               *ptr-- = '\0';\r
+                           if (access(deviceDir, X_OK) && mkdir(deviceDir, 0644)) {\r
+                               printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno);\r
+                           }\r
+                       }\r
+                       if (smartmknod(devName, S_IFBLK | 0600, \r
+                                 makedev(major, minor))) {\r
+                           printf("failed to create %s\n", devName);\r
+                       }\r
+                   }\r
+\r
+                   *chptr = old;\r
+                   start = chptr;\r
+               }\r
+\r
+           }\r
+       }\r
+\r
+       start = strchr(start, '\n');\r
+       if (!*start) return 1;\r
+       start = start + 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+int runStartup(int fd) {\r
+    char contents[32768];\r
+    int i;\r
+    char * start, * end;\r
+    char * chptr;\r
+    int rc;\r
+\r
+    i = read(fd, contents, sizeof(contents) - 1);\r
+    if (i == (sizeof(contents) - 1)) {\r
+       printf("Failed to read /startup.rc -- file too large.\n");\r
+       return 1;\r
+    }\r
+\r
+    contents[i] = '\0';\r
+\r
+    start = contents;\r
+    while (*start) {\r
+       while (isspace(*start) && *start && (*start != '\n')) start++;\r
+\r
+       if (*start == '#')\r
+           while (*start && (*start != '\n')) start++;\r
+\r
+       if (*start == '\n') {\r
+           start++;\r
+           continue;\r
+       }\r
+\r
+       if (!*start) {\r
+           printf("(last line in /startup.rc is empty)\n");\r
+           continue;\r
+       }\r
+\r
+       /* start points to the beginning of the command */\r
+       end = start + 1;\r
+       while (*end && (*end != '\n')) end++;\r
+       if (!*end) {\r
+           printf("(last line in /startup.rc missing \\n -- skipping)\n");\r
+           start = end;\r
+           continue;\r
+       }\r
+\r
+       /* end points to the \n at the end of the command */\r
+\r
+       chptr = start;\r
+       while (chptr < end && !isspace(*chptr)) chptr++;\r
+\r
+       if (!strncmp(start, "mount", MAX(5, chptr - start)))\r
+           rc = mountCommand(chptr, end);\r
+       else if (!strncmp(start, "losetup", MAX(7, chptr - start)))\r
+           rc = losetupCommand(chptr, end);\r
+       else if (!strncmp(start, "echo", MAX(4, chptr - start)))\r
+           rc = echoCommand(chptr, end);\r
+       else if (!strncmp(start, "raidautorun", MAX(11, chptr - start)))\r
+           rc = raidautorunCommand(chptr, end);\r
+       else if (!strncmp(start, "pivot_root", MAX(10, chptr - start)))\r
+           rc = pivotrootCommand(chptr, end);\r
+       else if (!strncmp(start, "mkrootdev", MAX(9, chptr - start)))\r
+           rc = mkrootdevCommand(chptr, end);\r
+       else if (!strncmp(start, "umount", MAX(6, chptr - start)))\r
+           rc = umountCommand(chptr, end);\r
+       else if (!strncmp(start, "exec", MAX(4, chptr - start)))\r
+           rc = execCommand(chptr, end);\r
+       else if (!strncmp(start, "mkdir", MAX(5, chptr - start)))\r
+           rc = mkdirCommand(chptr, end);\r
+       else if (!strncmp(start, "access", MAX(6, chptr - start)))\r
+           rc = accessCommand(chptr, end);\r
+       else if (!strncmp(start, "find", MAX(4, chptr - start)))\r
+           rc = findCommand(chptr, end);\r
+       else if (!strncmp(start, "findlodev", MAX(7, chptr - start)))\r
+           rc = findlodevCommand(chptr, end);\r
+       else if (!strncmp(start, "showlabels", MAX(10, chptr-start)))\r
+           rc = display_uuid_cache();\r
+       else if (!strncmp(start, "mkdevices", MAX(9, chptr-start)))\r
+           rc = mkdevicesCommand(chptr, end);\r
+       else if (!strncmp(start, "sleep", MAX(5, chptr-start)))\r
+           rc = sleepCommand(chptr, end);\r
+       else if (!strncmp(start, "mknod", MAX(5, chptr-start)))\r
+           rc = mknodCommand(chptr, end);\r
+        else if (!strncmp(start, "readlink", MAX(8, chptr-start)))\r
+            rc = readlinkCommand(chptr, end);\r
+       else {\r
+           *chptr = '\0';\r
+           rc = otherCommand(start, chptr + 1, end, 1);\r
+       }\r
+\r
+       start = end + 1;\r
+    }\r
+\r
+    return rc;\r
+}\r
+\r
+int main(int argc, char **argv) {\r
+    int fd = 0;\r
+    char * name;\r
+    int rc;\r
+    int force = 0;\r
+\r
+    name = strrchr(argv[0], '/');\r
+    if (!name) \r
+       name = argv[0];\r
+    else\r
+       name++;\r
+\r
+    if (!strcmp(name, "modprobe"))\r
+       exit(0);\r
+\r
+    testing = (getppid() != 0) && (getppid() != 1);\r
+    argv++, argc--;\r
+\r
+    while (argc && **argv == '-') {\r
+       if (!strcmp(*argv, "--force")) {\r
+           force = 1;\r
+           argv++, argc--;\r
+           testing = 0;\r
+       } else if (!strcmp(*argv, "--quiet")) {\r
+           quiet = 1;\r
+           argv++, argc--;\r
+       } else {\r
+           printf("unknown argument %s\n", *argv);\r
+           return 1;\r
+       }\r
+    }\r
+\r
+    if (force && !quiet)\r
+       printf("(forcing normal run)\n");\r
+\r
+    if (testing && !quiet)\r
+       printf("(running in test mode).\n");\r
+\r
+    if (!quiet) printf("Red Hat nash version %s starting\n", VERSION);\r
+\r
+    if (*argv) {\r
+       fd = open(*argv, O_RDONLY, 0);\r
+       if (fd < 0) {\r
+           printf("nash: cannot open %s: %d\n", *argv, errno);\r
+           exit(1);\r
+       }\r
+    }\r
+\r
+    rc = runStartup(fd);\r
+    close(fd);\r
+\r
+    return rc;\r
+}\r