]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/nash/nash.c
Firewallhitgraphs gefixt.
[people/pmueller/ipfire-2.x.git] / src / nash / nash.c
CommitLineData
330345c2
MT
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#include <ctype.h>
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <net/if.h>
31#include <signal.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/ioctl.h>
36#include <sys/mount.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/time.h>
40#include <sys/types.h>
41#include <sys/un.h>
42#include <sys/wait.h>
43#include <unistd.h>
44#include <sys/ioctl.h>
45#include <sys/reboot.h>
46#include <termios.h>
47
48#include <asm/unistd.h>
49
50#include "mount_by_label.h"
51
52/* Need to tell loop.h what the actual dev_t type is. */
53#undef dev_t
54#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
55#define dev_t unsigned int
56#else
57#define dev_t unsigned short
58#endif
59#include <linux/loop.h>
60#undef dev_t
61#define dev_t dev_t
62
63#define syslog klogctl
64
65#include <linux/cdrom.h>
66#define MD_MAJOR 9
67#include <linux/raid/md_u.h>
68
69#ifndef RAID_AUTORUN
70#define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
71#endif
72
73#ifndef MS_REMOUNT
74#define MS_REMOUNT 32
75#endif
76
77#ifndef MS_BIND
78#define MS_BIND 4096
79#endif
80
81#ifndef MS_MOVE
82#define MS_MOVE 8192
83#endif
84
85#ifndef MNT_FORCE
86#define MNT_FORCE 0x1
87#endif
88
89#ifndef MNT_DETACH
90#define MNT_DETACH 0x2
91#endif
92
93extern dev_t name_to_dev_t(char *name);
94extern int display_uuid_cache(void);
95
96#define MAX(a, b) ((a) > (b) ? a : b)
97
98int testing = 0, quiet = 0, reallyquiet = 0;
99
100#define PATH "/usr/bin:/bin:/sbin:/usr/sbin"
101
102char * env[] = {
103 "PATH=" PATH,
104 "LVM_SUPPRESS_FD_WARNINGS=1",
105 NULL
106};
107
108int smartmknod(char * device, mode_t mode, dev_t dev) {
109 char buf[256];
110 char * end;
111
112 strncpy(buf, device, 256);
113
114 end = buf;
115 while (*end) {
116 if (*end == '/') {
117 *end = '\0';
118 if (access(buf, F_OK) && errno == ENOENT)
119 mkdir(buf, 0755);
120 *end = '/';
121 }
122
123 end++;
124 }
125
126 return mknod(device, mode, dev);
127}
128
129char * getArg(char * cmd, char * end, char ** arg) {
130 char quote = '\0';
131
132 if (!cmd || cmd >= end) return NULL;
133
134 while (isspace(*cmd) && cmd < end) cmd++;
135 if (cmd >= end) return NULL;
136
137 if (*cmd == '"')
138 cmd++, quote = '"';
139 else if (*cmd == '\'')
140 cmd++, quote = '\'';
141
142 if (quote) {
143 *arg = cmd;
144
145 /* This doesn't support \ escapes */
146 while (cmd < end && *cmd != quote) cmd++;
147
148 if (cmd == end) {
149 printf("error: quote mismatch for %s\n", *arg);
150 return NULL;
151 }
152
153 *cmd = '\0';
154 cmd++;
155 } else {
156 *arg = cmd;
157 while (!isspace(*cmd) && cmd < end) cmd++;
158 *cmd = '\0';
159 if (**arg == '$')
160 *arg = getenv(*arg+1);
161 if (*arg == NULL)
162 *arg = "";
163 }
164
165 cmd++;
166
167 while (isspace(*cmd)) cmd++;
168
169 return cmd;
170}
171
172/* taken from anaconda/isys/probe.c */
173static int readFD (int fd, char **buf)
174{
175 char *p;
176 size_t size = 4096;
177 int s, filesize;
178
179 *buf = malloc (size);
180 if (*buf == 0)
181 return -1;
182
183 filesize = 0;
184 do {
185 p = &(*buf) [filesize];
186 s = read (fd, p, 4096);
187 if (s < 0)
188 break;
189 filesize += s;
190 if (s != 4096)
191 break;
192 size += 4096;
193 *buf = realloc (*buf, size);
194 } while (1);
195
196 if (filesize == 0 && s < 0) {
197 free (*buf);
198 *buf = NULL;
199 return -1;
200 }
201
202 return filesize;
203}
204
205#ifdef __powerpc__
206#define CMDLINESIZE 256
207#else
208#define CMDLINESIZE 1024
209#endif
210
211/* get the contents of the kernel command line from /proc/cmdline */
212static char * getKernelCmdLine(void) {
213 int fd, i;
214 char * buf;
215
216 fd = open("/proc/cmdline", O_RDONLY, 0);
217 if (fd < 0) {
218 printf("getKernelCmdLine: failed to open /proc/cmdline: %d\n", errno);
219 return NULL;
220 }
221
222 buf = malloc(CMDLINESIZE);
223 if (!buf)
224 return buf;
225
226 i = read(fd, buf, CMDLINESIZE);
227 if (i < 0) {
228 printf("getKernelCmdLine: failed to read /proc/cmdline: %d\n", errno);
229 close(fd);
230 return NULL;
231 }
232
233 close(fd);
234 if (i == 0)
235 buf[0] = '\0';
236 else
237 buf[i - 1] = '\0';
238 return buf;
239}
240
241/* get the start of a kernel arg "arg". returns everything after it
242 * (useful for things like getting the args to init=). so if you only
243 * want one arg, you need to terminate it at the n */
244static char * getKernelArg(char * arg) {
245 char * start, * cmdline;
246
247 cmdline = start = getKernelCmdLine();
248 if (start == NULL) return NULL;
249 while (*start) {
250 if (isspace(*start)) {
251 start++;
252 continue;
253 }
254 if (strncmp(start, arg, strlen(arg)) == 0) {
255 return start + strlen(arg);
256 }
257 while (*++start && !isspace(*start))
258 ;
259 }
260
261 return NULL;
262}
263
264int mountCommand(char * cmd, char * end) {
265 char * fsType = NULL;
266 char * device;
267 char * mntPoint;
268 char * deviceDir = NULL;
269 char * options = NULL;
270 int mustRemove = 0;
271 int mustRemoveDir = 0;
272 int rc = 0;
273 int flags = MS_MGC_VAL;
274 char * newOpts;
275
276 cmd = getArg(cmd, end, &device);
277 if (!cmd) {
278 printf("usage: mount [--ro] [-o <opts>] -t <type> <device> <mntpoint>\n");
279 return 1;
280 }
281
282 while (cmd && *device == '-') {
283 if (!strcmp(device, "--ro")) {
284 flags |= MS_RDONLY;
285 } else if (!strcmp(device, "--bind")) {
286 flags = MS_BIND;
287 fsType = "none";
288 } else if (!strcmp(device, "-o")) {
289 cmd = getArg(cmd, end, &options);
290 if (!cmd) {
291 printf("mount: -o requires arguments\n");
292 return 1;
293 }
294 } else if (!strcmp(device, "-t")) {
295 if (!(cmd = getArg(cmd, end, &fsType))) {
296 printf("mount: missing filesystem type\n");
297 return 1;
298 }
299 }
300
301 cmd = getArg(cmd, end, &device);
302 }
303
304 if (!cmd) {
305 printf("mount: missing device\n");
306 return 1;
307 }
308
309 if (!(cmd = getArg(cmd, end, &mntPoint))) {
310 printf("mount: missing mount point\n");
311 return 1;
312 }
313
314 if (!fsType) {
315 printf("mount: filesystem type expected\n");
316 return 1;
317 }
318
319 if (cmd < end) {
320 printf("mount: unexpected arguments\n");
321 return 1;
322 }
323
324 /* need to deal with options */
325 if (options) {
326 char * end;
327 char * start = options;
328
329 newOpts = alloca(strlen(options) + 1);
330 *newOpts = '\0';
331
332 while (*start) {
333 end = strchr(start, ',');
334 if (!end) {
335 end = start + strlen(start);
336 } else {
337 *end = '\0';
338 end++;
339 }
340
341 if (!strcmp(start, "ro"))
342 flags |= MS_RDONLY;
343 else if (!strcmp(start, "rw"))
344 flags &= ~MS_RDONLY;
345 else if (!strcmp(start, "nosuid"))
346 flags |= MS_NOSUID;
347 else if (!strcmp(start, "suid"))
348 flags &= ~MS_NOSUID;
349 else if (!strcmp(start, "nodev"))
350 flags |= MS_NODEV;
351 else if (!strcmp(start, "dev"))
352 flags &= ~MS_NODEV;
353 else if (!strcmp(start, "noexec"))
354 flags |= MS_NOEXEC;
355 else if (!strcmp(start, "exec"))
356 flags &= ~MS_NOEXEC;
357 else if (!strcmp(start, "sync"))
358 flags |= MS_SYNCHRONOUS;
359 else if (!strcmp(start, "async"))
360 flags &= ~MS_SYNCHRONOUS;
361 else if (!strcmp(start, "nodiratime"))
362 flags |= MS_NODIRATIME;
363 else if (!strcmp(start, "diratime"))
364 flags &= ~MS_NODIRATIME;
365 else if (!strcmp(start, "noatime"))
366 flags |= MS_NOATIME;
367 else if (!strcmp(start, "atime"))
368 flags &= ~MS_NOATIME;
369 else if (!strcmp(start, "remount"))
370 flags |= MS_REMOUNT;
371 else if (!strcmp(start, "defaults"))
372 ;
373 else {
374 if (*newOpts)
375 strcat(newOpts, ",");
376 strcat(newOpts, start);
377 }
378
379 start = end;
380 }
381
382 options = newOpts;
383 }
384
385 if (!strncmp("LABEL=", device, 6)) {
386 int major, minor;
387 char * devName;
388 char * ptr;
389 int i;
390
391 devName = get_spec_by_volume_label(device + 6, &major, &minor);
392
393 if (devName) {
394 device = devName;
395 if (access(device, F_OK)) {
396 ptr = device;
397 i = 0;
398 while (*ptr)
399 if (*ptr++ == '/')
400 i++;
401 if (i > 2) {
402 deviceDir = alloca(strlen(device) + 1);
403 strcpy(deviceDir, device);
404 ptr = deviceDir + (strlen(device) - 1);
405 while (*ptr != '/')
406 *ptr-- = '\0';
407 if (mkdir(deviceDir, 0644)) {
408 printf("mkdir: cannot create directory %s\n", deviceDir);
409 } else {
410 mustRemoveDir = 1;
411 }
412 }
413 if (smartmknod(device, S_IFBLK | 0600, makedev(major, minor))) {
414 printf("mount: cannot create device %s (%d,%d)\n",
415 device, major, minor);
416 return 1;
417 }
418 mustRemove = 1;
419 }
420 }
421 }
422
423 if (testing) {
424 printf("mount %s%s%s-t '%s' '%s' '%s' (%s%s%s%s%s%s%s)\n",
425 options ? "-o '" : "",
426 options ? options : "",
427 options ? "\' " : "",
428 fsType, device, mntPoint,
429 (flags & MS_RDONLY) ? "ro " : "",
430 (flags & MS_NOSUID) ? "nosuid " : "",
431 (flags & MS_NODEV) ? "nodev " : "",
432 (flags & MS_NOEXEC) ? "noexec " : "",
433 (flags & MS_SYNCHRONOUS) ? "sync " : "",
434 (flags & MS_REMOUNT) ? "remount " : "",
435 (flags & MS_NOATIME) ? "noatime " : ""
436 );
437 } else {
438 if (mount(device, mntPoint, fsType, flags, options)) {
439 printf("mount: error %d mounting %s\n", errno, fsType);
440 rc = 1;
441 }
442 }
443
444 if (mustRemove) unlink(device);
445 if (mustRemoveDir) rmdir(deviceDir);
446
447 return rc;
448}
449
450int otherCommand(char * bin, char * cmd, char * end, int doFork) {
451 char ** args;
452 char ** nextArg;
453 int pid, wpid;
454 int status;
455 char fullPath[255];
456 static const char * sysPath = PATH;
457 const char * pathStart;
458 const char * pathEnd;
459 char * stdoutFile = NULL;
460 int stdoutFd = 0;
461
462 args = (char **)malloc(sizeof(char *) * 128);
463 if (!args)
464 return 1;
465 nextArg = args;
466
467 if (!strchr(bin, '/')) {
468 pathStart = sysPath;
469 while (*pathStart) {
470 pathEnd = strchr(pathStart, ':');
471
472 if (!pathEnd) pathEnd = pathStart + strlen(pathStart);
473
474 strncpy(fullPath, pathStart, pathEnd - pathStart);
475 fullPath[pathEnd - pathStart] = '/';
476 strcpy(fullPath + (pathEnd - pathStart + 1), bin);
477
478 pathStart = pathEnd;
479 if (*pathStart) pathStart++;
480
481 if (!access(fullPath, X_OK)) {
482 bin = fullPath;
483 break;
484 }
485 }
486 }
487
488 *nextArg = strdup(bin);
489
490 while (cmd && cmd < end) {
491 nextArg++;
492 cmd = getArg(cmd, end, nextArg);
493 }
494
495 if (cmd) nextArg++;
496 *nextArg = NULL;
497
498 /* if the next-to-last arg is a >, redirect the output properly */
499 if (((nextArg - args) >= 2) && !strcmp(*(nextArg - 2), ">")) {
500 stdoutFile = *(nextArg - 1);
501 *(nextArg - 2) = NULL;
502
503 stdoutFd = open(stdoutFile, O_CREAT | O_RDWR | O_TRUNC, 0600);
504 if (stdoutFd < 0) {
505 printf("nash: failed to open %s: %d\n", stdoutFile, errno);
506 return 1;
507 }
508 }
509
510 if (testing) {
511 printf("%s ", bin);
512 nextArg = args + 1;
513 while (*nextArg)
514 printf(" '%s'", *nextArg++);
515 if (stdoutFile)
516 printf(" (> %s)", stdoutFile);
517 printf("\n");
518 } else {
519 if (!doFork || !(pid = fork())) {
520 /* child */
521 dup2(stdoutFd, 1);
522 execve(args[0], args, env);
523 printf("ERROR: failed in exec of %s\n", args[0]);
524 return 1;
525 }
526
527 close(stdoutFd);
528
529 for (;;) {
530 wpid = wait4(-1, &status, 0, NULL);
531 if (wpid == -1) {
532 printf("ERROR: Failed to wait for process %d\n", wpid);
533 }
534
535 if (wpid != pid)
536 continue;
537
538 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
539 printf("ERROR: %s exited abnormally with value %d ! (pid %d)\n", args[0], WEXITSTATUS(status), pid);
540 return 1;
541 }
542 break;
543 }
544 }
545
546 return 0;
547}
548
549#ifdef DEBUG
550static int lsdir(char *thedir, char * prefix) {
551 DIR * dir;
552 struct dirent * entry;
553 struct stat sb;
554 char * fn;
555
556 if (!(dir = opendir(thedir))) {
557 printf("error opening %s: %d\n", thedir, errno);
558 return 1;
559 }
560
561 fn = malloc(1024);
562 while ((entry = readdir(dir))) {
563 if (entry->d_name[0] == '.')
564 continue;
565 snprintf(fn, 1024, "%s/%s", thedir, entry->d_name);
566 stat(fn, &sb);
567 printf("%s%s", prefix, fn);
568
569 if (S_ISDIR(sb.st_mode)) {
570 char * pfx;
571 pfx = malloc(strlen(prefix) + 3);
572 sprintf(pfx, "%s ", prefix);
573 printf("/\n");
574 } else if (S_ISCHR(sb.st_mode)) {
575 printf(" c %d %d\n", major(sb.st_rdev), minor(sb.st_rdev));
576 } else if (S_ISBLK(sb.st_mode)) {
577 printf(" b %d %d\n", major(sb.st_rdev), minor(sb.st_rdev));
578 } else if (S_ISLNK(sb.st_mode)) {
579 char * target;
580 target = malloc(1024);
581 readlink(fn, target, 1024);
582 printf("->%s\n", target);
583 free(target);
584 } else {
585 printf("\n");
586 }
587 }
588 return 0;
589}
590
591int catCommand(char * cmd, char * end) {
592 char * file;
593 char * buf;
594 int fd;
595
596 if (!(cmd = getArg(cmd, end, &file))) {
597 printf("cat: argument expected\n");
598 return 1;
599 }
600
601 if ((fd = open(file, O_RDONLY)) < 0) {
602 printf("cat: error opening %s: %d\n", file, errno);
603 return 1;
604 }
605
606 buf = malloc(1024);
607 while (read(fd, buf, 1024) > 0) {
608 write(1, buf, 1024);
609 }
610 return 0;
611}
612
613int lsCommand(char * cmd, char * end) {
614 char * dir;
615
616 if (!(cmd = getArg(cmd, end, &dir))) {
617 printf("ls: argument expected\n");
618 return 1;
619 }
620
621 lsdir(dir, "");
622 return 0;
623}
624#endif
625
626int execCommand(char * cmd, char * end) {
627 char * bin;
628
629 if (!(cmd = getArg(cmd, end, &bin))) {
630 printf("exec: argument expected\n");
631 return 1;
632 }
633
634 return otherCommand(bin, cmd, end, 0);
635}
636
637int losetupCommand(char * cmd, char * end) {
638 char * device;
639 char * file;
640 int fd;
641 struct loop_info loopInfo;
642 int dev;
643
644 if (!(cmd = getArg(cmd, end, &device))) {
645 printf("losetup: missing device\n");
646 return 1;
647 }
648
649 if (!(cmd = getArg(cmd, end, &file))) {
650 printf("losetup: missing file\n");
651 return 1;
652 }
653
654 if (cmd < end) {
655 printf("losetup: unexpected arguments\n");
656 return 1;
657 }
658
659 if (testing) {
660 printf("losetup '%s' '%s'\n", device, file);
661 } else {
662 dev = open(device, O_RDWR, 0);
663 if (dev < 0) {
664 printf("losetup: failed to open %s: %d\n", device, errno);
665 return 1;
666 }
667
668 fd = open(file, O_RDWR, 0);
669 if (fd < 0) {
670 printf("losetup: failed to open %s: %d\n", file, errno);
671 close(dev);
672 return 1;
673 }
674
675 if (ioctl(dev, LOOP_SET_FD, (long) fd)) {
676 printf("losetup: LOOP_SET_FD failed: %d\n", errno);
677 close(dev);
678 close(fd);
679 return 1;
680 }
681
682 close(fd);
683
684 memset(&loopInfo, 0, sizeof(loopInfo));
685 strcpy(loopInfo.lo_name, file);
686
687 if (ioctl(dev, LOOP_SET_STATUS, &loopInfo))
688 printf("losetup: LOOP_SET_STATUS failed: %d\n", errno);
689
690 close(dev);
691 }
692
693 return 0;
694}
695
696#define RAID_MAJOR 9
697int raidautorunCommand(char * cmd, char * end) {
698 char * device;
699 int fd;
700
701 if (!(cmd = getArg(cmd, end, &device))) {
702 printf("raidautorun: raid device expected as first argument\n");
703 return 1;
704 }
705
706 if (cmd < end) {
707 printf("raidautorun: unexpected arguments\n");
708 return 1;
709 }
710
711 /* with udev, the raid devices don't exist until they get started.
712 * this won't work so well with raidautorun. so, let's be smart
713 * and create them ourselves if we need to */
714 if (access(device, R_OK & W_OK)) {
715 int minor;
716 if (sscanf(device, "/dev/md%d", &minor) != 1) {
717 printf("raidautorun: unable to autocreate %s\n", device);
718 return 1;
719 }
720
721 if (smartmknod(device, S_IFBLK | 0600, makedev(RAID_MAJOR, minor))) {
722 printf("raidautorun: unable to autocreate %s\n", device);
723 return 1;
724 }
725 }
726
727 fd = open(device, O_RDWR, 0);
728 if (fd < 0) {
729 printf("raidautorun: failed to open %s: %d\n", device, errno);
730 return 1;
731 }
732
733 if (ioctl(fd, RAID_AUTORUN, 0)) {
734 printf("raidautorun: RAID_AUTORUN failed: %d\n", errno);
735 close(fd);
736 return 1;
737 }
738
739 close(fd);
740 return 0;
741}
742
743#ifdef USE_DIET
744extern int pivot_root(char *, char *);
745#endif
746
747static int my_pivot_root(char * one, char * two) {
748#ifdef USE_DIET
749 return pivot_root(one, two);
750#else
751 return syscall(__NR_pivot_root, one, two);
752#endif
753}
754
755int pivotrootCommand(char * cmd, char * end) {
756 char * new;
757 char * old;
758
759 if (!(cmd = getArg(cmd, end, &new))) {
760 printf("pivotroot: new root mount point expected\n");
761 return 1;
762 }
763
764 if (!(cmd = getArg(cmd, end, &old))) {
765 printf("pivotroot: old root mount point expected\n");
766 return 1;
767 }
768
769 if (cmd < end) {
770 printf("pivotroot: unexpected arguments\n");
771 return 1;
772 }
773
774 if (my_pivot_root(new, old)) {
775 printf("pivotroot: pivot_root(%s,%s) failed: %d\n", new, old, errno);
776 return 1;
777 }
778
779 return 0;
780}
781
782#define MAX_INIT_ARGS 32
783/* 2.6 magic not-pivot-root but kind of similar stuff.
784 * This is based on code from klibc/utils/run_init.c
785 */
786int switchrootCommand(char * cmd, char * end) {
787 char * new;
788 const char * initprogs[] = { "/sbin/init", "/etc/init",
789 "/bin/init", "/bin/sh", NULL };
790 char * init, * cmdline = NULL;
791 char ** initargs;
792 /* Don't try to unmount the old "/", there's no way to do it. */
793 const char * umounts[] = { "/dev", "/proc", "/sys", NULL };
794 int fd, i = 0;
795 int moveDev = 0;
796
797 cmd = getArg(cmd, end, &new);
798 if (cmd) {
799 if (!strcmp(new, "--movedev"))
800 moveDev = 1;
801 cmd = getArg(cmd, end, &new);
802 }
803
804 if (!cmd) {
805 printf("switchroot: new root mount point expected\n");
806 return 1;
807 }
808
809 if (chdir(new)) {
810 printf("switchroot: chdir(%s) failed: %d\n", new, errno);
811 return 1;
812 }
813
814 init = getKernelArg("init=");
815 if (init == NULL)
816 cmdline = getKernelCmdLine();
817
818 if (moveDev) {
819 i = 1;
820 mount("/dev", "./dev", NULL, MS_MOVE, NULL);
821 }
822
823 if ((fd = open("./dev/console", O_RDWR)) < 0) {
824 printf("ERROR opening /dev/console!!!!: %d\n", errno);
825 fd = 0;
826 }
827
828 if (dup2(fd, 0) != 0) printf("error dup2'ing fd of %d to 0\n", fd);
829 if (dup2(fd, 1) != 1) printf("error dup2'ing fd of %d to 1\n", fd);
830 if (dup2(fd, 2) != 2) printf("error dup2'ing fd of %d to 2\n", fd);
831 if (fd > 2)
832 close(fd);
833
834 fd = open("/", O_RDONLY);
835 for (; umounts[i] != NULL; i++) {
836 if (!quiet) printf("unmounting old %s\n", umounts[i]);
837 if (umount2(umounts[i], MNT_DETACH)) {
838 printf("ERROR unmounting old %s: %d\n", umounts[i], errno);
839 printf("forcing unmount of %s\n", umounts[i]);
840 umount2(umounts[i], MNT_FORCE);
841 }
842 }
843 i=0;
844
845 if (mount(".", "/", NULL, MS_MOVE, NULL)) {
846 printf("switchroot: mount failed: %d\n", errno);
847 close(fd);
848 return 1;
849 }
850
851 if (chroot(".") || chdir("/")) {
852 printf("switchroot: chroot() failed: %d\n", errno);
853 close(fd);
854 return 1;
855 }
856
857 /* release the old "/" */
858 close(fd);
859
860 if (init == NULL) {
861 int j;
862 for (j = 0; initprogs[j] != NULL; j++) {
863 if (!access(initprogs[j], X_OK)) {
864 init = strdup(initprogs[j]);
865 break;
866 }
867 }
868 }
869
870 initargs = (char **)malloc(sizeof(char *)*(MAX_INIT_ARGS+1));
871 if (cmdline && init) {
872 initargs[i++] = strdup(init);
873 } else {
874 cmdline = init;
875 initargs[0] = NULL;
876 }
877
878 if (cmdline != NULL) {
879 char * chptr, * start;
880
881 start = chptr = cmdline;
882 for (; (i < MAX_INIT_ARGS) && (*start != '\0'); i++) {
883 while (*chptr && !isspace(*chptr)) chptr++;
884 if (*chptr != '\0') *(chptr++) = '\0';
885 initargs[i] = strdup(start);
886 start = chptr;
887 }
888 }
889
890 initargs[i] = NULL;
891
892 if (access(initargs[0], X_OK)) {
893 printf("WARNING: can't access %s\n", initargs[0]);
894 }
895 execv(initargs[0], initargs);
896 printf("exec of init (%s) failed!!!: %d\n", initargs[0], errno);
897 return 1;
898}
899
900int isEchoQuiet(int fd) {
901 if (!reallyquiet) return 0;
902 if (fd != 1) return 0;
903 return 1;
904}
905
906int echoCommand(char * cmd, char * end) {
907 char * args[256];
908 char ** nextArg = args;
909 int outFd = 1;
910 int num = 0;
911 int i;
912 int newline = 1;
913 int length = 0;
914 char *string;
915
916 if (testing && !quiet) {
917 printf("(echo) ");
918 fflush(stdout);
919 }
920
921 while ((cmd = getArg(cmd, end, nextArg))) {
922 if (!strncmp("-n", *nextArg, MAX(2, strlen(*nextArg)))) {
923 newline = 0;
924 } else {
925 length += strlen(*nextArg);
926 nextArg++, num++;
927 }
928 }
929 length += num + 1;
930
931 if ((nextArg - args >= 2) && !strcmp(*(nextArg - 2), ">")) {
932 outFd = open(*(nextArg - 1), O_WRONLY | O_CREAT | O_TRUNC, 0644);
933 if (outFd < 0) {
934 printf("echo: cannot open %s for write: %d\n",
935 *(nextArg - 1), errno);
936 return 1;
937 }
938
939 newline = 0;
940 num -= 2;
941 }
942 string = (char *)malloc(length * sizeof(char));
943 *string = '\0';
944 for (i = 0; i < num;i ++) {
945 if (i) strcat(string, " ");
946 strncat(string, args[i], strlen(args[i]));
947 }
948
949 if (newline) strcat(string, "\n");
950 if (!isEchoQuiet(outFd)) write(outFd, string, strlen(string));
951
952 if (outFd != 1) close(outFd);
953 free(string);
954
955 return 0;
956}
957
958int umountCommand(char * cmd, char * end) {
959 char * path;
960
961 if (!(cmd = getArg(cmd, end, &path))) {
962 printf("umount: path expected\n");
963 return 1;
964 }
965
966 if (cmd < end) {
967 printf("umount: unexpected arguments\n");
968 return 1;
969 }
970
971 if (umount(path)) {
972 printf("umount %s failed: %d\n", path, errno);
973 return 1;
974 }
975
976 return 0;
977}
978
979int mkrootdevCommand(char * cmd, char * end) {
980 char * path;
981 char *root, * chptr;
982 int devNum = 0;
983 int fd;
984 int i;
985 char buf[1024];
986 int major, minor;
987
988 if (!(cmd = getArg(cmd, end, &path))) {
989 printf("mkrootdev: path expected\n");
990 return 1;
991 }
992
993 if (cmd < end) {
994 printf("mkrootdev: unexpected arguments\n");
995 return 1;
996 }
997
998 root = getKernelArg("root=");
999
1000 if (root) {
1001 chptr = root;
1002 while (*chptr && !isspace(*chptr)) chptr++;
1003 *chptr = '\0';
1004 }
1005
1006 if (root && !access(root, R_OK)) {
1007 if (!symlink(root, "/dev/root"))
1008 return 0;
1009 }
1010
1011 if (root && !strncmp(root, "LABEL=", 6)) {
1012 if (get_spec_by_volume_label(root + 6, &major, &minor)) {
1013 if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {
1014 printf("mount: cannot create device %s (%d,%d)\n",
1015 path, major, minor);
1016 return 1;
1017 }
1018
1019 return 0;
1020 }
1021
1022 printf("mkrootdev: label %s not found\n", root + 6);
1023
1024 return 1;
1025 }
1026
1027 if (root && !strncmp(root, "UUID=", 5)) {
1028 if (get_spec_by_uuid(root+5, &major, &minor)) {
1029 if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {
1030 printf("mount: cannot create device %s (%d,%d)\n",
1031 path, major, minor);
1032 return 1;
1033 }
1034
1035 return 0;
1036 }
1037
1038 printf("mkrootdev: UUID %s not found\n", root+5);
1039
1040 return 1;
1041 }
1042
1043 fd = open("/proc/sys/kernel/real-root-dev", O_RDONLY, 0);
1044 if (fd < 0) {
1045 printf("mkrootdev: failed to open /proc/sys/kernel/real-root-dev: %d\n", errno);
1046 return 1;
1047 }
1048
1049 i = read(fd, buf, sizeof(buf));
1050 if (i < 0) {
1051 printf("mkrootdev: failed to read real-root-dev: %d\n", errno);
1052 close(fd);
1053 return 1;
1054 }
1055
1056 close(fd);
1057 if (i == 0)
1058 buf[i] = '\0';
1059 else
1060 buf[i - 1] = '\0';
1061
1062 devNum = atoi(buf);
1063 if (devNum < 0) {
1064 printf("mkrootdev: bad device %s\n", buf);
1065 return 1;
1066 }
1067
1068 if (!devNum && root)
1069 devNum = name_to_dev_t(root);
1070
1071 if (smartmknod(path, S_IFBLK | 0700, devNum)) {
1072 printf("mkrootdev: mknod failed: %d\n", errno);
1073 return 1;
1074 }
1075
1076 return 0;
1077}
1078
1079int mkdirCommand(char * cmd, char * end) {
1080 char * dir;
1081 int ignoreExists = 0;
1082
1083 cmd = getArg(cmd, end, &dir);
1084
1085 if (cmd && !strcmp(dir, "-p")) {
1086 ignoreExists = 1;
1087 cmd = getArg(cmd, end, &dir);
1088 }
1089
1090 if (!cmd) {
1091 printf("mkdir: directory expected\n");
1092 return 1;
1093 }
1094
1095 if (mkdir(dir, 0755)) {
1096 if (!ignoreExists && errno == EEXIST) {
1097 printf("mkdir: failed to create %s: %d\n", dir, errno);
1098 return 1;
1099 }
1100 }
1101
1102 return 0;
1103}
1104
1105int accessCommand(char * cmd, char * end) {
1106 char * permStr;
1107 int perms = 0;
1108 char * file = NULL;
1109
1110 cmd = getArg(cmd, end, &permStr);
1111 if (cmd) cmd = getArg(cmd, end, &file);
1112
1113 if (!cmd || *permStr != '-') {
1114 printf("usage: access -[perm] file\n");
1115 return 1;
1116 }
1117
1118 permStr++;
1119 while (*permStr) {
1120 switch (*permStr) {
1121 case 'r': perms |= R_OK; break;
1122 case 'w': perms |= W_OK; break;
1123 case 'x': perms |= X_OK; break;
1124 case 'f': perms |= F_OK; break;
1125 default:
1126 printf("perms must be -[r][w][x][f]\n");
1127 return 1;
1128 }
1129
1130 permStr++;
1131 }
1132
1133 if ((file == NULL) || (access(file, perms)))
1134 return 1;
1135
1136 return 0;
1137}
1138
1139int sleepCommand(char * cmd, char * end) {
1140 char *delaystr;
1141 int delay;
1142
1143 if (!(cmd = getArg(cmd, end, &delaystr))) {
1144 printf("sleep: delay expected\n");
1145 return 1;
1146 }
1147
1148 delay = atoi(delaystr);
1149 sleep(delay);
1150
1151 return 0;
1152}
1153
1154int readlinkCommand(char * cmd, char * end) {
1155 char * path;
1156 char * buf, * respath, * fullpath;
1157 struct stat sb;
1158 int rc = 0;
1159
1160 if (!(cmd = getArg(cmd, end, &path))) {
1161 printf("readlink: file expected\n");
1162 return 1;
1163 }
1164
1165 if (lstat(path, &sb) == -1) {
1166 fprintf(stderr, "unable to stat %s: %d\n", path, errno);
1167 return 1;
1168 }
1169
1170 if (!S_ISLNK(sb.st_mode)) {
1171 printf("%s\n", path);
1172 return 0;
1173 }
1174
1175 buf = malloc(512);
1176 if (readlink(path, buf, 512) == -1) {
1177 fprintf(stderr, "error readlink %s: %d\n", path, errno);
1178 free(buf);
1179 return 1;
1180 }
1181
1182 /* symlink is absolute */
1183 if (buf[0] == '/') {
1184 printf("%s\n", buf);
1185 free(buf);
1186 return 0;
1187 }
1188
1189 /* nope, need to handle the relative symlink case too */
1190 respath = strrchr(path, '/');
1191 if (respath) {
1192 *respath = '\0';
1193 }
1194
1195 fullpath = malloc(512);
1196 /* and normalize it */
1197 snprintf(fullpath, 512, "%s/%s", path, buf);
1198 respath = malloc(PATH_MAX);
1199 if (!(respath = realpath(fullpath, respath))) {
1200 fprintf(stderr, "error realpath %s: %d\n", fullpath, errno);
1201 rc = 1;
1202 goto readlinkout;
1203 }
1204
1205 printf("%s\n", respath);
1206 readlinkout:
1207 free(buf);
1208 free(respath);
1209 free(fullpath);
1210 return rc;
1211}
1212
1213int doFind(char * dirName, char * name) {
1214 struct stat sb;
1215 DIR * dir;
1216 struct dirent * d;
1217 char * strBuf = alloca(strlen(dirName) + 1024);
1218
1219 if (!(dir = opendir(dirName))) {
1220 fprintf(stderr, "error opening %s: %d\n", dirName, errno);
1221 return 0;
1222 }
1223
1224 errno = 0;
1225 while ((d = readdir(dir))) {
1226 errno = 0;
1227
1228 strcpy(strBuf, dirName);
1229 strcat(strBuf, "/");
1230 strcat(strBuf, d->d_name);
1231
1232 if (!strcmp(d->d_name, name))
1233 printf("%s\n", strBuf);
1234
1235 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
1236 errno = 0;
1237 continue;
1238 }
1239
1240 if (lstat(strBuf, &sb)) {
1241 fprintf(stderr, "failed to stat %s: %d\n", strBuf, errno);
1242 errno = 0;
1243 continue;
1244 }
1245
1246 if (S_ISDIR(sb.st_mode))
1247 doFind(strBuf, name);
1248 }
1249
1250 if (errno) {
1251 closedir(dir);
1252 printf("error reading from %s: %d\n", dirName, errno);
1253 return 1;
1254 }
1255
1256 closedir(dir);
1257
1258 return 0;
1259}
1260
1261int findCommand(char * cmd, char * end) {
1262 char * dir;
1263 char * name;
1264
1265 cmd = getArg(cmd, end, &dir);
1266 if (cmd) cmd = getArg(cmd, end, &name);
1267 if (cmd && strcmp(name, "-name")) {
1268 printf("usage: find [path] -name [file]\n");
1269 return 1;
1270 }
1271
1272 if (cmd) cmd = getArg(cmd, end, &name);
1273 if (!cmd) {
1274 printf("usage: find [path] -name [file]\n");
1275 return 1;
1276 }
1277
1278 return doFind(dir, name);
1279}
1280
1281int findlodevCommand(char * cmd, char * end) {
1282 char devName[20];
1283 int devNum;
1284 int fd;
1285 struct loop_info loopInfo;
1286 char separator[2] = "";
1287
1288 if (*end != '\n') {
1289 printf("usage: findlodev\n");
1290 return 1;
1291 }
1292
1293 if (!access("/dev/.devfsd", X_OK))
1294 strcpy(separator, "/");
1295
1296 for (devNum = 0; devNum < 256; devNum++) {
1297 sprintf(devName, "/dev/loop%s%d", separator, devNum);
1298 if ((fd = open(devName, O_RDONLY)) < 0) return 0;
1299
1300 if (ioctl(fd, LOOP_GET_STATUS, &loopInfo)) {
1301 close(fd);
1302 printf("%s\n", devName);
1303 return 0;
1304 }
1305
1306 close(fd);
1307 }
1308
1309 return 0;
1310}
1311
1312int mknodCommand(char * cmd, char * end) {
1313 char * path, * type;
1314 char * majorStr, * minorStr;
1315 int major;
1316 int minor;
1317 char * chptr;
1318 mode_t mode;
1319
1320 cmd = getArg(cmd, end, &path);
1321 cmd = getArg(cmd, end, &type);
1322 cmd = getArg(cmd, end, &majorStr);
1323 cmd = getArg(cmd, end, &minorStr);
1324 if (!minorStr) {
1325 printf("mknod: usage mknod <path> [c|b] <major> <minor>\n");
1326 return 1;
1327 }
1328
1329 if (!strcmp(type, "b")) {
1330 mode = S_IFBLK;
1331 } else if (!strcmp(type, "c")) {
1332 mode = S_IFCHR;
1333 } else {
1334 printf("mknod: invalid type\n");
1335 return 1;
1336 }
1337
1338 major = strtol(majorStr, &chptr, 10);
1339 if (*chptr) {
1340 printf("invalid major number\n");
1341 return 1;
1342 }
1343
1344 minor = strtol(minorStr, &chptr, 10);
1345 if (*chptr) {
1346 printf("invalid minor number\n");
1347 return 1;
1348 }
1349
1350 if (smartmknod(path, mode | 0600, makedev(major, minor))) {
1351 printf("mknod: failed to create %s: %d\n", path, errno);
1352 return 1;
1353 }
1354
1355 return 0;
1356}
1357
1358int mkdevicesCommand(char * cmd, char * end) {
1359 int fd;
1360 char *buf;
1361 int i;
1362 char * start, * chptr;
1363 int major, minor;
1364 char old;
1365 char devName[128];
1366 char * prefix;
1367
1368 if (!(cmd = getArg(cmd, end, &prefix))) {
1369 printf("mkdevices: path expected\n");
1370 return 1;
1371 }
1372
1373 if (cmd < end) {
1374 printf("mkdevices: unexpected arguments\n");
1375 return 1;
1376 }
1377
1378 if ((fd = open("/proc/partitions", O_RDONLY)) < 0) {
1379 printf("mkrootdev: failed to open /proc/partitions: %d\n", errno);
1380 return 1;
1381 }
1382
1383 i = readFD(fd, &buf);
1384 if (i < 1) {
1385 close(fd);
1386 printf("failed to read /proc/partitions: %d\n", errno);
1387 return 1;
1388 }
1389 buf[i] = '\0';
1390 close(fd);
1391
1392 start = strchr(buf, '\n');
1393 if (start) {
1394 start++;
1395 start = strchr(buf, '\n');
1396 }
1397 if (!start) return 1;
1398
1399 start = start + 1;
1400 while (*start) {
1401 while (*start && isspace(*start)) start++;
1402 major = strtol(start, &chptr, 10);
1403
1404 if (start != chptr) {
1405 start = chptr;
1406 while (*start && isspace(*start)) start++;
1407 minor = strtol(start, &chptr, 10);
1408
1409 if (start != chptr) {
1410 start = chptr;
1411 while (*start && isspace(*start)) start++;
1412 while (*start && !isspace(*start)) start++;
1413 while (*start && isspace(*start)) start++;
1414
1415 if (*start) {
1416
1417 chptr = start;
1418 while (!isspace(*chptr)) chptr++;
1419 old = *chptr;
1420 *chptr = '\0';
1421
1422 if (testing) {
1423 printf("% 3d % 3d %s\n", major, minor, start);
1424 } else {
1425 char * ptr, * deviceDir;
1426 int i;
1427
1428 sprintf(devName, "%s/%s", prefix, start);
1429 unlink(devName);
1430
1431 ptr = devName;
1432 i = 0;
1433 while (*ptr)
1434 if (*ptr++ == '/')
1435 i++;
1436 if (i > 2) {
1437 deviceDir = alloca(strlen(devName) + 1);
1438 strcpy(deviceDir, devName);
1439 ptr = deviceDir + (strlen(devName) - 1);
1440 while (*ptr != '/')
1441 *ptr-- = '\0';
1442 if (access(deviceDir, X_OK) && mkdir(deviceDir, 0644)) {
1443 printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno);
1444 }
1445 }
1446 if (smartmknod(devName, S_IFBLK | 0600,
1447 makedev(major, minor))) {
1448 printf("failed to create %s\n", devName);
1449 }
1450 }
1451
1452 *chptr = old;
1453 start = chptr;
1454 }
1455
1456 }
1457 }
1458
1459 start = strchr(start, '\n');
1460 if (!*start) return 1;
1461 start = start + 1;
1462 }
1463
1464 return 0;
1465}
1466
1467static int getDevNumFromProc(char * file, char * device) {
1468 char buf[32768], line[4096];
1469 char * start, *end;
1470 int num;
1471 int fd;
1472
1473 if ((fd = open(file, O_RDONLY)) == -1) {
1474 printf("can't open file %s: %d\n", file, errno);
1475 return -1;
1476 }
1477
1478 num = read(fd, buf, sizeof(buf));
1479 if (num < 1) {
1480 close(fd);
1481 printf("failed to read %s: %d\n", file, errno);
1482 return -1;
1483 }
1484 buf[num] = '\0';
1485 close(fd);
1486
1487 start = buf;
1488 end = strchr(start, '\n');
1489 while (start && end) {
1490 *end++ = '\0';
1491 if ((sscanf(start, "%d %s", &num, line)) == 2) {
1492 if (!strncmp(device, line, strlen(device)))
1493 return num;
1494 }
1495 start = end;
1496 end = strchr(start, '\n');
1497 }
1498 return -1;
1499}
1500
1501int mkDMNodCommand(char * cmd, char * end) {
1502 int major = getDevNumFromProc("/proc/devices", "misc");
1503 int minor = getDevNumFromProc("/proc/misc", "device-mapper");
1504
1505 if ((major == -1) || (minor == -1)) {
1506 printf("Unable to find device-mapper major/minor\n");
1507 return 1;
1508 }
1509
1510 if (!access("/dev/mapper/control", R_OK)) {
1511 struct stat sb;
1512 if (stat("/dev/mapper/control", &sb) == 0) {
1513 if (S_ISCHR(sb.st_mode) && (sb.st_rdev == makedev(major, minor)))
1514 return 0;
1515 }
1516
1517 unlink("/dev/mapper/control");
1518 }
1519
1520 if (smartmknod("/dev/mapper/control", S_IFCHR | 0600,
1521 makedev(major, minor))) {
1522 printf("failed to create /dev/mapper/control\n");
1523 return 1;
1524 }
1525
1526 return 0;
1527}
1528
1529int setQuietCommand(char * cmd, char * end) {
1530 int fd, rc;
1531
1532 if ((fd = open("/proc/cmdline", O_RDONLY)) >= 0) {
1533 char * buf = malloc(512);
1534 rc = read(fd, buf, 511);
1535 if (strstr(buf, "quiet") != NULL)
1536 reallyquiet = 1;
1537 close(fd);
1538 free(buf);
1539 }
1540
1541 if (reallyquiet)
1542 quiet = 1;
1543
1544 return 0;
1545}
1546
1547int runStartup(int fd) {
1548 char contents[32768];
1549 int i;
1550 char * start, * end;
1551 char * chptr;
1552 int rc;
1553
1554 i = read(fd, contents, sizeof(contents) - 1);
1555 if (i == (sizeof(contents) - 1)) {
1556 printf("Failed to read /startup.rc -- file too large.\n");
1557 return 1;
1558 }
1559 close(fd);
1560
1561 contents[i] = '\0';
1562
1563 start = contents;
1564 while (*start) {
1565 while (isspace(*start) && *start && (*start != '\n')) start++;
1566
1567 if (*start == '#')
1568 while (*start && (*start != '\n')) start++;
1569
1570 if (*start == '\n') {
1571 start++;
1572 continue;
1573 }
1574
1575 if (!*start) {
1576 printf("(last line in /startup.rc is empty)\n");
1577 continue;
1578 }
1579
1580 /* start points to the beginning of the command */
1581 end = start + 1;
1582 while (*end && (*end != '\n')) end++;
1583 if (!*end) {
1584 printf("(last line in /startup.rc missing \\n -- skipping)\n");
1585 start = end;
1586 continue;
1587 }
1588
1589 /* end points to the \n at the end of the command */
1590
1591 chptr = start;
1592 while (chptr < end && !isspace(*chptr)) chptr++;
1593
1594 if (!strncmp(start, "mount", MAX(5, chptr - start)))
1595 rc = mountCommand(chptr, end);
1596 else if (!strncmp(start, "losetup", MAX(7, chptr - start)))
1597 rc = losetupCommand(chptr, end);
1598 else if (!strncmp(start, "echo", MAX(4, chptr - start)))
1599 rc = echoCommand(chptr, end);
1600 else if (!strncmp(start, "raidautorun", MAX(11, chptr - start)))
1601 rc = raidautorunCommand(chptr, end);
1602 else if (!strncmp(start, "pivot_root", MAX(10, chptr - start)))
1603 rc = pivotrootCommand(chptr, end);
1604 else if (!strncmp(start, "switchroot", MAX(10, chptr - start)))
1605 rc = switchrootCommand(chptr, end);
1606 else if (!strncmp(start, "mkrootdev", MAX(9, chptr - start)))
1607 rc = mkrootdevCommand(chptr, end);
1608 else if (!strncmp(start, "umount", MAX(6, chptr - start)))
1609 rc = umountCommand(chptr, end);
1610 else if (!strncmp(start, "exec", MAX(4, chptr - start)))
1611 rc = execCommand(chptr, end);
1612 else if (!strncmp(start, "mkdir", MAX(5, chptr - start)))
1613 rc = mkdirCommand(chptr, end);
1614 else if (!strncmp(start, "access", MAX(6, chptr - start)))
1615 rc = accessCommand(chptr, end);
1616 else if (!strncmp(start, "find", MAX(4, chptr - start)))
1617 rc = findCommand(chptr, end);
1618 else if (!strncmp(start, "findlodev", MAX(7, chptr - start)))
1619 rc = findlodevCommand(chptr, end);
1620 else if (!strncmp(start, "showlabels", MAX(10, chptr-start)))
1621 rc = display_uuid_cache();
1622 else if (!strncmp(start, "mkdevices", MAX(9, chptr-start)))
1623 rc = mkdevicesCommand(chptr, end);
1624 else if (!strncmp(start, "sleep", MAX(5, chptr-start)))
1625 rc = sleepCommand(chptr, end);
1626 else if (!strncmp(start, "mknod", MAX(5, chptr-start)))
1627 rc = mknodCommand(chptr, end);
1628 else if (!strncmp(start, "mkdmnod", MAX(7, chptr-start)))
1629 rc = mkDMNodCommand(chptr, end);
1630 else if (!strncmp(start, "readlink", MAX(8, chptr-start)))
1631 rc = readlinkCommand(chptr, end);
1632 else if (!strncmp(start, "setquiet", MAX(8, chptr-start)))
1633 rc = setQuietCommand(chptr, end);
1634#ifdef DEBUG
1635 else if (!strncmp(start, "cat", MAX(3, chptr-start)))
1636 rc = catCommand(chptr, end);
1637 else if (!strncmp(start, "ls", MAX(2, chptr-start)))
1638 rc = lsCommand(chptr, end);
1639#endif
1640 else {
1641 *chptr = '\0';
1642 rc = otherCommand(start, chptr + 1, end, 1);
1643 }
1644
1645 start = end + 1;
1646 }
1647
1648 return rc;
1649}
1650
1651int main(int argc, char **argv) {
1652 int fd = 0;
1653 char * name;
1654 int rc;
1655 int force = 0;
1656
1657 name = strrchr(argv[0], '/');
1658 if (!name)
1659 name = argv[0];
1660 else
1661 name++;
1662
1663 if (!strcmp(name, "modprobe"))
1664 exit(0);
1665 if (!strcmp(name, "hotplug")) {
1666 argv[0] = strdup("/sbin/udev");
1667 execv(argv[0], argv);
1668 printf("ERROR: exec of udev failed!\n");
1669 exit(1);
1670 }
1671
1672 testing = (getppid() != 0) && (getppid() != 1);
1673 argv++, argc--;
1674
1675 while (argc && **argv == '-') {
1676 if (!strcmp(*argv, "--force")) {
1677 force = 1;
1678 argv++, argc--;
1679 testing = 0;
1680 } else if (!strcmp(*argv, "--quiet")) {
1681 quiet = 1;
1682 argv++, argc--;
1683 } else if (!strcmp(*argv, "--reallyquiet")) {
1684 reallyquiet = 1;
1685 argv++, argc--;
1686 } else {
1687 printf("unknown argument %s\n", *argv);
1688 return 1;
1689 }
1690 }
1691
1692 if (force && !quiet)
1693 printf("(forcing normal run)\n");
1694
1695 if (testing && !quiet)
1696 printf("(running in test mode).\n");
1697
1698 if (!quiet) printf("Red Hat nash version %s starting\n", VERSION);
1699
1700 if (*argv) {
1701 fd = open(*argv, O_RDONLY, 0);
1702 if (fd < 0) {
1703 printf("nash: cannot open %s: %d\n", *argv, errno);
1704 exit(1);
1705 }
1706 }
1707
1708 /* runStartup closes fd */
1709 rc = runStartup(fd);
1710
1711 return rc;
1712}