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