Magellan Linux

Contents of /tags/mkinitrd-6_1_12/nash/nash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 939 - (show annotations) (download)
Tue Nov 17 21:24:51 2009 UTC (14 years, 5 months ago) by niro
File MIME type: text/plain
File size: 48197 byte(s)
tagged 'mkinitrd-6_1_12'
1 /*
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 }