2 * Copyright (c) 2014 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
6 * Most simple built-in commands are here.
11 #include <sys/types.h>
13 #include <sys/mount.h>
24 /* Need to tell loop.h what the actual dev_t type is. */
26 #if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
27 #define dev_t unsigned int
29 #define dev_t unsigned short
31 #include <linux/loop.h>
37 do_echo(int argc, const char ** argv)
49 fputs(*(++argv), stdout);
59 do_pwd(int argc, const char ** argv)
63 if (getcwd(buf, PATH_LEN) == NULL)
65 fprintf(stderr, "Cannot get current directory\n");
77 do_cd(int argc, const char ** argv)
85 path = getenv("HOME");
89 fprintf(stderr, "No HOME environment variable\n");
107 do_mkdir(int argc, const char ** argv)
113 if (mkdir(argv[1], 0777) < 0)
127 do_mknod(int argc, const char ** argv)
136 if (strcmp(argv[2], "b") == 0)
138 else if (strcmp(argv[2], "c") == 0)
142 fprintf(stderr, "Bad device type\n");
150 while (isDecimal(*cp))
151 major = major * 10 + *cp++ - '0';
153 if (*cp || (major < 0) || (major > 255))
155 fprintf(stderr, "Bad major number\n");
163 while (isDecimal(*cp))
164 minor = minor * 10 + *cp++ - '0';
166 if (*cp || (minor < 0) || (minor > 255))
168 fprintf(stderr, "Bad minor number\n");
173 if (mknod(argv[1], mode, major * 256 + minor) < 0)
187 do_pivot_root(int argc, const char ** argv)
189 if (pivot_root(argv[1], argv[2]) < 0)
191 perror("pivot_root");
202 #if HAVE_LINUX_CHROOT
205 do_chroot(int argc, const char ** argv)
207 if (chroot(argv[1]) < 0)
221 do_rmdir(int argc, const char ** argv)
227 if (rmdir(argv[1]) < 0)
241 do_sync(int argc, const char ** argv)
250 do_rm(int argc, const char ** argv)
256 if (unlink(argv[1]) < 0)
270 do_chmod(int argc, const char ** argv)
281 mode = mode * 8 + (*cp++ - '0');
285 fprintf(stderr, "Mode must be octal\n");
295 if (chmod(argv[1], mode) < 0)
309 do_chown(int argc, const char ** argv)
324 while (isDecimal(*cp))
325 uid = uid * 10 + (*cp++ - '0');
329 fprintf(stderr, "Bad uid value\n");
340 fprintf(stderr, "Unknown user name\n");
355 if ((stat(*argv, &statBuf) < 0) ||
356 (chown(*argv, uid, statBuf.st_gid) < 0))
368 do_chgrp(int argc, const char ** argv)
383 while (isDecimal(*cp))
384 gid = gid * 10 + (*cp++ - '0');
388 fprintf(stderr, "Bad gid value\n");
399 fprintf(stderr, "Unknown group name\n");
414 if ((stat(*argv, &statBuf) < 0) ||
415 (chown(*argv, statBuf.st_uid, gid) < 0))
427 do_touch(int argc, const char ** argv)
436 now.modtime = now.actime;
442 fd = open(name, O_CREAT | O_WRONLY | O_EXCL, 0666);
459 if (utime(name, &now) < 0)
471 do_mv(int argc, const char ** argv)
473 const char * srcName;
474 const char * destName;
475 const char * lastArg;
480 lastArg = argv[argc - 1];
482 dirFlag = isDirectory(lastArg);
484 if ((argc > 3) && !dirFlag)
486 fprintf(stderr, "%s: not a directory\n", lastArg);
491 while (!intFlag && (argc-- > 2))
495 if (access(srcName, 0) < 0)
506 destName = buildName(destName, srcName);
508 if (rename(srcName, destName) >= 0)
519 if (!copyFile(srcName, destName, TRUE))
526 if (unlink(srcName) < 0)
538 do_ln(int argc, const char ** argv)
540 const char * srcName;
541 const char * destName;
542 const char * lastArg;
548 if (argv[1][0] == '-')
550 if (strcmp(argv[1], "-s"))
552 fprintf(stderr, "Unknown option\n");
559 fprintf(stderr, "Wrong number of arguments for symbolic link\n");
565 if (symlink(argv[2], argv[3]) < 0)
574 fprintf(stderr, "Symbolic links are not allowed\n");
581 * Here for normal hard links.
583 lastArg = argv[argc - 1];
584 dirFlag = isDirectory(lastArg);
586 if ((argc > 3) && !dirFlag)
588 fprintf(stderr, "%s: not a directory\n", lastArg);
597 if (access(srcName, 0) < 0)
608 destName = buildName(destName, srcName);
610 if (link(srcName, destName) < 0)
624 do_cp(int argc, const char ** argv)
626 const char * srcName;
627 const char * destName;
628 const char * lastArg;
633 lastArg = argv[argc - 1];
635 dirFlag = isDirectory(lastArg);
637 if ((argc > 3) && !dirFlag)
639 fprintf(stderr, "%s: not a directory\n", lastArg);
644 while (!intFlag && (argc-- > 2))
650 destName = buildName(destName, srcName);
652 if (!copyFile(srcName, destName, FALSE))
661 do_mount(int argc, const char ** argv)
678 while ((argc > 0) && (**argv == '-'))
683 while (*++str) switch (*str)
686 if ((argc <= 0) || (**argv == '-'))
688 fprintf(stderr, "Missing file system type\n");
728 fprintf(stderr, "Unknown option\n");
736 fprintf(stderr, "Wrong number of arguments for mount\n");
743 if (mount(argv[0], argv[1], type, flags, 0) < 0)
745 perror("mount failed");
751 struct adosfs_args adosfs;
754 struct msdosfs_args msdosfs;
757 if (!strcmp(type, "ffs") || !strcmp(type, "ufs"))
759 ufs.fspec = (char*) argv[0];
762 else if (!strcmp(type, "adosfs"))
764 adosfs.fspec = (char*) argv[0];
769 else if (!strcmp(type, "cd9660"))
771 iso.fspec = (char*) argv[0];
774 else if (!strcmp(type, "mfs"))
776 mfs.fspec = (char*) argv[0];
779 else if (!strcmp(type, "msdos"))
781 msdosfs.fspec = (char*) argv[0];
788 fprintf(stderr, "Unknown filesystem type: %s", type);
790 "Supported: ffs ufs adosfs cd9660 mfs msdos\n");
795 if (mount(type, argv[1], flags, args) < 0)
808 do_umount(int argc, const char ** argv)
811 if (umount(argv[1]) < 0)
823 (argc > 0) && (**argv == '-');)
839 if (unmount(argv[0], flags) < 0)
852 do_cmp(int argc, const char ** argv)
863 struct stat statBuf1;
864 struct stat statBuf2;
869 if (stat(argv[1], &statBuf1) < 0)
876 if (stat(argv[2], &statBuf2) < 0)
883 if ((statBuf1.st_dev == statBuf2.st_dev) &&
884 (statBuf1.st_ino == statBuf2.st_ino))
886 printf("Files are links to each other\n");
891 if (statBuf1.st_size != statBuf2.st_size)
893 printf("Files are different sizes\n");
898 fd1 = open(argv[1], O_RDONLY);
907 fd2 = open(argv[2], O_RDONLY);
924 cc1 = read(fd1, buf1, sizeof(buf1));
933 cc2 = read(fd2, buf2, sizeof(buf2));
942 if ((cc1 == 0) && (cc2 == 0))
944 printf("Files are identical\n");
951 printf("First file is shorter than second\n");
958 printf("Second file is shorter than first\n");
963 if (memcmp(buf1, buf2, cc1) == 0)
973 while (*bp1++ == *bp2++)
976 printf("Files differ at byte position %ld\n", pos);
991 do_more(int argc, const char ** argv)
1003 * Get the width and height of the screen if it is set.
1004 * If not, then default it.
1009 name = getenv("LINES");
1012 pageLines = atoi(name);
1014 name = getenv("COLS");
1017 pageColumns = atoi(name);
1022 if (pageColumns <= 0)
1026 * OK, process each file.
1032 fp = fopen(name, "r");
1041 printf("<< %s >>\n", name);
1045 while (fp && ((ch = fgetc(fp)) != EOF))
1059 col = ((col + 1) | 0x07) + 1;
1073 if (col >= pageColumns)
1079 if (line < pageLines)
1088 if (intFlag || (read(0, buf, sizeof(buf)) < 0))
1129 do_sum(int argc, const char ** argv)
1136 unsigned long checksum;
1148 fd = open(name, O_RDONLY);
1160 while ((cc = read(fd, buf, sizeof(buf))) > 0)
1162 for (i = 0; i < cc; i++)
1166 if ((checksum & 0x01) != 0)
1167 checksum = (checksum >> 1) + 0x8000;
1169 checksum = (checksum >> 1);
1171 checksum = (checksum + ch) & 0xffff;
1187 printf("%05lu %s\n", checksum, name);
1195 do_exit(int argc, const char ** argv)
1201 fprintf(stderr, "You are the INIT process!\n");
1218 do_setenv(int argc, const char ** argv)
1228 * The value given to putenv must remain around, so we must malloc it.
1229 * Note: memory is not reclaimed if the same variable is redefined.
1231 str = malloc(strlen(name) + strlen(value) + 2);
1235 fprintf(stderr, "Cannot allocate memory\n");
1251 do_printenv(int argc, const char ** argv)
1254 extern char ** environ;
1257 env = (const char **) environ;
1262 printf("%s\n", *env++);
1267 len = strlen(argv[1]);
1271 if ((strlen(*env) > len) && (env[0][len] == '=') &&
1272 (memcmp(argv[1], *env, len) == 0))
1274 printf("%s\n", &env[0][len+1]);
1286 do_umask(int argc, const char ** argv)
1295 printf("%03o\n", mask);
1303 while (isOctal(*cp))
1304 mask = mask * 8 + *cp++ - '0';
1306 if (*cp || (mask & ~0777))
1308 fprintf(stderr, "Bad umask value\n");
1320 do_kill(int argc, const char ** argv)
1330 if (argv[1][0] == '-')
1334 if (strcmp(cp, "HUP") == 0)
1336 else if (strcmp(cp, "INT") == 0)
1338 else if (strcmp(cp, "QUIT") == 0)
1340 else if (strcmp(cp, "KILL") == 0)
1342 else if (strcmp(cp, "STOP") == 0)
1344 else if (strcmp(cp, "CONT") == 0)
1346 else if (strcmp(cp, "USR1") == 0)
1348 else if (strcmp(cp, "USR2") == 0)
1350 else if (strcmp(cp, "TERM") == 0)
1356 while (isDecimal(*cp))
1357 sig = sig * 10 + *cp++ - '0';
1361 fprintf(stderr, "Unknown signal\n");
1376 while (isDecimal(*cp))
1377 pid = pid * 10 + *cp++ - '0';
1381 fprintf(stderr, "Non-numeric pid\n");
1386 if (kill(pid, sig) < 0)
1398 do_where(int argc, const char ** argv)
1400 const char * program;
1401 const char * dirName;
1411 if (strchr(program, '/') != NULL)
1413 fprintf(stderr, "Program name cannot include a path\n");
1418 path = getenv("PATH");
1420 fullPath = getChunk(strlen(path) + strlen(program) + 2);
1421 path = chunkstrdup(path);
1423 if ((path == NULL) || (fullPath == NULL))
1425 fprintf(stderr, "Memory allocation failed\n");
1431 * Check out each path to see if the program exists and is
1432 * executable in that path.
1434 for (; path; path = endPath)
1437 * Find the end of the next path and NULL terminate
1440 endPath = strchr(path, ':');
1446 * Get the directory name, defaulting it to DOT if
1451 if (dirName == '\0')
1455 * Construct the full path of the program.
1457 strcpy(fullPath, dirName);
1458 strcat(fullPath, "/");
1459 strcat(fullPath, program);
1462 * See if the program exists and is executable.
1464 if (access(fullPath, X_OK) < 0)
1466 if (errno != ENOENT)
1475 printf("%s\n", fullPath);
1481 printf("Program \"%s\" not found in PATH\n", program);
1488 #if HAVE_LINUX_LOSETUP
1491 do_losetup(int argc, const char ** argv)
1495 struct loop_info loopInfo;
1497 if (!strcmp(argv[1], "-d"))
1499 loopfd = open(argv[2], O_RDWR);
1503 fprintf(stderr, "Error opening %s: %s\n", argv[2],
1509 if (ioctl(loopfd, LOOP_CLR_FD, 0))
1511 fprintf(stderr, "Error unassociating device: %s\n",
1518 loopfd = open(argv[1], O_RDWR);
1522 fprintf(stderr, "Error opening %s: %s\n", argv[1],
1528 targfd = open(argv[2], O_RDWR);
1532 fprintf(stderr, "Error opening %s: %s\n", argv[2],
1538 if (ioctl(loopfd, LOOP_SET_FD, targfd))
1540 fprintf(stderr, "Error setting up loopback device: %s\n",
1546 memset(&loopInfo, 0, sizeof(loopInfo));
1547 strcpy(loopInfo.lo_name, argv[2]);
1549 if (ioctl(loopfd, LOOP_SET_STATUS, &loopInfo))
1551 fprintf(stderr, "Error setting up loopback device: %s\n",