]> git.ipfire.org Git - ipfire-2.x.git/blob - src/nash/nash.c
git-svn-id: http://svn.ipfire.org/svn/ipfire/IPFire/source@16 ea5c0bd1-69bd-2848...
[ipfire-2.x.git] / src / nash / nash.c
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 *
9 * Copyright 2002 Red Hat Software
10 *
11 * This software may be freely redistributed under the terms of the GNU
12 * public license.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20 /* We internalize losetup, mount, raidautorun, and echo commands. Other
21 commands are run from the filesystem. Comments and blank lines work as
22 well, argument parsing is screwy. */
23
24 #include <ctype.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <net/if.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34 #include <sys/mount.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/un.h>
40 #include <sys/wait.h>
41 #include <unistd.h>
42 #include <sys/ioctl.h>
43 #include <sys/reboot.h>
44 #include <termios.h>
45
46 #include <asm/unistd.h>
47
48 #include "mount_by_label.h"
49
50 /* Need to tell loop.h what the actual dev_t type is. */
51 #undef dev_t
52 #if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
53 #define dev_t unsigned int
54 #else
55 #define dev_t unsigned short
56 #endif
57 #include <linux/loop.h>
58 #undef dev_t
59 #define dev_t dev_t
60
61 #define syslog klogctl
62
63 #include <linux/cdrom.h>
64 #define MD_MAJOR 9
65 #include <linux/raid/md_u.h>
66
67 #ifndef RAID_AUTORUN
68 #define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
69 #endif
70
71 #ifndef MS_REMOUNT
72 #define MS_REMOUNT 32
73 #endif
74
75 #ifdef USE_DIET
76 static inline _syscall2(int,pivot_root,const char *,one,const char *,two)
77 #endif
78
79 #define MAX(a, b) ((a) > (b) ? a : b)
80
81 int testing = 0, quiet = 0;
82
83 #define PATH "/usr/bin:/bin:/sbin:/usr/sbin"
84
85 char * env[] = {
86 "PATH=" PATH,
87 NULL
88 };
89
90 int smartmknod(char * device, mode_t mode, dev_t dev) {
91 char buf[256];
92 char * end;
93
94 strcpy(buf, device);
95
96 end = buf;
97 while (*end) {
98 if (*end == '/') {
99 *end = '\0';
100 if (access(buf, F_OK) && errno == ENOENT)
101 mkdir(buf, 0700);
102 *end = '/';
103 }
104
105 end++;
106 }
107
108 return mknod(device, mode, dev);
109 }
110
111 char * getArg(char * cmd, char * end, char ** arg) {
112 char quote = '\0';
113
114 if (cmd >= end) return NULL;
115
116 while (isspace(*cmd) && cmd < end) cmd++;
117 if (cmd >= end) return NULL;
118
119 if (*cmd == '"')
120 cmd++, quote = '"';
121 else if (*cmd == '\'')
122 cmd++, quote = '\'';
123
124 if (quote) {
125 *arg = cmd;
126
127 /* This doesn't support \ escapes */
128 while (cmd < end && *cmd != quote) cmd++;
129
130 if (cmd == end) {
131 printf("error: quote mismatch for %s\n", *arg);
132 return NULL;
133 }
134
135 *cmd = '\0';
136 cmd++;
137 } else {
138 *arg = cmd;
139 while (!isspace(*cmd) && cmd < end) cmd++;
140 *cmd = '\0';
141 }
142
143 cmd++;
144
145 while (isspace(*cmd)) cmd++;
146
147 return cmd;
148 }
149
150 int mountCommand(char * cmd, char * end) {
151 char * fsType = NULL;
152 char * device;
153 char * mntPoint;
154 char * deviceDir;
155 char * options = NULL;
156 int mustRemove = 0;
157 int mustRemoveDir = 0;
158 int rc;
159 int flags = MS_MGC_VAL;
160 char * newOpts;
161
162 cmd = getArg(cmd, end, &device);
163 if (!cmd) {
164 printf("usage: mount [--ro] [-o <opts>] -t <type> <device> <mntpoint>\n");
165 return 1;
166 }
167
168 while (cmd && *device == '-') {
169 if (!strcmp(device, "--ro")) {
170 flags |= MS_RDONLY;
171 } else if (!strcmp(device, "-o")) {
172 cmd = getArg(cmd, end, &options);
173 if (!cmd) {
174 printf("mount: -o requires arguments\n");
175 return 1;
176 }
177 } else if (!strcmp(device, "-t")) {
178 if (!(cmd = getArg(cmd, end, &fsType))) {
179 printf("mount: missing filesystem type\n");
180 return 1;
181 }
182 }
183
184 cmd = getArg(cmd, end, &device);
185 }
186
187 if (!cmd) {
188 printf("mount: missing device\n");
189 return 1;
190 }
191
192 if (!(cmd = getArg(cmd, end, &mntPoint))) {
193 printf("mount: missing mount point\n");
194 return 1;
195 }
196
197 if (!fsType) {
198 printf("mount: filesystem type expected\n");
199 return 1;
200 }
201
202 if (cmd < end) {
203 printf("mount: unexpected arguments\n");
204 return 1;
205 }
206
207 /* need to deal with options */
208 if (options) {
209 char * end;
210 char * start = options;
211
212 newOpts = alloca(strlen(options) + 1);
213 *newOpts = '\0';
214
215 while (*start) {
216 end = strchr(start, ',');
217 if (!end) {
218 end = start + strlen(start);
219 } else {
220 *end = '\0';
221 end++;
222 }
223
224 if (!strcmp(start, "ro"))
225 flags |= MS_RDONLY;
226 else if (!strcmp(start, "rw"))
227 flags &= ~MS_RDONLY;
228 else if (!strcmp(start, "nosuid"))
229 flags |= MS_NOSUID;
230 else if (!strcmp(start, "suid"))
231 flags &= ~MS_NOSUID;
232 else if (!strcmp(start, "nodev"))
233 flags |= MS_NODEV;
234 else if (!strcmp(start, "dev"))
235 flags &= ~MS_NODEV;
236 else if (!strcmp(start, "noexec"))
237 flags |= MS_NOEXEC;
238 else if (!strcmp(start, "exec"))
239 flags &= ~MS_NOEXEC;
240 else if (!strcmp(start, "sync"))
241 flags |= MS_SYNCHRONOUS;
242 else if (!strcmp(start, "async"))
243 flags &= ~MS_SYNCHRONOUS;
244 else if (!strcmp(start, "nodiratime"))
245 flags |= MS_NODIRATIME;
246 else if (!strcmp(start, "diratime"))
247 flags &= ~MS_NODIRATIME;
248 else if (!strcmp(start, "noatime"))
249 flags |= MS_NOATIME;
250 else if (!strcmp(start, "atime"))
251 flags &= ~MS_NOATIME;
252 else if (!strcmp(start, "remount"))
253 flags |= MS_REMOUNT;
254 else if (!strcmp(start, "defaults"))
255 ;
256 else {
257 if (*newOpts)
258 strcat(newOpts, ",");
259 strcat(newOpts, start);
260 }
261
262 start = end;
263 }
264
265 options = newOpts;
266 }
267
268 if (!strncmp("LABEL=", device, 6)) {
269 int major, minor;
270 char * devName;
271 char * ptr;
272 int i;
273
274 devName = get_spec_by_volume_label(device + 6, &major, &minor);
275
276 if (devName) {
277 device = devName;
278 if (access(device, F_OK)) {
279 ptr = device;
280 i = 0;
281 while (*ptr)
282 if (*ptr++ == '/')
283 i++;
284 if (i > 2) {
285 deviceDir = alloca(strlen(device) + 1);
286 strcpy(deviceDir, device);
287 ptr = deviceDir + (strlen(device) - 1);
288 while (*ptr != '/')
289 *ptr-- = '\0';
290 if (mkdir(deviceDir, 0644)) {
291 printf("mkdir: cannot create directory %s\n", deviceDir);
292 } else {
293 mustRemoveDir = 1;
294 }
295 }
296 if (smartmknod(device, S_IFBLK | 0600, makedev(major, minor))) {
297 printf("mount: cannot create device %s (%d,%d)\n",
298 device, major, minor);
299 return 1;
300 }
301 mustRemove = 1;
302 }
303 }
304 }
305
306 if (testing) {
307 printf("mount %s%s%s-t '%s' '%s' '%s' (%s%s%s%s%s%s%s)\n",
308 options ? "-o '" : "",
309 options ? options : "",
310 options ? "\' " : "",
311 fsType, device, mntPoint,
312 (flags & MS_RDONLY) ? "ro " : "",
313 (flags & MS_NOSUID) ? "nosuid " : "",
314 (flags & MS_NODEV) ? "nodev " : "",
315 (flags & MS_NOEXEC) ? "noexec " : "",
316 (flags & MS_SYNCHRONOUS) ? "sync " : "",
317 (flags & MS_REMOUNT) ? "remount " : "",
318 (flags & MS_NOATIME) ? "noatime " : ""
319 );
320 } else {
321 if (mount(device, mntPoint, fsType, flags, options)) {
322 printf("mount: error %d mounting %s\n", errno, fsType);
323 rc = 1;
324 }
325 }
326
327 if (mustRemove) unlink(device);
328 if (mustRemoveDir) rmdir(deviceDir);
329
330 return rc;
331 }
332
333 int otherCommand(char * bin, char * cmd, char * end, int doFork) {
334 char * args[128];
335 char ** nextArg;
336 int pid;
337 int status;
338 char fullPath[255];
339 const static char * sysPath = PATH;
340 const char * pathStart;
341 const char * pathEnd;
342 char * stdoutFile = NULL;
343 int stdoutFd = 0;
344
345 nextArg = args;
346
347 if (!strchr(bin, '/')) {
348 pathStart = sysPath;
349 while (*pathStart) {
350 pathEnd = strchr(pathStart, ':');
351
352 if (!pathEnd) pathEnd = pathStart + strlen(pathStart);
353
354 strncpy(fullPath, pathStart, pathEnd - pathStart);
355 fullPath[pathEnd - pathStart] = '/';
356 strcpy(fullPath + (pathEnd - pathStart + 1), bin);
357
358 pathStart = pathEnd;
359 if (*pathStart) pathStart++;
360
361 if (!access(fullPath, X_OK)) {
362 bin = fullPath;
363 break;
364 }
365 }
366 }
367
368 *nextArg = bin;
369
370 while (cmd && cmd < end) {
371 nextArg++;
372 cmd = getArg(cmd, end, nextArg);
373 }
374
375 if (cmd) nextArg++;
376 *nextArg = NULL;
377
378 /* if the next-to-last arg is a >, redirect the output properly */
379 if (((nextArg - args) >= 2) && !strcmp(*(nextArg - 2), ">")) {
380 stdoutFile = *(nextArg - 1);
381 *(nextArg - 2) = NULL;
382
383 stdoutFd = open(stdoutFile, O_CREAT | O_RDWR | O_TRUNC, 0600);
384 if (stdoutFd < 0) {
385 printf("nash: failed to open %s: %d\n", stdoutFile, errno);
386 return 1;
387 }
388 }
389
390 if (testing) {
391 printf("%s ", bin);
392 nextArg = args + 1;
393 while (*nextArg)
394 printf(" '%s'", *nextArg++);
395 if (stdoutFile)
396 printf(" (> %s)", stdoutFile);
397 printf("\n");
398 } else {
399 if (!doFork || !(pid = fork())) {
400 /* child */
401 dup2(stdoutFd, 1);
402 execve(args[0], args, env);
403 printf("ERROR: failed in exec of %s\n", args[0]);
404 return 1;
405 }
406
407 close(stdoutFd);
408
409 wait4(-1, &status, 0, NULL);
410 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
411 printf("ERROR: %s exited abnormally!\n", args[0]);
412 return 1;
413 }
414 }
415
416 return 0;
417 }
418
419 int execCommand(char * cmd, char * end) {
420 char * bin;
421
422 if (!(cmd = getArg(cmd, end, &bin))) {
423 printf("exec: argument expected\n");
424 return 1;
425 }
426
427 return otherCommand(bin, cmd, end, 0);
428 }
429
430 int losetupCommand(char * cmd, char * end) {
431 char * device;
432 char * file;
433 int fd;
434 struct loop_info loopInfo;
435 int dev;
436
437 if (!(cmd = getArg(cmd, end, &device))) {
438 printf("losetup: missing device\n");
439 return 1;
440 }
441
442 if (!(cmd = getArg(cmd, end, &file))) {
443 printf("losetup: missing file\n");
444 return 1;
445 }
446
447 if (cmd < end) {
448 printf("losetup: unexpected arguments\n");
449 return 1;
450 }
451
452 if (testing) {
453 printf("losetup '%s' '%s'\n", device, file);
454 } else {
455 dev = open(device, O_RDWR, 0);
456 if (dev < 0) {
457 printf("losetup: failed to open %s: %d\n", device, errno);
458 return 1;
459 }
460
461 fd = open(file, O_RDWR, 0);
462 if (fd < 0) {
463 printf("losetup: failed to open %s: %d\n", file, errno);
464 close(dev);
465 return 1;
466 }
467
468 if (ioctl(dev, LOOP_SET_FD, (long) fd)) {
469 printf("losetup: LOOP_SET_FD failed: %d\n", errno);
470 close(dev);
471 close(fd);
472 return 1;
473 }
474
475 close(fd);
476
477 memset(&loopInfo, 0, sizeof(loopInfo));
478 strcpy(loopInfo.lo_name, file);
479
480 if (ioctl(dev, LOOP_SET_STATUS, &loopInfo))
481 printf("losetup: LOOP_SET_STATUS failed: %d\n", errno);
482
483 close(dev);
484 }
485
486 return 0;
487 }
488
489 int raidautorunCommand(char * cmd, char * end) {
490 char * device;
491 int fd;
492
493 if (!(cmd = getArg(cmd, end, &device))) {
494 printf("raidautorun: raid device expected as first argument\n");
495 return 1;
496 }
497
498 if (cmd < end) {
499 printf("raidautorun: unexpected arguments\n");
500 return 1;
501 }
502
503 fd = open(device, O_RDWR, 0);
504 if (fd < 0) {
505 printf("raidautorun: failed to open %s: %d\n", device, errno);
506 return 1;
507 }
508
509 if (ioctl(fd, RAID_AUTORUN, 0)) {
510 printf("raidautorun: RAID_AUTORUN failed: %d\n", errno);
511 close(fd);
512 return 1;
513 }
514
515 close(fd);
516 return 0;
517 }
518
519 static int my_pivot_root(char * one, char * two) {
520 #ifdef USE_DIET
521 return pivot_root(one, two);
522 #else
523 return syscall(__NR_pivot_root, one, two);
524 #endif
525 }
526
527 int pivotrootCommand(char * cmd, char * end) {
528 char * new;
529 char * old;
530
531 if (!(cmd = getArg(cmd, end, &new))) {
532 printf("pivotroot: new root mount point expected\n");
533 return 1;
534 }
535
536 if (!(cmd = getArg(cmd, end, &old))) {
537 printf("pivotroot: old root mount point expected\n");
538 return 1;
539 }
540
541 if (cmd < end) {
542 printf("pivotroot: unexpected arguments\n");
543 return 1;
544 }
545
546 if (my_pivot_root(new, old)) {
547 printf("pivotroot: pivot_root(%s,%s) failed: %d\n", new, old, errno);
548 return 1;
549 }
550
551 return 0;
552 }
553
554 int echoCommand(char * cmd, char * end) {
555 char * args[256];
556 char ** nextArg = args;
557 int outFd = 1;
558 int num = 0;
559 int i;
560
561 if (testing && !quiet) {
562 printf("(echo) ");
563 fflush(stdout);
564 }
565
566 while ((cmd = getArg(cmd, end, nextArg)))
567 nextArg++, num++;
568
569 if ((nextArg - args >= 2) && !strcmp(*(nextArg - 2), ">")) {
570 outFd = open(*(nextArg - 1), O_RDWR | O_CREAT | O_TRUNC, 0644);
571 if (outFd < 0) {
572 printf("echo: cannot open %s for write: %d\n",
573 *(nextArg - 1), errno);
574 return 1;
575 }
576
577 num -= 2;
578 }
579
580 for (i = 0; i < num;i ++) {
581 if (i)
582 write(outFd, " ", 1);
583 write(outFd, args[i], strlen(args[i]));
584 }
585
586 write(outFd, "\n", 1);
587
588 if (outFd != 1) close(outFd);
589
590 return 0;
591 }
592
593 int umountCommand(char * cmd, char * end) {
594 char * path;
595
596 if (!(cmd = getArg(cmd, end, &path))) {
597 printf("umount: path expected\n");
598 return 1;
599 }
600
601 if (cmd < end) {
602 printf("umount: unexpected arguments\n");
603 return 1;
604 }
605
606 if (umount(path)) {
607 printf("umount %s failed: %d\n", path, errno);
608 return 1;
609 }
610
611 return 0;
612 }
613
614 int mkrootdevCommand(char * cmd, char * end) {
615 char * path;
616 char * start, * chptr;
617 unsigned int devNum = 0;
618 int fd;
619 int i;
620 char buf[1024];
621 int major, minor;
622
623 if (!(cmd = getArg(cmd, end, &path))) {
624 printf("mkrootdev: path expected\n");
625 return 1;
626 }
627
628 if (cmd < end) {
629 printf("mkrootdev: unexpected arguments\n");
630 return 1;
631 }
632
633 fd = open("/proc/cmdline", O_RDONLY, 0);
634 if (fd < 0) {
635 printf("mkrootdev: failed to open /proc/cmdline: %d\n", errno);
636 return 1;
637 }
638
639 i = read(fd, buf, sizeof(buf));
640 if (i < 0) {
641 printf("mkrootdev: failed to read /proc/cmdline: %d\n", errno);
642 close(fd);
643 return 1;
644 }
645
646 close(fd);
647 buf[i - 1] = '\0';
648
649 start = buf;
650 while (*start && isspace(*start)) start++;
651 while (*start && strncmp(start, "root=", 5)) {
652 while (*start && !isspace(*start)) start++;
653 while (*start && isspace(*start)) start++;
654 }
655
656 start += 5;
657 chptr = start;
658 while (*chptr && !isspace(*chptr)) chptr++;
659 *chptr = '\0';
660
661 if (!strncmp(start, "LABEL=", 6)) {
662 if (get_spec_by_volume_label(start + 6, &major, &minor)) {
663 if (smartmknod(path, S_IFBLK | 0600, makedev(major, minor))) {
664 printf("mount: cannot create device %s (%d,%d)\n",
665 path, major, minor);
666 return 1;
667 }
668
669 return 0;
670 }
671
672 printf("mkrootdev: label %s not found\n", start + 6);
673
674 return 1;
675 }
676
677 fd = open("/proc/sys/kernel/real-root-dev", O_RDONLY, 0);
678 if (fd < 0) {
679 printf("mkrootdev: failed to open /proc/sys/kernel/real-root-dev: %d\n", errno);
680 return 1;
681 }
682
683 i = read(fd, buf, sizeof(buf));
684 if (i < 0) {
685 printf("mkrootdev: failed to read real-root-dev: %d\n", errno);
686 close(fd);
687 return 1;
688 }
689
690 close(fd);
691 buf[i - 1] = '\0';
692
693 devNum = atoi(buf);
694 if (devNum < 0) {
695 printf("mkrootdev: bad device %s\n", buf);
696 return 1;
697 }
698
699 if (smartmknod(path, S_IFBLK | 0700, devNum)) {
700 printf("mkrootdev: mknod failed: %d\n", errno);
701 return 1;
702 }
703
704 return 0;
705 }
706
707 int mkdirCommand(char * cmd, char * end) {
708 char * dir;
709 int ignoreExists = 0;
710
711 cmd = getArg(cmd, end, &dir);
712
713 if (cmd && !strcmp(dir, "-p")) {
714 ignoreExists = 1;
715 cmd = getArg(cmd, end, &dir);
716 }
717
718 if (!cmd) {
719 printf("mkdir: directory expected\n");
720 return 1;
721 }
722
723 if (mkdir(dir, 0755)) {
724 if (!ignoreExists && errno == EEXIST) {
725 printf("mkdir: failed to create %s: %d\n", dir, errno);
726 return 1;
727 }
728 }
729
730 return 0;
731 }
732
733 int accessCommand(char * cmd, char * end) {
734 char * permStr;
735 int perms = 0;
736 char * file;
737
738 cmd = getArg(cmd, end, &permStr);
739 if (cmd) cmd = getArg(cmd, end, &file);
740
741 if (!cmd || *permStr != '-') {
742 printf("usage: access -[perm] file\n");
743 return 1;
744 }
745
746 permStr++;
747 while (*permStr) {
748 switch (*permStr) {
749 case 'r': perms |= R_OK; break;
750 case 'w': perms |= W_OK; break;
751 case 'x': perms |= X_OK; break;
752 case 'f': perms |= F_OK; break;
753 default:
754 printf("perms must be -[r][w][x][f]\n");
755 return 1;
756 }
757
758 permStr++;
759 }
760
761 if (access(file, perms))
762 return 1;
763
764 return 0;
765 }
766
767 int sleepCommand(char * cmd, char * end) {
768 char *delaystr;
769 int delay;
770
771 if (!(cmd = getArg(cmd, end, &delaystr))) {
772 printf("sleep: delay expected\n");
773 return 1;
774 }
775
776 delay = atoi(delaystr);
777 sleep(delay);
778
779 return 0;
780 }
781
782 int readlinkCommand(char * cmd, char * end) {
783 char * path;
784 char * buf, * respath, * fullpath;
785 struct stat sb;
786
787 if (!(cmd = getArg(cmd, end, &path))) {
788 printf("readlink: file expected\n");
789 return 1;
790 }
791
792 if (lstat(path, &sb) == -1) {
793 fprintf(stderr, "unable to stat %s: %d\n", path, errno);
794 return 1;
795 }
796
797 if (!S_ISLNK(sb.st_mode)) {
798 printf("%s\n", path);
799 return 0;
800 }
801
802 buf = malloc(512);
803 if (readlink(path, buf, 512) == -1) {
804 fprintf(stderr, "error readlink %s: %d\n", path, errno);
805 return 1;
806 }
807
808 /* symlink is absolute */
809 if (buf[0] == '/') {
810 printf("%s\n", buf);
811 return 0;
812 }
813
814 /* nope, need to handle the relative symlink case too */
815 respath = strrchr(path, '/');
816 if (respath) {
817 *respath = '\0';
818 }
819
820 fullpath = malloc(512);
821 /* and normalize it */
822 snprintf(fullpath, 512, "%s/%s", path, buf);
823 respath = malloc(PATH_MAX);
824 if (!(respath = realpath(fullpath, respath))) {
825 fprintf(stderr, "error realpath %s: %d\n", fullpath, errno);
826 return 1;
827 }
828
829 printf("%s\n", respath);
830 return 0;
831 }
832
833 int doFind(char * dirName, char * name) {
834 struct stat sb;
835 DIR * dir;
836 struct dirent * d;
837 char * strBuf = alloca(strlen(dirName) + 1024);
838
839 if (!(dir = opendir(dirName))) {
840 fprintf(stderr, "error opening %s: %d\n", dirName, errno);
841 return 0;
842 }
843
844 errno = 0;
845 while ((d = readdir(dir))) {
846 errno = 0;
847
848 strcpy(strBuf, dirName);
849 strcat(strBuf, "/");
850 strcat(strBuf, d->d_name);
851
852 if (!strcmp(d->d_name, name))
853 printf("%s\n", strBuf);
854
855 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
856 errno = 0;
857 continue;
858 }
859
860 if (lstat(strBuf, &sb)) {
861 fprintf(stderr, "failed to stat %s: %d\n", strBuf, errno);
862 errno = 0;
863 continue;
864 }
865
866 if (S_ISDIR(sb.st_mode))
867 doFind(strBuf, name);
868 }
869
870 if (errno) {
871 closedir(dir);
872 printf("error reading from %s: %d\n", dirName, errno);
873 return 1;
874 }
875
876 closedir(dir);
877
878 return 0;
879 }
880
881 int findCommand(char * cmd, char * end) {
882 char * dir;
883 char * name;
884
885 cmd = getArg(cmd, end, &dir);
886 if (cmd) cmd = getArg(cmd, end, &name);
887 if (cmd && strcmp(name, "-name")) {
888 printf("usage: find [path] -name [file]\n");
889 return 1;
890 }
891
892 if (cmd) cmd = getArg(cmd, end, &name);
893 if (!cmd) {
894 printf("usage: find [path] -name [file]\n");
895 return 1;
896 }
897
898 return doFind(dir, name);
899 }
900
901 int findlodevCommand(char * cmd, char * end) {
902 char devName[20];
903 int devNum;
904 int fd;
905 struct loop_info loopInfo;
906 char separator[2] = "";
907
908 if (*end != '\n') {
909 printf("usage: findlodev\n");
910 return 1;
911 }
912
913 if (!access("/dev/.devfsd", X_OK))
914 strcpy(separator, "/");
915
916 for (devNum = 0; devNum < 256; devNum++) {
917 sprintf(devName, "/dev/loop%s%d", separator, devNum);
918 if ((fd = open(devName, O_RDONLY)) < 0) return 0;
919
920 if (ioctl(fd, LOOP_GET_STATUS, &loopInfo)) {
921 close(fd);
922 printf("%s\n", devName);
923 return 0;
924 }
925
926 close(fd);
927 }
928
929 return 0;
930 }
931
932 int mknodCommand(char * cmd, char * end) {
933 char * path, * type;
934 char * majorStr, * minorStr;
935 int major;
936 int minor;
937 char * chptr;
938 mode_t mode;
939
940 cmd = getArg(cmd, end, &path);
941 cmd = getArg(cmd, end, &type);
942 cmd = getArg(cmd, end, &majorStr);
943 cmd = getArg(cmd, end, &minorStr);
944 if (!minorStr) {
945 printf("mknod: usage mknod <path> [c|b] <major> <minor>\n");
946 return 1;
947 }
948
949 if (!strcmp(type, "b")) {
950 mode = S_IFBLK;
951 } else if (!strcmp(type, "c")) {
952 mode = S_IFCHR;
953 } else {
954 printf("mknod: invalid type\n");
955 return 1;
956 }
957
958 major = strtol(majorStr, &chptr, 10);
959 if (*chptr) {
960 printf("invalid major number\n");
961 return 1;
962 }
963
964 minor = strtol(minorStr, &chptr, 10);
965 if (*chptr) {
966 printf("invalid minor number\n");
967 return 1;
968 }
969
970 if (smartmknod(path, mode | 0600, makedev(major, minor))) {
971 printf("mknod: failed to create %s: %d\n", path, errno);
972 return 1;
973 }
974
975 return 0;
976 }
977
978 int mkdevicesCommand(char * cmd, char * end) {
979 int fd;
980 char buf[32768];
981 int i;
982 char * start, * chptr;
983 int major, minor;
984 char old;
985 char devName[128];
986 char * prefix;
987
988 if (!(cmd = getArg(cmd, end, &prefix))) {
989 printf("mkdevices: path expected\n");
990 return 1;
991 }
992
993 if (cmd < end) {
994 printf("mkdevices: unexpected arguments\n");
995 return 1;
996 }
997
998 if ((fd = open("/proc/partitions", O_RDONLY)) < 0) {
999 printf("mkrootdev: failed to open /proc/partitions: %d\n", errno);
1000 return 1;
1001 }
1002
1003 i = read(fd, buf, sizeof(buf));
1004 if (i < 1) {
1005 close(fd);
1006 printf("failed to read /proc/partitions: %d\n", errno);
1007 return 1;
1008 }
1009 buf[i] = '\0';
1010 close(fd);
1011
1012 start = strchr(buf, '\n');
1013 if (start) {
1014 start++;
1015 start = strchr(buf, '\n');
1016 }
1017 if (!start) return 1;
1018
1019 start = start + 1;
1020 while (*start) {
1021 while (*start && isspace(*start)) start++;
1022 major = strtol(start, &chptr, 10);
1023
1024 if (start != chptr) {
1025 start = chptr;
1026 while (*start && isspace(*start)) start++;
1027 minor = strtol(start, &chptr, 10);
1028
1029 if (start != chptr) {
1030 start = chptr;
1031 while (*start && isspace(*start)) start++;
1032 while (*start && !isspace(*start)) start++;
1033 while (*start && isspace(*start)) start++;
1034
1035 if (*start) {
1036
1037 chptr = start;
1038 while (!isspace(*chptr)) chptr++;
1039 old = *chptr;
1040 *chptr = '\0';
1041
1042 if (testing) {
1043 printf("% 3d % 3d %s\n", major, minor, start);
1044 } else {
1045 char * ptr, * deviceDir;
1046 int i;
1047
1048 sprintf(devName, "%s/%s", prefix, start);
1049 unlink(devName);
1050
1051 ptr = devName;
1052 i = 0;
1053 while (*ptr)
1054 if (*ptr++ == '/')
1055 i++;
1056 if (i > 2) {
1057 deviceDir = alloca(strlen(devName) + 1);
1058 strcpy(deviceDir, devName);
1059 ptr = deviceDir + (strlen(devName) - 1);
1060 while (*ptr != '/')
1061 *ptr-- = '\0';
1062 if (access(deviceDir, X_OK) && mkdir(deviceDir, 0644)) {
1063 printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno);
1064 }
1065 }
1066 if (smartmknod(devName, S_IFBLK | 0600,
1067 makedev(major, minor))) {
1068 printf("failed to create %s\n", devName);
1069 }
1070 }
1071
1072 *chptr = old;
1073 start = chptr;
1074 }
1075
1076 }
1077 }
1078
1079 start = strchr(start, '\n');
1080 if (!*start) return 1;
1081 start = start + 1;
1082 }
1083
1084 return 0;
1085 }
1086
1087 int runStartup(int fd) {
1088 char contents[32768];
1089 int i;
1090 char * start, * end;
1091 char * chptr;
1092 int rc;
1093
1094 i = read(fd, contents, sizeof(contents) - 1);
1095 if (i == (sizeof(contents) - 1)) {
1096 printf("Failed to read /startup.rc -- file too large.\n");
1097 return 1;
1098 }
1099
1100 contents[i] = '\0';
1101
1102 start = contents;
1103 while (*start) {
1104 while (isspace(*start) && *start && (*start != '\n')) start++;
1105
1106 if (*start == '#')
1107 while (*start && (*start != '\n')) start++;
1108
1109 if (*start == '\n') {
1110 start++;
1111 continue;
1112 }
1113
1114 if (!*start) {
1115 printf("(last line in /startup.rc is empty)\n");
1116 continue;
1117 }
1118
1119 /* start points to the beginning of the command */
1120 end = start + 1;
1121 while (*end && (*end != '\n')) end++;
1122 if (!*end) {
1123 printf("(last line in /startup.rc missing \\n -- skipping)\n");
1124 start = end;
1125 continue;
1126 }
1127
1128 /* end points to the \n at the end of the command */
1129
1130 chptr = start;
1131 while (chptr < end && !isspace(*chptr)) chptr++;
1132
1133 if (!strncmp(start, "mount", MAX(5, chptr - start)))
1134 rc = mountCommand(chptr, end);
1135 else if (!strncmp(start, "losetup", MAX(7, chptr - start)))
1136 rc = losetupCommand(chptr, end);
1137 else if (!strncmp(start, "echo", MAX(4, chptr - start)))
1138 rc = echoCommand(chptr, end);
1139 else if (!strncmp(start, "raidautorun", MAX(11, chptr - start)))
1140 rc = raidautorunCommand(chptr, end);
1141 else if (!strncmp(start, "pivot_root", MAX(10, chptr - start)))
1142 rc = pivotrootCommand(chptr, end);
1143 else if (!strncmp(start, "mkrootdev", MAX(9, chptr - start)))
1144 rc = mkrootdevCommand(chptr, end);
1145 else if (!strncmp(start, "umount", MAX(6, chptr - start)))
1146 rc = umountCommand(chptr, end);
1147 else if (!strncmp(start, "exec", MAX(4, chptr - start)))
1148 rc = execCommand(chptr, end);
1149 else if (!strncmp(start, "mkdir", MAX(5, chptr - start)))
1150 rc = mkdirCommand(chptr, end);
1151 else if (!strncmp(start, "access", MAX(6, chptr - start)))
1152 rc = accessCommand(chptr, end);
1153 else if (!strncmp(start, "find", MAX(4, chptr - start)))
1154 rc = findCommand(chptr, end);
1155 else if (!strncmp(start, "findlodev", MAX(7, chptr - start)))
1156 rc = findlodevCommand(chptr, end);
1157 else if (!strncmp(start, "showlabels", MAX(10, chptr-start)))
1158 rc = display_uuid_cache();
1159 else if (!strncmp(start, "mkdevices", MAX(9, chptr-start)))
1160 rc = mkdevicesCommand(chptr, end);
1161 else if (!strncmp(start, "sleep", MAX(5, chptr-start)))
1162 rc = sleepCommand(chptr, end);
1163 else if (!strncmp(start, "mknod", MAX(5, chptr-start)))
1164 rc = mknodCommand(chptr, end);
1165 else if (!strncmp(start, "readlink", MAX(8, chptr-start)))
1166 rc = readlinkCommand(chptr, end);
1167 else {
1168 *chptr = '\0';
1169 rc = otherCommand(start, chptr + 1, end, 1);
1170 }
1171
1172 start = end + 1;
1173 }
1174
1175 return rc;
1176 }
1177
1178 int main(int argc, char **argv) {
1179 int fd = 0;
1180 char * name;
1181 int rc;
1182 int force = 0;
1183
1184 name = strrchr(argv[0], '/');
1185 if (!name)
1186 name = argv[0];
1187 else
1188 name++;
1189
1190 if (!strcmp(name, "modprobe"))
1191 exit(0);
1192
1193 testing = (getppid() != 0) && (getppid() != 1);
1194 argv++, argc--;
1195
1196 while (argc && **argv == '-') {
1197 if (!strcmp(*argv, "--force")) {
1198 force = 1;
1199 argv++, argc--;
1200 testing = 0;
1201 } else if (!strcmp(*argv, "--quiet")) {
1202 quiet = 1;
1203 argv++, argc--;
1204 } else {
1205 printf("unknown argument %s\n", *argv);
1206 return 1;
1207 }
1208 }
1209
1210 if (force && !quiet)
1211 printf("(forcing normal run)\n");
1212
1213 if (testing && !quiet)
1214 printf("(running in test mode).\n");
1215
1216 if (!quiet) printf("Red Hat nash version %s starting\n", VERSION);
1217
1218 if (*argv) {
1219 fd = open(*argv, O_RDONLY, 0);
1220 if (fd < 0) {
1221 printf("nash: cannot open %s: %d\n", *argv, errno);
1222 exit(1);
1223 }
1224 }
1225
1226 rc = runStartup(fd);
1227 close(fd);
1228
1229 return rc;
1230 }