Magellan Linux

Annotation of /tags/mkinitrd-6_1_3/nash/nash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
Original Path: trunk/mkinitrd-magellan/nash/nash.c
File MIME type: text/plain
File size: 48197 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /*
2     * nash.c
3     *
4     * Simple code to load modules, mount root, and get things going. Uses
5     * dietlibc to keep things small.
6     *
7     * Erik Troan (ewt@redhat.com)
8     * Jeremy Katz (katzj@redhat.com)
9     * Peter Jones (pjones@redhat.com)
10     *
11     * Copyright 2002-2005 Red Hat Software
12     *
13     * This software may be freely redistributed under the terms of the GNU
14     * public license.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     *
20     */
21    
22     /* We internalize losetup, mount, raidautorun, and echo commands. Other
23     commands are run from the filesystem. Comments and blank lines work as
24     well, argument parsing is screwy. */
25    
26     #define _GNU_SOURCE 1
27    
28     #include <ctype.h>
29     #include <dirent.h>
30     #include <errno.h>
31     #include <fcntl.h>
32     #include <net/if.h>
33     #include <signal.h>
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <stdarg.h>
37     #include <string.h>
38     #include <sys/ioctl.h>
39     #include <sys/mount.h>
40     #include <sys/socket.h>
41     #include <sys/stat.h>
42     #include <sys/time.h>
43     #include <sys/types.h>
44     #include <sys/un.h>
45     #include <sys/wait.h>
46     #include <unistd.h>
47     #include <sys/ioctl.h>
48     #include <sys/reboot.h>
49     #include <termios.h>
50     #include <mntent.h>
51    
52     #include <asm/unistd.h>
53    
54     #include "name_to_dev_t.h"
55     #include "mount_by_label.h"
56    
57     /* Need to tell loop.h what the actual dev_t type is. */
58     #undef dev_t
59     #if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
60     #define dev_t unsigned int
61     #else
62     #define dev_t unsigned short
63     #endif
64     #include <linux/loop.h>
65     #undef dev_t
66     #define dev_t dev_t
67    
68     #define syslog klogctl
69    
70     #include <linux/cdrom.h>
71     #define MD_MAJOR 9
72     #include <linux/raid/md_u.h>
73    
74     #ifndef RAID_AUTORUN
75     #define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
76     #endif
77    
78     #ifndef MS_REMOUNT
79     #define MS_REMOUNT 32
80     #endif
81    
82     #ifndef MS_BIND
83     #define MS_BIND 4096
84     #endif
85    
86     #ifndef MS_MOVE
87     #define MS_MOVE 8192
88     #endif
89    
90     #ifndef MNT_FORCE
91     #define MNT_FORCE 0x1
92     #endif
93    
94     #ifndef MNT_DETACH
95     #define MNT_DETACH 0x2
96     #endif
97    
98     #define MAX(a, b) ((a) > (b) ? a : b)
99    
100     static int testing = 0, quiet = 0, reallyquiet = 0;
101    
102     static int qprintf(const char *format, ...)
103     __attribute__((format(printf, 1, 2)));
104     static int eprintf(const char *format, ...)
105     __attribute__((format(printf, 1, 2)));
106    
107     static int
108     qprintf(const char *format, ...)
109     {
110     va_list ap;
111     int ret;
112    
113     if (quiet)
114     return 0;
115    
116     va_start(ap, format);
117     ret = vprintf(format, ap);
118     va_end(ap);
119    
120     fflush(stdout);
121     return ret;
122     }
123    
124     static int
125     eprintf(const char *format, ...)
126     {
127     va_list ap;
128     int ret;
129    
130     va_start(ap, format);
131     ret = vfprintf(stderr, format, ap);
132     va_end(ap);
133    
134     return ret;
135     }
136    
137     #define PATH "/usr/bin:/bin:/sbin:/usr/sbin"
138     static char * env[] = {
139     "PATH=" PATH,
140     "LVM_SUPPRESS_FD_WARNINGS=1",
141     NULL
142     };
143     static char sysPath[] = PATH;
144    
145     static int
146     smartmknod(char * device, mode_t mode, dev_t dev)
147     {
148     char buf[256];
149     char * end;
150    
151     strncpy(buf, device, 256);
152    
153     end = buf;
154     while (*end) {
155     if (*end == '/') {
156     *end = '\0';
157     if (access(buf, F_OK) && errno == ENOENT)
158     mkdir(buf, 0755);
159     *end = '/';
160     }
161    
162     end++;
163     }
164    
165     return mknod(device, mode, dev);
166     }
167    
168     static int
169     searchPath(char *bin, char **resolved)
170     {
171     char *fullPath = NULL;
172     char *pathStart;
173     char *pathEnd;
174     int rc;
175    
176     if (!strchr(bin, '/')) {
177     pathStart = sysPath;
178     while (*pathStart) {
179     char pec;
180     pathEnd = strchr(pathStart, ':');
181    
182     if (!pathEnd)
183     pathEnd = pathStart + strlen(pathStart);
184    
185     pec = *pathEnd;
186     *pathEnd = '\0';
187    
188     rc = asprintf(&fullPath, "%s/%s", pathStart, bin);
189     if (!fullPath) {
190     int errnum = errno;
191     eprintf("error searching path: %s\n", strerror(errnum));
192     return -errnum;
193     }
194    
195     *pathEnd = pec;
196     pathStart = pathEnd;
197     if (*pathStart)
198     pathStart++;
199    
200     if (!access(fullPath, X_OK)) {
201     *resolved = fullPath;
202     return 0;
203     }
204     free(fullPath);
205     }
206     }
207    
208     if (!access(bin, X_OK)) {
209     *resolved = strdup(bin);
210     if (*resolved)
211     return 0;
212     }
213     return -errno;
214     }
215    
216     static char *
217     getArg(char * cmd, char * end, char ** arg)
218     {
219     char quote = '\0';
220    
221     if (!cmd || cmd >= end)
222     return NULL;
223    
224     while (isspace(*cmd) && cmd < end) cmd++;
225     if (cmd >= end)
226     return NULL;
227    
228     if (*cmd == '"')
229     cmd++, quote = '"';
230     else if (*cmd == '\'')
231     cmd++, quote = '\'';
232    
233     if (quote) {
234     *arg = cmd;
235    
236     /* This doesn't support \ escapes */
237     while (cmd < end && *cmd != quote) cmd++;
238    
239     if (cmd == end) {
240     eprintf("error: quote mismatch for %s\n", *arg);
241     return NULL;
242     }
243    
244     *cmd = '\0';
245     cmd++;
246     } else {
247     *arg = cmd;
248     while (!isspace(*cmd) && cmd < end) cmd++;
249     *cmd = '\0';
250     if (**arg == '$')
251     *arg = getenv(*arg+1);
252     if (*arg == NULL)
253     *arg = "";
254     }
255    
256     cmd++;
257    
258     while (isspace(*cmd)) cmd++;
259    
260     return cmd;
261     }
262    
263     /* taken from anaconda/isys/probe.c */
264     static int
265     readFD (int fd, char **buf)
266     {
267     char *p;
268     size_t size = 16384;
269     int s, filesize;
270    
271     *buf = calloc (16384, sizeof (char));
272     if (*buf == 0) {
273     eprintf("calloc failed: %s\n", strerror(errno));
274     return -1;
275     }
276    
277     filesize = 0;
278     do {
279     p = &(*buf) [filesize];
280     s = read (fd, p, 16384);
281     if (s < 0)
282     break;
283     filesize += s;
284     /* only exit for empty reads */
285     if (s == 0)
286     break;
287     size += s;
288     *buf = realloc (*buf, size);
289     } while (1);
290    
291     if (filesize == 0 && s < 0) {
292     free (*buf);
293     *buf = NULL;
294     return -1;
295     }
296    
297     return filesize;
298     }
299    
300     #ifdef __powerpc__
301     #define CMDLINESIZE 256
302     #else
303     #define CMDLINESIZE 1024
304     #endif
305    
306     /* get the contents of the kernel command line from /proc/cmdline */
307     static char *
308     getKernelCmdLine(void)
309     {
310     int fd, i, errnum;
311     static char * buf = NULL;
312    
313     if (buf)
314     return buf;
315    
316     fd = open("/proc/cmdline", O_RDONLY, 0);
317     if (fd < 0) {
318     eprintf("getKernelCmdLine: failed to open /proc/cmdline: %s\n",
319     strerror(errno));
320     return NULL;
321     }
322    
323     i = readFD(fd, &buf);
324     errnum = errno;
325     close(fd);
326     if (i < 0) {
327     eprintf("getKernelCmdLine: failed to read /proc/cmdline: %s\n",
328     strerror(errnum));
329     return NULL;
330     }
331     return buf;
332     }
333    
334     /* get the start of a kernel arg "arg". returns everything after it
335     * (useful for things like getting the args to init=). so if you only
336     * want one arg, you need to terminate it at the n */
337     static char *
338     getKernelArg(char * arg)
339     {
340     char * start, * cmdline;
341     int len;
342    
343     cmdline = start = getKernelCmdLine();
344     if (start == NULL)
345     return NULL;
346     while (*start) {
347     if (isspace(*start)) {
348     start++;
349     continue;
350     }
351     len = strlen(arg);
352     /* don't return if it's some other arg that just starts like
353     this one */
354     if (strncmp(start, arg, len) == 0) {
355     if (start[len] == '=')
356     return start + len + 1;
357     if (!start[len] || isspace(start[len]))
358     return start + len;
359     }
360     while (*++start && !isspace(*start))
361     ;
362     }
363    
364     return NULL;
365     }
366    
367     static int
368     mountCommand(char * cmd, char * end)
369     {
370     char * fsType = NULL;
371     char * device;
372     char * mntPoint;
373     char * deviceDir = NULL;
374     char * options = NULL;
375     int mustRemove = 0;
376     int mustRemoveDir = 0;
377     int rc = 0;
378     int flags = MS_MGC_VAL;
379     char * newOpts;
380    
381     cmd = getArg(cmd, end, &device);
382     if (!cmd) {
383     eprintf(
384     "usage: mount [--ro] [-o <opts>] -t <type> <device> <mntpoint>\n");
385     return 1;
386     }
387    
388     while (cmd && *device == '-') {
389     if (!strcmp(device, "--ro")) {
390     flags |= MS_RDONLY;
391     } else if (!strcmp(device, "--bind")) {
392     flags = MS_BIND;
393     fsType = "none";
394     } else if (!strcmp(device, "-o")) {
395     cmd = getArg(cmd, end, &options);
396     if (!cmd) {
397     eprintf("mount: -o requires arguments\n");
398     return 1;
399     }
400     } else if (!strcmp(device, "-t")) {
401     if (!(cmd = getArg(cmd, end, &fsType))) {
402     eprintf("mount: missing filesystem type\n");
403     return 1;
404     }
405     }
406    
407     cmd = getArg(cmd, end, &device);
408     }
409    
410     if (!cmd) {
411     eprintf("mount: missing device or mountpoint\n");
412     return 1;
413     }
414    
415     if (!(cmd = getArg(cmd, end, &mntPoint))) {
416     struct mntent *mnt;
417     FILE *fstab;
418    
419     fstab = fopen("/fstab", "r");
420     do {
421     if (!fstab || !(mnt = getmntent(fstab))) {
422     eprintf("mount: missing mount point\n");
423     return 1;
424     }
425     if (!strcmp(mnt->mnt_dir, device)) {
426     device = mnt->mnt_fsname;
427     mntPoint = mnt->mnt_dir;
428    
429     if (!strcmp(mnt->mnt_type, "bind")) {
430     flags |= MS_BIND;
431     fsType = "none";
432     } else
433     fsType = mnt->mnt_type;
434    
435     options = mnt->mnt_opts;
436     break;
437     }
438     } while(1);
439    
440     fclose(fstab);
441     }
442    
443     if (!fsType) {
444     eprintf("mount: filesystem type expected\n");
445     return 1;
446     }
447    
448     if (cmd && cmd < end) {
449     eprintf("mount: unexpected arguments\n");
450     return 1;
451     }
452    
453     /* need to deal with options */
454     if (options) {
455     char * end;
456     char * start = options;
457    
458     newOpts = alloca(strlen(options) + 1);
459     *newOpts = '\0';
460    
461     while (*start) {
462     end = strchr(start, ',');
463     if (!end) {
464     end = start + strlen(start);
465     } else {
466     *end = '\0';
467     end++;
468     }
469    
470     if (!strcmp(start, "ro"))
471     flags |= MS_RDONLY;
472     else if (!strcmp(start, "rw"))
473     flags &= ~MS_RDONLY;
474     else if (!strcmp(start, "nosuid"))
475     flags |= MS_NOSUID;
476     else if (!strcmp(start, "suid"))
477     flags &= ~MS_NOSUID;
478     else if (!strcmp(start, "nodev"))
479     flags |= MS_NODEV;
480     else if (!strcmp(start, "dev"))
481     flags &= ~MS_NODEV;
482     else if (!strcmp(start, "noexec"))
483     flags |= MS_NOEXEC;
484     else if (!strcmp(start, "exec"))
485     flags &= ~MS_NOEXEC;
486     else if (!strcmp(start, "sync"))
487     flags |= MS_SYNCHRONOUS;
488     else if (!strcmp(start, "async"))
489     flags &= ~MS_SYNCHRONOUS;
490     else if (!strcmp(start, "nodiratime"))
491     flags |= MS_NODIRATIME;
492     else if (!strcmp(start, "diratime"))
493     flags &= ~MS_NODIRATIME;
494     else if (!strcmp(start, "noatime"))
495     flags |= MS_NOATIME;
496     else if (!strcmp(start, "atime"))
497     flags &= ~MS_NOATIME;
498     else if (!strcmp(start, "remount"))
499     flags |= MS_REMOUNT;
500     else if (!strcmp(start, "defaults"))
501     ;
502     else {
503     if (*newOpts)
504     strcat(newOpts, ",");
505     strcat(newOpts, start);
506     }
507    
508     start = end;
509     }
510    
511     options = newOpts;
512     }
513    
514     if (!strncmp("LABEL=", device, 6)) {
515     int major, minor;
516     char * devName;
517     char * ptr;
518     int i;
519    
520     devName = get_spec_by_volume_label(device + 6, &major, &minor);
521    
522     if (devName) {
523     device = devName;
524     if (access(device, F_OK)) {
525     ptr = device;
526     i = 0;
527     while (*ptr)
528     if (*ptr++ == '/')
529     i++;
530     if (i > 2) {
531     deviceDir = alloca(strlen(device) + 1);
532     strcpy(deviceDir, device);
533     ptr = deviceDir + (strlen(device) - 1);
534     while (*ptr != '/')
535     *ptr-- = '\0';
536     if (mkdir(deviceDir, 0644)) {
537     eprintf("mkdir: cannot create directory %s: %s\n",
538     deviceDir, strerror(errno));
539     } else {
540     mustRemoveDir = 1;
541     }
542     }
543     if (smartmknod(device, S_IFBLK | 0600, makedev(major, minor))) {
544     printf("mount: cannot create device %s (%d,%d)\n",
545     device, major, minor);
546     return 1;
547     }
548     mustRemove = 1;
549     }
550     }
551     }
552    
553     if (testing) {
554     printf("mount %s%s%s-t '%s' '%s' '%s' (%s%s%s%s%s%s%s)\n",
555     options ? "-o '" : "",
556     options ? options : "",
557     options ? "\' " : "",
558     fsType, device, mntPoint,
559     (flags & MS_RDONLY) ? "ro " : "",
560     (flags & MS_NOSUID) ? "nosuid " : "",
561     (flags & MS_NODEV) ? "nodev " : "",
562     (flags & MS_NOEXEC) ? "noexec " : "",
563     (flags & MS_SYNCHRONOUS) ? "sync " : "",
564     (flags & MS_REMOUNT) ? "remount " : "",
565     (flags & MS_NOATIME) ? "noatime " : ""
566     );
567     } else {
568     if (mount(device, mntPoint, fsType, flags, options) < 0) {
569     eprintf("mount: error %s mounting %s on %s as %s\n",
570     strerror(errno), device, mntPoint, fsType);
571     rc = 1;
572     }
573     }
574    
575     if (mustRemove) unlink(device);
576     if (mustRemoveDir) rmdir(deviceDir);
577    
578     return rc;
579     }
580    
581     static int
582     otherCommand(char * bin, char * cmd, char * end, int doFork)
583     {
584     char ** args;
585     char ** nextArg;
586     int pid, wpid;
587     int status;
588     char * stdoutFile = NULL;
589     int stdoutFd = 1;
590    
591     args = (char **)calloc(128, sizeof (char *));
592     if (!args)
593     return 1;
594     nextArg = args;
595    
596     if (access(bin, X_OK)) {
597     eprintf("failed to execute %s: %s\n", bin, strerror(errno));
598     return 1;
599     }
600    
601     *nextArg = strdup(bin);
602    
603     while (cmd && cmd < end) {
604     nextArg++;
605     cmd = getArg(cmd, end, nextArg);
606     }
607    
608     if (cmd) nextArg++;
609     *nextArg = NULL;
610    
611     /* if the next-to-last arg is a >, redirect the output properly */
612     if (((nextArg - args) >= 2) && !strcmp(*(nextArg - 2), ">")) {
613     stdoutFile = *(nextArg - 1);
614     *(nextArg - 2) = NULL;
615    
616     stdoutFd = open(stdoutFile, O_CREAT | O_RDWR | O_TRUNC, 0600);
617     if (stdoutFd < 0) {
618     eprintf("nash: failed to open %s: %s\n", stdoutFile,
619     strerror(errno));
620     return 1;
621     }
622     }
623    
624     if (testing) {
625     printf("%s ", bin);
626     nextArg = args + 1;
627     while (*nextArg)
628     printf(" '%s'", *nextArg++);
629     if (stdoutFile)
630     printf(" (> %s)", stdoutFile);
631     printf("\n");
632     } else {
633     if (!doFork || !(pid = fork())) {
634     /* child */
635     int errnum;
636    
637     dup2(stdoutFd, 1);
638     execve(args[0], args, env);
639     errnum = errno; /* so we'll have it after printf */
640     eprintf("ERROR: failed in exec of %s: %s\n", args[0],
641     strerror(errnum));
642     return errnum;
643     }
644    
645     if (stdoutFd != 1)
646     close(stdoutFd);
647    
648     for (;;) {
649     wpid = wait4(-1, &status, 0, NULL);
650     if (wpid == -1) {
651     eprintf("ERROR: Failed to wait for process %d: %s\n", wpid,
652     strerror(errno));
653     }
654    
655     if (wpid != pid)
656     continue;
657    
658     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
659     #if 0
660     eprintf("ERROR: %s exited abnormally with value %d (pid %d)\n",
661     args[0], WEXITSTATUS(status), pid);
662     #endif
663     return 1;
664     }
665     break;
666     }
667     }
668    
669     return 0;
670     }
671    
672     static int
673     lnCommand(char *cmd, char *end)
674     {
675     char *oldpath, *newpath;
676     int symbolic = 0, rc;
677    
678     if (!(cmd = getArg(cmd, end, &oldpath))) {
679     eprintf("ln: argument expected\n");
680     return 1;
681     }
682    
683     if (!strcmp(cmd, "-s")) {
684     symbolic = 1;
685     if (!(cmd = getArg(cmd, end, &oldpath))) {
686     eprintf("ln: argument expected\n");
687     return 1;
688     }
689     }
690    
691     if (!(cmd = getArg(cmd, end, &newpath))) {
692     eprintf("ln: argument expected\n");
693     return 1;
694     }
695    
696     if (symbolic)
697     rc = symlink(oldpath, newpath);
698     else
699     rc = link(oldpath, newpath);
700    
701     if (rc > 0) {
702     eprintf("ln: error: %s\n", strerror(errno));
703     return 1;
704     }
705    
706     return 0;
707     }
708    
709     #ifdef DEBUG
710     static int lsdir(char *thedir, char * prefix)
711     {
712     DIR * dir;
713     struct dirent * entry;
714     struct stat sb;
715     char * fn;
716    
717     if (!(dir = opendir(thedir))) {
718     eprintf("error opening %s: %s\n", thedir, strerror(errno));
719     return 1;
720     }
721    
722     fn = calloc(1024, sizeof (char));
723     while ((entry = readdir(dir))) {
724     if (entry->d_name[0] == '.')
725     continue;
726     snprintf(fn, 1024, "%s/%s", thedir, entry->d_name);
727     stat(fn, &sb);
728     printf("%s%s", prefix, fn);
729    
730     if (S_ISDIR(sb.st_mode)) {
731     char * pfx;
732     pfx = calloc(strlen(prefix) + 3, sizeof (char));
733     sprintf(pfx, "%s ", prefix);
734     printf("/\n");
735     } else if (S_ISCHR(sb.st_mode)) {
736     printf(" c %d %d\n", major(sb.st_rdev), minor(sb.st_rdev));
737     } else if (S_ISBLK(sb.st_mode)) {
738     printf(" b %d %d\n", major(sb.st_rdev), minor(sb.st_rdev));
739     } else if (S_ISLNK(sb.st_mode)) {
740     char * target;
741     target = calloc(1024, sizeof (char));
742     readlink(fn, target, 1024);
743     printf("->%s\n", target);
744     free(target);
745     } else {
746     printf("\n");
747     }
748     }
749     return 0;
750     }
751    
752     static int
753     catCommand(char * cmd, char * end)
754     {
755     char * file;
756     char * buf;
757     int fd, n;
758    
759     if (!(cmd = getArg(cmd, end, &file))) {
760     eprintf("cat: argument expected\n");
761     return 1;
762     }
763    
764     if ((fd = open(file, O_RDONLY)) < 0) {
765     eprintf("cat: error opening %s: %s\n", file, strerror(errno));
766     return 1;
767     }
768    
769     buf = calloc(1024, sizeof (char));
770     while ((n = read(fd, buf, 1024)) > 0) {
771     write(1, buf, n);
772     }
773     return 0;
774     }
775    
776     static int
777     lsCommand(char * cmd, char * end)
778     {
779     char * dir;
780    
781     if (!(cmd = getArg(cmd, end, &dir))) {
782     eprintf("ls: argument expected\n");
783     return 1;
784     }
785    
786     lsdir(dir, "");
787     return 0;
788     }
789     #endif
790    
791     static int
792     execCommand(char *cmd, char *end)
793     {
794     char *bin, *fullPath = NULL;
795     int rc;
796    
797     if (!(cmd = getArg(cmd, end, &bin))) {
798     eprintf("exec: argument expected\n");
799     return 1;
800     }
801     rc = searchPath(bin, &fullPath);
802     if (rc < 0)
803     return 1;
804    
805     rc = otherCommand(fullPath, cmd, end, 0);
806     return rc == -ENOENT ? 1 : rc;
807     }
808    
809     static int
810     losetupCommand(char * cmd, char * end)
811     {
812     char * device;
813     char * file;
814     int fd;
815     struct loop_info loopInfo;
816     int dev;
817    
818     if (!(cmd = getArg(cmd, end, &device))) {
819     eprintf("losetup: missing device\n");
820     return 1;
821     }
822    
823     if (!(cmd = getArg(cmd, end, &file))) {
824     eprintf("losetup: missing file\n");
825     return 1;
826     }
827    
828     if (cmd < end) {
829     eprintf("losetup: unexpected arguments\n");
830     return 1;
831     }
832    
833     if (testing) {
834     printf("losetup '%s' '%s'\n", device, file);
835     } else {
836     dev = open(device, O_RDWR, 0);
837     if (dev < 0) {
838     eprintf("losetup: failed to open %s: %s\n", device,strerror(errno));
839     return 1;
840     }
841    
842     fd = open(file, O_RDWR, 0);
843     if (fd < 0) {
844     eprintf("losetup: failed to open %s: %s\n", file, strerror(errno));
845     close(dev);
846     return 1;
847     }
848    
849     if (ioctl(dev, LOOP_SET_FD, (long) fd)) {
850     eprintf("losetup: LOOP_SET_FD failed for fd %d: %s\n", fd,
851     strerror(errno));
852     close(dev);
853     close(fd);
854     return 1;
855     }
856    
857     close(fd);
858    
859     memset(&loopInfo, 0, sizeof(loopInfo));
860     strcpy(loopInfo.lo_name, file);
861    
862     if (ioctl(dev, LOOP_SET_STATUS, &loopInfo))
863     eprintf("losetup: LOOP_SET_STATUS failed: %s\n", strerror(errno));
864    
865     close(dev);
866     }
867    
868     return 0;
869     }
870    
871     #define RAID_MAJOR 9
872     static int
873     raidautorunCommand(char * cmd, char * end)
874     {
875     char * device;
876     int fd;
877    
878     if (!(cmd = getArg(cmd, end, &device))) {
879     eprintf("raidautorun: raid device expected as first argument\n");
880     return 1;
881     }
882    
883     if (cmd < end) {
884     eprintf("raidautorun: unexpected arguments\n");
885     return 1;
886     }
887    
888     /* with udev, the raid devices don't exist until they get started.
889     * this won't work so well with raidautorun. so, let's be smart
890     * and create them ourselves if we need to */
891     if (access(device, R_OK & W_OK)) {
892     int minor;
893     if (sscanf(device, "/dev/md%d", &minor) != 1) {
894     eprintf("raidautorun: unable to autocreate %s\n", device);
895     return 1;
896     }
897    
898     if (smartmknod(device, S_IFBLK | 0600, makedev(RAID_MAJOR, minor))) {
899     eprintf("raidautorun: unable to autocreate %s\n", device);
900     return 1;
901     }
902     }
903    
904     fd = open(device, O_RDWR, 0);
905     if (fd < 0) {
906     eprintf("raidautorun: failed to open %s: %s\n", device,strerror(errno));
907     return 1;
908     }
909    
910     if (ioctl(fd, RAID_AUTORUN, 0)) {
911     eprintf("raidautorun: RAID_AUTORUN failed: %s\n", strerror(errno));
912     close(fd);
913     return 1;
914     }
915    
916     close(fd);
917     return 0;
918     }
919    
920     /* remove all files/directories below dirName -- don't cross mountpoints */
921     static int
922     recursiveRemove(char * dirName)
923     {
924     struct stat sb,rb;
925     DIR * dir;
926     struct dirent * d;
927     char * strBuf = alloca(strlen(dirName) + 1024);
928    
929     if (!(dir = opendir(dirName))) {
930     eprintf("error opening %s: %s\n", dirName, strerror(errno));
931     return 0;
932     }
933    
934     if (fstat(dirfd(dir),&rb)) {
935     eprintf("unable to stat %s: %s\n", dirName, strerror(errno));
936     return 0;
937     }
938    
939     errno = 0;
940     while ((d = readdir(dir))) {
941     errno = 0;
942    
943     if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
944     errno = 0;
945     continue;
946     }
947    
948     strcpy(strBuf, dirName);
949     strcat(strBuf, "/");
950     strcat(strBuf, d->d_name);
951    
952     if (lstat(strBuf, &sb)) {
953     eprintf("failed to stat %s: %s\n", strBuf, strerror(errno));
954     errno = 0;
955     continue;
956     }
957    
958     /* only descend into subdirectories if device is same as dir */
959     if (S_ISDIR(sb.st_mode)) {
960     if (sb.st_dev == rb.st_dev) {
961     recursiveRemove(strBuf);
962     if (rmdir(strBuf))
963     eprintf("failed to rmdir %s: %s\n", strBuf,
964     strerror(errno));
965     }
966     errno = 0;
967     continue;
968     }
969    
970     if (unlink(strBuf)) {
971     eprintf("failed to remove %s: %s\n", strBuf, strerror(errno));
972     errno = 0;
973     continue;
974     }
975     }
976    
977     if (errno) {
978     closedir(dir);
979     eprintf("error reading from %s: %s\n", dirName, strerror(errno));
980     return 1;
981     }
982    
983     closedir(dir);
984    
985     return 0;
986     }
987    
988     static int
989     setuprootCommand(char *cmd, char *end)
990     {
991     FILE *fp;
992     char *new;
993    
994     qprintf("Setting up new root fs\n");
995    
996     cmd = getArg(cmd, end, &new);
997     if (cmd) {
998     eprintf("setuproot: unexpected arguments\n");
999     return 1;
1000     }
1001     new = "/sysroot";
1002    
1003     if (chdir(new)) {
1004     eprintf("setuproot: chdir(%s) failed: %s\n", new, strerror(errno));
1005     return 1;
1006     }
1007    
1008     if (mount("/dev", "./dev", NULL, MS_BIND, NULL) < 0)
1009     eprintf("setuproot: moving /dev failed: %s\n", strerror(errno));
1010    
1011     if (!getKernelArg("nomnt")) {
1012     fp = setmntent("./etc/fstab.sys", "r");
1013     if (fp)
1014     qprintf("using fstab.sys from mounted FS\n");
1015     else {
1016     fp = setmntent("/etc/fstab.sys", "r");
1017     if (fp)
1018     qprintf("using fstab.sys from initrd\n");
1019     }
1020     if (fp) {
1021     struct mntent *mnt;
1022    
1023     while((mnt = getmntent(fp))) {
1024     char *start = NULL, *end;
1025     char *target = NULL;
1026     struct stat sb;
1027    
1028     qprintf("mounting %s\n", mnt->mnt_dir);
1029     if (asprintf(&target, ".%s", mnt->mnt_dir) < 0) {
1030     eprintf("setuproot: out of memory while mounting %s\n",
1031     mnt->mnt_dir);
1032     continue;
1033     }
1034    
1035     if (stat(target, &sb) < 0) {
1036     free(target);
1037     target = NULL;
1038     continue;
1039     }
1040    
1041     if (asprintf(&start, "-o %s -t %s %s .%s\n",
1042     mnt->mnt_opts, mnt->mnt_type, mnt->mnt_fsname,
1043     mnt->mnt_dir) < 0) {
1044     eprintf("setuproot: out of memory while mounting %s\n",
1045     mnt->mnt_dir);
1046     continue;
1047     }
1048    
1049     end = start + 1;
1050     while (*end && (*end != '\n')) end++;
1051     /* end points to the \n at the end of the command */
1052    
1053     if (mountCommand(start, end) != 0)
1054     eprintf("setuproot: mount returned error\n");
1055    
1056     free(start);
1057     start = NULL;
1058     }
1059     endmntent(fp);
1060     } else {
1061     struct {
1062     char *source;
1063     char *target;
1064     char *type;
1065     int flags;
1066     void *data;
1067     } fstab[] = {
1068     { "/proc", "./proc", "proc", 0, NULL },
1069     { "/sys", "./sys", "sysfs", 0, NULL },
1070     #if 0
1071     { "/dev/pts", "./dev/pts", "devpts", 0, "gid=5,mode=620" },
1072     { "/dev/shm", "./dev/shm", "tmpfs", 0, NULL },
1073     { "/selinux", "/selinux", "selinuxfs", 0, NULL },
1074     #endif
1075     { NULL, }
1076     };
1077     int i = 0;
1078    
1079     qprintf("no fstab.sys, mounting internal defaults\n");
1080     for (; fstab[i].source != NULL; i++) {
1081     if (mount(fstab[i].source, fstab[i].target, fstab[i].type,
1082     fstab[i].flags, fstab[i].data) < 0)
1083     eprintf("setuproot: error mounting %s: %s\n",
1084     fstab[i].source, strerror(errno));
1085     }
1086     }
1087     }
1088    
1089     chdir("/");
1090     return 0;
1091     }
1092    
1093     #define MAX_INIT_ARGS 32
1094     static int
1095     switchrootCommand(char * cmd, char * end)
1096     {
1097     /* Don't try to unmount the old "/", there's no way to do it. */
1098     const char * umounts[] = { "/dev", "/proc", "/sys", NULL };
1099     const char *initprogs[] = { "/sbin/init", "/etc/init",
1100     "/bin/init", "/bin/sh", NULL };
1101     char *init, **initargs;
1102     char *cmdline = NULL;
1103     char *new;
1104     int fd, i = 0;
1105    
1106     cmd = getArg(cmd, end, &new);
1107     if (cmd) {
1108     eprintf("switchroot: unexpected arguments\n");
1109     return 1;
1110     }
1111     new = "/sysroot";
1112    
1113     /* this has to happen before we unmount /proc */
1114     init = getKernelArg("init");
1115     if (init == NULL)
1116     cmdline = getKernelCmdLine();
1117    
1118     fd = open("/", O_RDONLY);
1119     for (; umounts[i] != NULL; i++) {
1120     qprintf("unmounting old %s\n", umounts[i]);
1121     if (umount2(umounts[i], MNT_DETACH) < 0) {
1122     eprintf("ERROR unmounting old %s: %s\n",umounts[i],strerror(errno));
1123     eprintf("forcing unmount of %s\n", umounts[i]);
1124     umount2(umounts[i], MNT_FORCE);
1125     }
1126     }
1127     i=0;
1128    
1129     chdir(new);
1130    
1131     recursiveRemove("/");
1132    
1133     if (mount(new, "/", NULL, MS_MOVE, NULL) < 0) {
1134     eprintf("switchroot: mount failed: %s\n", strerror(errno));
1135     close(fd);
1136     return 1;
1137     }
1138    
1139     if (chroot(".") || chdir("/")) {
1140     eprintf("switchroot: chroot() failed: %s\n", strerror(errno));
1141     close(fd);
1142     return 1;
1143     }
1144    
1145     /* release the old "/" */
1146     close(fd);
1147    
1148     if ((fd = open("/dev/console", O_RDWR)) < 0) {
1149     eprintf("ERROR opening /dev/console: %s\n", strerror(errno));
1150     eprintf("Trying to use fd 0 instead.\n");
1151     fd = dup2(0, 3);
1152     close(0);
1153     } else {
1154     dup2(fd, 3);
1155     close(fd);
1156     close(0);
1157     fd = 3;
1158     dup2(fd, 0);
1159     }
1160     close(1);
1161     dup2(fd, 1);
1162     close(2);
1163     dup2(fd, 2);
1164     close(fd);
1165    
1166     if (init == NULL) {
1167     for (i = 0; initprogs[i] != NULL; i++) {
1168     if (!access(initprogs[i], X_OK)) {
1169     init = strdup(initprogs[i]);
1170     break;
1171     }
1172     }
1173     }
1174     i = 0;
1175    
1176     initargs = (char **)calloc(MAX_INIT_ARGS+1, sizeof (char *));
1177     if (cmdline && init) {
1178     initargs[i++] = strdup(init);
1179     } else {
1180     cmdline = init;
1181     initargs[0] = NULL;
1182     }
1183    
1184     if (cmdline != NULL) {
1185     char * chptr, * start;
1186    
1187     start = chptr = cmdline;
1188     for (; (i < MAX_INIT_ARGS) && (*start != '\0'); i++) {
1189     while (*chptr && !isspace(*chptr)) chptr++;
1190     if (*chptr != '\0') *(chptr++) = '\0';
1191     /*
1192     * On x86_64, the kernel adds a magic command line parameter
1193     * *after* everything you pass. Bash doesn't know what "console="
1194     * means, so it exits, init gets killed, etc, etc. Bad news.
1195     *
1196     * Apparently being removed "soon", but for now, nash needs to
1197     * special case it.
1198     */
1199     if (cmdline == init && !strncmp(start, "console=", 8)) {
1200     if (!*chptr)
1201     initargs[i] = NULL;
1202     else
1203     i--;
1204     start = chptr;
1205     continue;
1206     }
1207     initargs[i] = strdup(start);
1208     start = chptr;
1209     }
1210     }
1211    
1212     initargs[i] = NULL;
1213    
1214     if (access(initargs[0], X_OK)) {
1215     eprintf("WARNING: can't access %s\n", initargs[0]);
1216     }
1217     execv(initargs[0], initargs);
1218    
1219     eprintf("exec of init (%s) failed!!!: %s\n", initargs[0], strerror(errno));
1220     return 1;
1221     }
1222    
1223     static int
1224     isEchoQuiet(int fd)
1225     {
1226     if (!reallyquiet)
1227     return 0;
1228     if (fd != 1)
1229     return 0;
1230     return 1;
1231     }
1232    
1233     static int
1234     echoCommand(char * cmd, char * end)
1235     {
1236     char * args[256];
1237     char ** nextArg = args;
1238     int outFd = 1;
1239     int num = 0;
1240     int i;
1241     int newline = 1;
1242     int length = 0;
1243     char *string;
1244    
1245     if (testing)
1246     qprintf("(echo) ");
1247    
1248     while ((cmd = getArg(cmd, end, nextArg))) {
1249     if (!strncmp("-n", *nextArg, MAX(2, strlen(*nextArg)))) {
1250     newline = 0;
1251     } else {
1252     length += strlen(*nextArg);
1253     nextArg++, num++;
1254     }
1255     }
1256     length += num + 1;
1257    
1258     if ((nextArg - args >= 2) && !strcmp(*(nextArg - 2), ">")) {
1259     outFd = open(*(nextArg - 1), O_WRONLY | O_CREAT | O_TRUNC, 0644);
1260     if (outFd < 0) {
1261     eprintf("echo: cannot open %s for write: %s\n", *(nextArg - 1),
1262     strerror(errno));
1263     return 1;
1264     }
1265    
1266     newline = 0;
1267     num -= 2;
1268     }
1269     string = (char *)calloc(length, sizeof (char));
1270     *string = '\0';
1271     for (i = 0; i < num;i ++) {
1272     if (i) strcat(string, " ");
1273     strncat(string, args[i], strlen(args[i]));
1274     }
1275    
1276     if (newline) strcat(string, "\n");
1277     if (!isEchoQuiet(outFd)) write(outFd, string, strlen(string));
1278    
1279     if (outFd != 1) close(outFd);
1280     free(string);
1281    
1282     return 0;
1283     }
1284    
1285     static int
1286     umountCommand(char * cmd, char * end)
1287     {
1288     char * path;
1289    
1290     if (!(cmd = getArg(cmd, end, &path))) {
1291     eprintf("umount: path expected\n");
1292     return 1;
1293     }
1294    
1295     if (cmd < end) {
1296     eprintf("umount: unexpected arguments\n");
1297     return 1;
1298     }
1299    
1300     if (umount(path) < 0) {
1301     eprintf("umount %s failed: %s\n", path, strerror(errno));
1302     return 1;
1303     }
1304    
1305     return 0;
1306     }
1307    
1308     static int
1309     mkpathbyspec(char * spec, char * path)
1310     {
1311     int major, minor;
1312    
1313     if (!spec)
1314     return -1;
1315    
1316     if (!strncmp(spec, "LABEL=", 6)) {
1317     if (get_spec_by_volume_label(spec + 6, &major, &minor)) {
1318     if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {
1319     eprintf("mkdev: cannot create device %s (%d,%d)\n",
1320     path, major, minor);
1321     return 1;
1322     }
1323    
1324     qprintf("created path for %s: %d/%d\n", spec, major, minor);
1325     return 0;
1326     }
1327    
1328     eprintf("label %s not found\n", spec + 6);
1329     return 1;
1330     }
1331    
1332     if (!strncmp(spec, "UUID=", 5)) {
1333     if (get_spec_by_uuid(spec+5, &major, &minor)) {
1334     if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {
1335     eprintf("mkdev: cannot create device %s (%d,%d)\n",
1336     path, major, minor);
1337     return 1;
1338     }
1339    
1340     return 0;
1341     }
1342    
1343     eprintf("mkdev: UUID %s not found\n", spec+5);
1344     return 1;
1345    
1346     }
1347     #if 0
1348     qprintf("mkdev: '%s' is not a UUID or LABEL spec\n", spec);
1349     #endif
1350     return -1;
1351     }
1352    
1353     /* 2.6 magic swsusp stuff */
1354     static int
1355     resumeCommand(char * cmd, char * end)
1356     {
1357     char * resumedev = NULL;
1358     char * resume = NULL;
1359     int fd;
1360     struct stat sb;
1361     char buf[25];
1362    
1363     if (!(cmd = getArg(cmd, end, &resume))) {
1364     eprintf("resume: resume device expected\n");
1365     return 1;
1366     }
1367    
1368     if (access("/sys/power/resume", W_OK)) {
1369     /* eprintf("/sys/power/resume doesn't exist, can't resume!\n");*/
1370     return 0;
1371     }
1372    
1373     if (strstr(getKernelCmdLine(), "noresume")) {
1374     qprintf("noresume passed, not resuming...\n");
1375     return 0;
1376     }
1377    
1378     resumedev = getKernelArg("resume");
1379     if (resumedev == NULL) {
1380     resumedev = resume;
1381     }
1382    
1383     qprintf("Trying to resume from %s\n", resumedev);
1384    
1385     if (mkpathbyspec(resumedev, "/dev/swsuspresume") == 0)
1386     resumedev = strdup("/dev/swsuspresume");
1387    
1388     if (access(resumedev, R_OK)) {
1389     eprintf("Unable to access resume device (%s)\n", resumedev);
1390     return 1;
1391     }
1392    
1393     if ((fd = open(resumedev, O_RDONLY)) < 0)
1394     return 1;
1395     if (lseek(fd, getpagesize() - 10, SEEK_SET) != getpagesize() - 10)
1396     return 1;
1397     if (read(fd, &buf, 6) != 6)
1398     return 1;
1399     if (strncmp(buf, "S1SUSP", 6) && strncmp(buf, "S2SUSP", 6)) {
1400     qprintf("No suspend signature on swap, not resuming.\n");
1401     return 1;
1402     }
1403    
1404     if (fstat(fd, &sb))
1405     return 1;
1406     close(fd);
1407    
1408     printf("Resuming from %s.\n", resumedev);
1409     fflush(stdout);
1410     fd = open("/sys/power/resume", O_WRONLY);
1411     memset(buf, '\0', 20);
1412     snprintf(buf, 20, "%d:%d", major(sb.st_rdev), minor(sb.st_rdev));
1413     write(fd, buf, 20);
1414     close(fd);
1415    
1416     eprintf("Resume failed. Continuing with normal startup.\n");
1417     return 0;
1418     }
1419    
1420     static int
1421     mkrootdevCommand(char *cmd, char *end)
1422     {
1423     char *chptr = NULL, *root;
1424     int i, devNum;
1425     FILE *fstab;
1426     struct mntent mnt = {
1427     .mnt_fsname = "/dev/root",
1428     .mnt_dir = "/sysroot",
1429     .mnt_type = NULL,
1430     .mnt_opts = NULL,
1431     .mnt_freq = 0,
1432     .mnt_passno = 0
1433     };
1434    
1435     root = getKernelArg("root");
1436     if (root) {
1437     char c;
1438     chptr = root;
1439     while (*chptr && !isspace(*chptr))
1440     chptr++;
1441     c = *chptr;
1442     *chptr = '\0';
1443     root = strdupa(root);
1444     *chptr = c;
1445     chptr = NULL;
1446     }
1447    
1448     i = 0;
1449     while ((cmd = getArg(cmd, end, &chptr))) {
1450     if (!strcmp(chptr, "-t")) {
1451     cmd = getArg(cmd, end, &mnt.mnt_type);
1452     if (!cmd) {
1453     eprintf("mkrootdev: expected fs type\n");
1454     return 1;
1455     }
1456     } else if (!strcmp(chptr, "-o")) {
1457     cmd = getArg(cmd, end, &mnt.mnt_opts);
1458     if (!cmd) {
1459     eprintf("mkrootdev: expected device name\n");
1460     return 1;
1461     }
1462     } else if (root) {
1463     if (i) {
1464     eprintf("mkrootdev: unexpected arguments\n");
1465     eprintf("cmd: %p end: %p\n", cmd, end);
1466     eprintf("cmd: %s\n", cmd);
1467     return 1;
1468     }
1469     /* if we get here, we got root from the kernel command line,
1470     so we don't _really_ care that there wasn't one on the
1471     mkrootdev command line. */
1472     i++;
1473     } else {
1474     root = chptr;
1475     i++;
1476     }
1477     }
1478     if (!root) {
1479     eprintf("mkrootdev: expected device name\n");
1480     return 1;
1481     }
1482    
1483     if (!mnt.mnt_type) {
1484     eprintf("mkrootdev: expected fs type\n");
1485     return 1;
1486     }
1487     if (!mnt.mnt_opts) {
1488     eprintf("mkrootdev: expected fs options\n");
1489     return 1;
1490     }
1491    
1492     umask(0122);
1493     fstab = fopen("/fstab", "w+");
1494     if (!fstab) {
1495     eprintf("mkrootdev: could not create fstab: %s\n", strerror(errno));
1496     return 1;
1497     }
1498     addmntent(fstab, &mnt);
1499     fclose(fstab);
1500    
1501     if ((i = mkpathbyspec(root, "/dev/root")) != -1)
1502     return i;
1503    
1504     if (root)
1505     devNum = name_to_dev_t(root);
1506    
1507     if (smartmknod("/dev/root", S_IFBLK | 0700, devNum)) {
1508     eprintf("mkrootdev: mknod /dev/root 0x%08x failed: %s\n", devNum,
1509     strerror(errno));
1510     return 1;
1511     }
1512    
1513     return 0;
1514     }
1515    
1516     static int
1517     mkdirCommand(char * cmd, char * end)
1518     {
1519     char * dir;
1520     int ignoreExists = 0;
1521    
1522     cmd = getArg(cmd, end, &dir);
1523    
1524     if (cmd && !strcmp(dir, "-p")) {
1525     ignoreExists = 1;
1526     cmd = getArg(cmd, end, &dir);
1527     }
1528    
1529     if (!cmd) {
1530     eprintf("mkdir: directory expected\n");
1531     return 1;
1532     }
1533    
1534     if (mkdir(dir, 0755)) {
1535     if (!ignoreExists && errno == EEXIST) {
1536     eprintf("mkdir: failed to create %s: %s\n", dir, strerror(errno));
1537     return 1;
1538     }
1539     }
1540    
1541     return 0;
1542     }
1543    
1544     static int
1545     accessCommand(char * cmd, char * end)
1546     {
1547     char * permStr;
1548     int perms = 0;
1549     char * file = NULL;
1550    
1551     cmd = getArg(cmd, end, &permStr);
1552     if (cmd) cmd = getArg(cmd, end, &file);
1553    
1554     if (!cmd || *permStr != '-') {
1555     eprintf("usage: access -[perm] file\n");
1556     return 1;
1557     }
1558    
1559     permStr++;
1560     while (*permStr) {
1561     switch (*permStr) {
1562     case 'r': perms |= R_OK; break;
1563     case 'w': perms |= W_OK; break;
1564     case 'x': perms |= X_OK; break;
1565     case 'f': perms |= F_OK; break;
1566     default:
1567     eprintf("perms must be -[r][w][x][f]\n");
1568     return 1;
1569     }
1570    
1571     permStr++;
1572     }
1573    
1574     if ((file == NULL) || (access(file, perms)))
1575     return 1;
1576    
1577     return 0;
1578     }
1579    
1580     static int
1581     sleepCommand(char * cmd, char * end)
1582     {
1583     char *delaystr;
1584     int delay;
1585    
1586     if (!(cmd = getArg(cmd, end, &delaystr))) {
1587     eprintf("sleep: delay expected\n");
1588     return 1;
1589     }
1590    
1591     delay = atoi(delaystr);
1592     sleep(delay);
1593    
1594     return 0;
1595     }
1596    
1597     static int
1598     readlinkCommand(char * cmd, char * end)
1599     {
1600     char * path;
1601     char * buf, * respath, * fullpath;
1602     struct stat sb;
1603     int rc = 0;
1604    
1605     if (!(cmd = getArg(cmd, end, &path))) {
1606     eprintf("readlink: file expected\n");
1607     return 1;
1608     }
1609    
1610     if (lstat(path, &sb) == -1) {
1611     eprintf("unable to stat %s: %s\n", path, strerror(errno));
1612     return 1;
1613     }
1614    
1615     if (!S_ISLNK(sb.st_mode)) {
1616     printf("%s\n", path);
1617     return 0;
1618     }
1619    
1620     buf = calloc(512, sizeof (char));
1621     if (readlink(path, buf, 512) == -1) {
1622     eprintf("error readlink %s: %s\n", path, strerror(errno));
1623     free(buf);
1624     return 1;
1625     }
1626    
1627     /* symlink is absolute */
1628     if (buf[0] == '/') {
1629     printf("%s\n", buf);
1630     free(buf);
1631     return 0;
1632     }
1633    
1634     /* nope, need to handle the relative symlink case too */
1635     respath = strrchr(path, '/');
1636     if (respath) {
1637     *respath = '\0';
1638     }
1639    
1640     fullpath = calloc(512, sizeof (char));
1641     /* and normalize it */
1642     snprintf(fullpath, 512, "%s/%s", path, buf);
1643     respath = NULL;
1644     respath = canonicalize_file_name(fullpath);
1645     if (respath == NULL) {
1646     eprintf("error resolving symbolic link %s: %s\n", fullpath,
1647     strerror(errno));
1648     rc = 1;
1649     goto readlinkout;
1650     }
1651    
1652     printf("%s\n", respath);
1653     free(respath);
1654     readlinkout:
1655     free(buf);
1656     free(fullpath);
1657     return rc;
1658     }
1659    
1660     static int
1661     doFind(char * dirName, char * name)
1662     {
1663     struct stat sb;
1664     DIR * dir;
1665     struct dirent * d;
1666     char * strBuf = alloca(strlen(dirName) + 1024);
1667    
1668     if (!(dir = opendir(dirName))) {
1669     eprintf("error opening %s: %s\n", dirName, strerror(errno));
1670     return 0;
1671     }
1672    
1673     errno = 0;
1674     while ((d = readdir(dir))) {
1675     errno = 0;
1676    
1677     strcpy(strBuf, dirName);
1678     strcat(strBuf, "/");
1679     strcat(strBuf, d->d_name);
1680    
1681     if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
1682     errno = 0;
1683     continue;
1684     }
1685    
1686     if (!name || !strcmp(d->d_name, name))
1687     printf("%s\n", strBuf);
1688    
1689     if (lstat(strBuf, &sb)) {
1690     eprintf("failed to stat %s: %s\n", strBuf, strerror(errno));
1691     errno = 0;
1692     continue;
1693     }
1694    
1695     if (S_ISDIR(sb.st_mode))
1696     doFind(strBuf, name);
1697     }
1698    
1699     if (errno) {
1700     closedir(dir);
1701     eprintf("error reading from %s: %s\n", dirName, strerror(errno));
1702     return 1;
1703     }
1704    
1705     closedir(dir);
1706    
1707     return 0;
1708     }
1709    
1710     static int
1711     findCommand(char * cmd, char * end)
1712     {
1713     char * dir;
1714     char * name = NULL;
1715    
1716     cmd = getArg(cmd, end, &dir);
1717     if (cmd) cmd = getArg(cmd, end, &name);
1718     if (cmd) {
1719     if (strcmp(name, "-name")) {
1720     eprintf("usage: find [path] -name [file]\n");
1721     return 1;
1722     }
1723     if (cmd) cmd = getArg(cmd, end, &name);
1724     if (!cmd && !name) {
1725     eprintf("usage: find [path] -name [file]\n");
1726     return 1;
1727     }
1728     }
1729    
1730     return doFind(dir, name);
1731     }
1732    
1733     static int
1734     findlodevCommand(char * cmd, char * end)
1735     {
1736     char devName[20];
1737     int devNum;
1738     int fd;
1739     struct loop_info loopInfo;
1740     char separator[2] = "";
1741    
1742     if (*end != '\n') {
1743     eprintf("usage: findlodev\n");
1744     return 1;
1745     }
1746    
1747     if (!access("/dev/.devfsd", X_OK))
1748     strcpy(separator, "/");
1749    
1750     for (devNum = 0; devNum < 256; devNum++) {
1751     sprintf(devName, "/dev/loop%s%d", separator, devNum);
1752     if ((fd = open(devName, O_RDONLY)) < 0)
1753     return 0;
1754    
1755     if (ioctl(fd, LOOP_GET_STATUS, &loopInfo)) {
1756     close(fd);
1757     printf("%s\n", devName);
1758     return 0;
1759     }
1760    
1761     close(fd);
1762     }
1763    
1764     return 0;
1765     }
1766    
1767     static int
1768     mknodCommand(char * cmd, char * end)
1769     {
1770     char * path, * type;
1771     char * majorStr, * minorStr;
1772     int major;
1773     int minor;
1774     char * chptr;
1775     mode_t mode;
1776    
1777     cmd = getArg(cmd, end, &path);
1778     cmd = getArg(cmd, end, &type);
1779     cmd = getArg(cmd, end, &majorStr);
1780     cmd = getArg(cmd, end, &minorStr);
1781     if (!minorStr) {
1782     eprintf("mknod: usage mknod <path> [c|b] <major> <minor>\n");
1783     return 1;
1784     }
1785    
1786     if (!strcmp(type, "b")) {
1787     mode = S_IFBLK;
1788     } else if (!strcmp(type, "c")) {
1789     mode = S_IFCHR;
1790     } else {
1791     eprintf("mknod: invalid type\n");
1792     return 1;
1793     }
1794    
1795     major = strtol(majorStr, &chptr, 10);
1796     if (*chptr) {
1797     eprintf("invalid major number\n");
1798     return 1;
1799     }
1800    
1801     minor = strtol(minorStr, &chptr, 10);
1802     if (*chptr) {
1803     eprintf("invalid minor number\n");
1804     return 1;
1805     }
1806    
1807     if (smartmknod(path, mode | 0600, makedev(major, minor))) {
1808     eprintf("mknod: failed to create %s: %s\n", path, strerror(errno));
1809     return 1;
1810     }
1811    
1812     return 0;
1813     }
1814    
1815     static int
1816     getDevNumFromProc(char * file, char * device)
1817     {
1818     char buf[32768], line[4096];
1819     char * start, *end;
1820     int num;
1821     int fd;
1822    
1823     if ((fd = open(file, O_RDONLY)) == -1) {
1824     eprintf("can't open file %s: %s\n", file, strerror(errno));
1825     return -1;
1826     }
1827    
1828     num = read(fd, buf, sizeof(buf));
1829     if (num < 1) {
1830     close(fd);
1831     eprintf("failed to read %s: %s\n", file, strerror(errno));
1832     return -1;
1833     }
1834     buf[num] = '\0';
1835     close(fd);
1836    
1837     start = buf;
1838     end = strchr(start, '\n');
1839     while (start && end) {
1840     *end++ = '\0';
1841     if ((sscanf(start, "%d %s", &num, line)) == 2) {
1842     if (!strncmp(device, line, strlen(device)))
1843     return num;
1844     }
1845     start = end;
1846     end = strchr(start, '\n');
1847     }
1848     return -1;
1849     }
1850    
1851     static int
1852     mkDMNodCommand(char * cmd, char * end)
1853     {
1854     int major = getDevNumFromProc("/proc/devices", "misc");
1855     int minor = getDevNumFromProc("/proc/misc", "device-mapper");
1856    
1857     if ((major == -1) || (minor == -1)) {
1858     eprintf("Unable to find device-mapper major/minor\n");
1859     return 1;
1860     }
1861    
1862     if (!access("/dev/mapper/control", R_OK)) {
1863     struct stat sb;
1864     if (stat("/dev/mapper/control", &sb) == 0) {
1865     if (S_ISCHR(sb.st_mode) && (sb.st_rdev == makedev(major, minor)))
1866     return 0;
1867     }
1868    
1869     unlink("/dev/mapper/control");
1870     }
1871    
1872     if (smartmknod("/dev/mapper/control", S_IFCHR | 0600,
1873     makedev(major, minor))) {
1874     eprintf("failed to create /dev/mapper/control\n");
1875     return 1;
1876     }
1877    
1878     return 0;
1879     }
1880    
1881     static int
1882     parse_sysfs_devnum(const char *path, dev_t *dev)
1883     {
1884     char *first = NULL, *second;
1885     int major, minor;
1886     int fd, len = strlen(path);
1887     char devname[len + 5];
1888    
1889     sprintf(devname, "%s/dev", path);
1890     fd = open(devname, O_RDONLY);
1891     if (fd < 0) {
1892     #if 0
1893     eprintf("open on %s failed: %s\n", devname, strerror(errno));
1894     #endif
1895     return -1;
1896     }
1897    
1898     len = readFD(fd, &first);
1899    
1900     close(fd);
1901    
1902     second = strchr(first, ':');
1903     *second++ = '\0';
1904    
1905     errno = 0;
1906     major = strtol(first, NULL, 10);
1907    
1908     errno = 0;
1909     minor = strtol(second, NULL, 10);
1910     free(first);
1911    
1912     *dev = makedev(major, minor);
1913     return 0;
1914     }
1915    
1916     static void
1917     sysfs_blkdev_probe(const char *dirname, const char *name)
1918     {
1919     char *path = NULL, *devpath = NULL;
1920     dev_t dev = 0;
1921     int ret;
1922     DIR *dir;
1923     struct dirent *dent;
1924    
1925     asprintf(&path, "%s/%s", dirname, name);
1926     #if 0
1927     qprintf("Testing %s for block device.\n", path);
1928     #endif
1929    
1930     ret = parse_sysfs_devnum(path, &dev);
1931     if (ret < 0) {
1932     free(path);
1933     return;
1934     }
1935    
1936     asprintf(&devpath, "/dev/%s", name);
1937    
1938     smartmknod(devpath, S_IFBLK | 0700, dev);
1939     free(devpath);
1940    
1941     dir = opendir(path);
1942     if (dir == NULL) {
1943     free(path);
1944     return;
1945     }
1946    
1947     for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1948     if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1949     continue;
1950    
1951     sysfs_blkdev_probe(path, dent->d_name);
1952     }
1953     free(path);
1954     }
1955    
1956     static int
1957     mkblkdevsCommand(char * cmd, char * end)
1958     {
1959     DIR *dir;
1960     struct dirent *dent;
1961    
1962     if (cmd < end) {
1963     eprintf("mkblkdevs: unexpected arguments\n");
1964     return 1;
1965     }
1966    
1967     dir = opendir("/sys/block");
1968     if (dir == NULL)
1969     return -1;
1970    
1971     for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1972     if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1973     continue;
1974    
1975     sysfs_blkdev_probe("/sys/block", dent->d_name);
1976     }
1977     return 1;
1978     }
1979    
1980     static int
1981     setQuietCommand(char * cmd, char * end)
1982     {
1983     char *quietcmd;
1984    
1985     quietcmd = getKernelArg("quiet");
1986     if (quietcmd)
1987     reallyquiet = 1;
1988    
1989     quietcmd = getKernelArg("noquiet");
1990     if (quietcmd)
1991     reallyquiet = 0;
1992    
1993     /* reallyquiet may be set elsewhere */
1994     if (reallyquiet)
1995     quiet = 1;
1996    
1997     return 0;
1998     }
1999    
2000     struct commandHandler {
2001     char *name;
2002     int (*fp)(char *cmd, char *end);
2003     };
2004    
2005     static const struct commandHandler handlers[] = {
2006     { "mount", mountCommand },
2007     { "losetup", losetupCommand },
2008     { "echo", echoCommand },
2009     { "raidautorun", raidautorunCommand },
2010     { "umount", umountCommand },
2011     { "exec", execCommand },
2012     { "mkdir", mkdirCommand },
2013     { "access", accessCommand },
2014     { "find", findCommand },
2015     { "findlodev", findlodevCommand },
2016     { "showlabels", display_uuid_cache },
2017     { "sleep", sleepCommand },
2018     { "mknod", mknodCommand },
2019     { "mkdmnod", mkDMNodCommand },
2020     { "readlink", readlinkCommand },
2021     { "setquiet", setQuietCommand },
2022     { "ln", lnCommand },
2023     { "mkblkdevs", mkblkdevsCommand },
2024     { "resume", resumeCommand },
2025     { "mkrootdev", mkrootdevCommand },
2026     { "setuproot", setuprootCommand },
2027     { "switchroot", switchrootCommand },
2028     #ifdef DEBUG
2029     { "cat", catCommand },
2030     { "ls", lsCommand },
2031     #endif
2032     { NULL, },
2033     };
2034    
2035     static const struct commandHandler *
2036     getCommandHandler(const char *name)
2037     {
2038     const struct commandHandler *handler = NULL;
2039    
2040     for (handler = &handlers[0]; handler->name; handler++)
2041     if (!strncmp(name, handler->name, strlen(handler->name)))
2042     return handler;
2043     return handler;
2044     }
2045    
2046     static int
2047     runStartup(int fd, char *name)
2048     {
2049     char *contents;
2050     int i;
2051     char * start, * end;
2052     char * chptr;
2053     int rc;
2054     const struct commandHandler *handler;
2055    
2056     i = readFD(fd, &contents);
2057    
2058     if (i < 0) {
2059     eprintf("Failed to read startup file %s", name);
2060     return 1;
2061     }
2062     close(fd);
2063    
2064     start = contents;
2065     while (*start) {
2066     while (isspace(*start) && *start && (*start != '\n')) start++;
2067    
2068     if (*start == '#')
2069     while (*start && (*start != '\n')) start++;
2070    
2071     if (*start == '\n') {
2072     start++;
2073     continue;
2074     }
2075    
2076     if (!*start) {
2077     eprintf("(last line in %s is empty)\n", name);
2078     continue;
2079     }
2080    
2081     /* start points to the beginning of the command */
2082     end = start + 1;
2083     while (*end && (*end != '\n')) end++;
2084     if (!*end) {
2085     eprintf("(last line in %s missing newline -- skipping)\n", name);
2086     start = end;
2087     continue;
2088     }
2089    
2090     /* end points to the \n at the end of the command */
2091    
2092     chptr = start;
2093     while (chptr < end && !isspace(*chptr)) chptr++;
2094    
2095     i = 0;
2096     rc = 1;
2097     *(chptr++) = '\0';
2098     if (strncmp(start, "nash-", 5)) {
2099     char *fullPath = NULL;
2100     rc = searchPath(start, &fullPath);
2101     if (rc >= 0) {
2102     rc = otherCommand(fullPath, chptr, end, 1);
2103     free(fullPath);
2104     } else
2105     i = 1;
2106     } else {
2107     start += 5;
2108     i = 1;
2109     }
2110    
2111     if (i == 1) {
2112     handler = getCommandHandler(start);
2113     if (handler->name != NULL)
2114     rc = (handler->fp)(chptr, end);
2115     }
2116     start = end + 1;
2117     }
2118    
2119     free(contents);
2120     return rc;
2121     }
2122    
2123     int main(int argc, char **argv) {
2124     int fd = 0;
2125     char * name;
2126     int rc;
2127     int force = 0;
2128    
2129     name = strrchr(argv[0], '/');
2130     if (!name)
2131     name = argv[0];
2132     else
2133     name++;
2134    
2135     if (!strcmp(name, "modprobe"))
2136     exit(0);
2137     if (!strcmp(name, "hotplug")) {
2138     argv[0] = strdup("/sbin/udev");
2139     execv(argv[0], argv);
2140     eprintf("ERROR: exec of udev failed!\n");
2141     exit(1);
2142     }
2143    
2144     testing = (getppid() != 0) && (getppid() != 1);
2145     argv++, argc--;
2146    
2147     while (argc && **argv == '-') {
2148     if (!strcmp(*argv, "--forcequiet")) {
2149     force = 1;
2150     quiet = 1;
2151     argv++, argc--;
2152     testing = 0;
2153     } else if (!strcmp(*argv, "--force")) {
2154     force = 1;
2155     argv++, argc--;
2156     testing = 0;
2157     } else if (!strcmp(*argv, "--quiet")) {
2158     quiet = 1;
2159     argv++, argc--;
2160     } else if (!strcmp(*argv, "--reallyquiet")) {
2161     reallyquiet = 1;
2162     argv++, argc--;
2163     } else {
2164     eprintf("unknown argument %s\n", *argv);
2165     return 1;
2166     }
2167     }
2168    
2169     if (force)
2170     qprintf("(forcing normal run)\n");
2171    
2172     if (testing)
2173     qprintf("(running in test mode).\n");
2174    
2175     qprintf("Red Hat nash version %s starting\n", VERSION);
2176    
2177     if (*argv) {
2178     fd = open(*argv, O_RDONLY, 0);
2179     if (fd < 0) {
2180     eprintf("nash: cannot open %s: %s\n", *argv, strerror(errno));
2181     exit(1);
2182     }
2183     }
2184    
2185     /* runStartup closes fd */
2186     rc = runStartup(fd, *argv);
2187    
2188     return rc;
2189     }