--- /dev/null
+/*\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