_h’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ü’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ķA@“Œ:!ķA “Œ:!#¤ )“Œ:! ¤n“Œ:!¤~“Œ:!¤“*“Œ:! ¤~ “Œ:!$%&¤Ż“Œ:!'¤Õ“Œ:!(¤“Œ:!)¤¬“Œ:!*+,¤i “Œ:!-./0¤K “Œ:!123¤ “Œ:!4567¤r“Œ:!89:;<=¤£ “Œ:!>?@¤ŹN“Œ:!ABCDEFGI¤Ó“Œ:!V¤ō“Œ:!W¤ź “Œ:!XYZ¤  “Œ:![\]^¤ń“Œ:!_`¤)“Œ:!a¤„“Œ:!bcde¤>“Œ:!fg¤:“Œ:!hi¤»“Œ:!jk¤o“Œ:!lm¤|2“Œ:!nopqrstv¤'“Œ:!|}¤He„Œ:!~€‚ƒ„†¤ć“Œ:!—¤e“Œ:!˜¤O “Œ:!™š›œ¤I“Œ:!žŸ ”¢¤P “Œ:!£¤„¤¢“Œ:!¦§Ø©Ŗ«¬¤c“Œ:!­®¤Ŗ“Œ:!ư¤ “Œ:!±²³¤ŗ “Œ:!“µ¶¤$O“Œ:!·ø¹ŗ»¼½æ¤X“Œ:!̤ę“Œ:!Ķԁš“Œ:!ĻŠ¤«“Œ:!Ѥœz“Œ:!ŅÓŌÕÖ×ŲŚ¤¹“Œ:!ņ󤁩 “Œ:!ōõö¤d“Œ:!÷ų¤¼“Œ:!łś¤Œ“Œ:!ū¤«“Œ:!üżž’¤¢$“Œ:! ¤”“Œ:!  ¤S “Œ:!¤ē“Œ:!¤Ć “Œ:!¤¤“Œ:!¤æ “Œ:!¤ “Œ:!¤h “Œ:!’A “Œ:! ’A0“Œ:!!¤“Œ:!"’A0“Œ:!$¤£“Œ:!%’A0“Œ:!&¤“Œ:!'’Aą“Œ:!(¤;“Œ:!)¤”“Œ:!*¤m“Œ:!+,¤9“Œ:!-¤'“Œ:!.¤€“Œ:!/¤z“Œ:!0¤.“Œ:!1¤ž“Œ:!2¤“Œ:!34¤]“Œ:!5¤«“Œ:!67Ō ...commandsFinclude...ar.cbasename.ccat.ccc.cchmem.cchmod.c chown.c clr.c cmp.c comm.c cp.cdate.cdd.cdf.cdosread.cecho.cgetlf.cgrep.cgres.chead.ckill.clibpack.clibupack.cln.clogin.clpr.cls.cmkdir.cmkfs.c mknod.c!mount.c"mv.c#od.c$passwd.c%pr.c&pwd.c'rev.c(rm.c)rmdir.c*roff.c+run,shar.c-size.c.sleep.c/sort.c0split.c1stty.c2su.c3sum.c4sync.c5tail.c6tar.c7tee.c8time.c9touch.c:tr.c;umount.c<uniq.c=update.c>wc.c?bin@MINIX/* ar - archiver Author: Michiel Huisjes */ /* * Usage: ar [adprtvx] archive [file] ... * v: verbose * x: extract * a: append * r: replace (append when not in archive) * d: delete * t: print contents of archive * p: print named files */ #include "stat.h" #include "signal.h" #define MAGIC_NUMBER 0177545 #define odd(nr) (nr & 01) #define even(nr) (odd(nr) ? nr + 1 : nr) union swabber { struct sw { short mem_1; short mem_2; } mem; long joined; } swapped; long swap (); typedef struct { char m_name[14]; short m_time_1; short m_time_2; char m_uid; char m_gid; short m_mode; short m_size_1; short m_size_2; } MEMBER; typedef char BOOL; #define FALSE 0 #define TRUE 1 #define READ 0 #define APPEND 2 #define CREATE 1 #define NIL_PTR ((char *) 0) #define NIL_MEM ((MEMBER *) 0) #define NIL_LONG ((long *) 0) #define IO_SIZE (10 * 1024) #define BLOCK_SIZE 1024 #define flush() print(NIL_PTR) #define equal(str1, str2) (!strncmp((str1), (str2), 14)) BOOL verbose; BOOL app_fl; BOOL ex_fl; BOOL show_fl; BOOL pr_fl; BOOL rep_fl; BOOL del_fl; int ar_fd; long mem_time, mem_size; char io_buffer[IO_SIZE]; char terminal[BLOCK_SIZE]; char temp_arch[] = "/tmp/ar.XXXXX"; usage() { error(TRUE, "Usage: ar [adprtxv] archive [file] ...", NIL_PTR); } error(quit, str1, str2) BOOL quit; char *str1, *str2; { write(2, str1, strlen(str1)); if (str2 != NIL_PTR) write(2, str2, strlen(str2)); write(2, "\n", 1); if (quit) { (void) unlink(temp_arch); exit(1); } } char *basename(path) char *path; { register char *ptr = path; register char *last = NIL_PTR; while (*ptr != '\0') { if (*ptr == '/') last = ptr; ptr++; } if (last == NIL_PTR) return path; if (*(last + 1) == '\0') { *last = '\0'; return basename(path); } return last + 1; } open_archive(name, mode) register char *name; register int mode; { unsigned short magic = 0; int fd; if (mode == CREATE) { if ((fd = creat(name, 0644)) < 0) error(TRUE, "Cannot creat ", name); magic = MAGIC_NUMBER; mwrite(fd, &magic, sizeof(magic)); return fd; } if ((fd = open(name, mode)) < 0) { if (mode == APPEND) { (void) close(open_archive(name, CREATE)); error(FALSE, "ar: creating ", name); return open_archive(name, APPEND); } error(TRUE, "Cannot open ", name); } (void) lseek(fd, 0L, 0); (void) read(fd, &magic, sizeof(magic)); if (magic != MAGIC_NUMBER) error(TRUE, name, " is not in ar format."); return fd; } catch() { (void) unlink(temp_arch); exit (2); } main(argc, argv) int argc; char *argv[]; { register char *ptr; int pow, pid; if (argc < 3) usage(); for (ptr = argv[1]; *ptr; ptr++) { switch (*ptr) { case 't' : show_fl = TRUE; break; case 'v' : verbose = TRUE; break; case 'x' : ex_fl = TRUE; break; case 'a' : app_fl = TRUE; break; case 'p' : pr_fl = TRUE; break; case 'd' : del_fl = TRUE; break; case 'r' : rep_fl = TRUE; break; default : usage(); } } if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1) usage(); if (rep_fl || del_fl) { ptr = &temp_arch[8]; pid = getpid(); pow = 10000; while (pow != 0) { *ptr++ = (pid / pow) + '0'; pid %= pow; pow /= 10; } } signal(SIGINT, catch); get(argc, argv); exit(0); } MEMBER *get_member() { static MEMBER member; register int ret; if ((ret = read(ar_fd, &member, sizeof(MEMBER))) == 0) return NIL_MEM; if (ret != sizeof(MEMBER)) error(TRUE, "Corrupted archive.", NIL_PTR); mem_time = swap (&(member.m_time_1)); mem_size = swap (&(member.m_size_1)); return &member; } long swap (sw_ptr) union swabber *sw_ptr; { swapped.mem.mem_1 = (sw_ptr->mem).mem_2; swapped.mem.mem_2 = (sw_ptr->mem).mem_1; return swapped.joined; } get(argc, argv) int argc; register char *argv[]; { register MEMBER *member; int i = 0; int temp_fd, read_chars; ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND); if (rep_fl || del_fl) temp_fd = open_archive(temp_arch, CREATE); while ((member = get_member()) != NIL_MEM) { if (argc > 3) { for (i = 3; i < argc; i++) { if (equal(basename(argv[i]), member->m_name)) break; } if (i == argc || app_fl) { if (rep_fl || del_fl) { mwrite(temp_fd, member,sizeof(MEMBER)); copy_member(member, ar_fd, temp_fd); } else { if (app_fl && i != argc) { print(argv[i]); print(": already in archive.\n"); argv[i] = ""; } (void) lseek(ar_fd, even(mem_size),1); } continue; } } if (ex_fl || pr_fl) extract(member); else { if (rep_fl) add(argv[i], temp_fd, 'r'); else if (show_fl) { if (verbose) { print_mode(member->m_mode); if (member->m_uid < 10) print(" "); litoa(0, (long) member->m_uid); print("/"); litoa(0, (long) member->m_gid); litoa(8, mem_size); date(mem_time); } p_name(member->m_name); print("\n"); } else if (del_fl) show('d', member->m_name); (void) lseek(ar_fd, even(mem_size), 1); } argv[i] = ""; } if (argc > 3) { for (i = 3; i < argc; i++) if (argv[i][0] != '\0') { if (app_fl) add(argv[i], ar_fd, 'a'); else if (rep_fl) add(argv[i], temp_fd, 'a'); else { print(argv[i]); print(": not found\n"); } } } flush(); if (rep_fl || del_fl) { signal(SIGINT, SIG_IGN); (void) close(ar_fd); (void) close(temp_fd); ar_fd = open_archive(argv[2], CREATE); temp_fd = open_archive(temp_arch, APPEND); while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0) mwrite(ar_fd, io_buffer, read_chars); (void) close(temp_fd); (void) unlink(temp_arch); } (void) close(ar_fd); } add(name, fd, mess) char *name; int fd; char mess; { static MEMBER member; register int read_chars; struct stat status; int src_fd; if (stat(name, &status) < 0) { error(FALSE, "Cannot find ", name); return; } else if ((src_fd = open(name, 0)) < 0) { error(FALSE, "Cannot open ", name); return; } strcpy (member.m_name, basename (name)); member.m_uid = status.st_uid; member.m_gid = status.st_gid; member.m_mode = status.st_mode & 07777; (void) swap (&(status.st_mtime)); member.m_time_1 = swapped.mem.mem_1; member.m_time_2 = swapped.mem.mem_2; (void) swap (&(status.st_size)); member.m_size_1 = swapped.mem.mem_1; member.m_size_2 = swapped.mem.mem_2; mwrite (fd, &member, sizeof (MEMBER)); while ((read_chars = read(src_fd, io_buffer, IO_SIZE)) > 0) mwrite(fd, io_buffer, read_chars); if (odd(status.st_size)) mwrite(fd, io_buffer, 1); if (verbose) show(mess, name); (void) close(src_fd); } extract(member) register MEMBER *member; { int fd = 1; if (pr_fl == FALSE && (fd = creat(member->m_name, 0644)) < 0) { error(FALSE, "Cannot create ", member->m_name); return; } if (verbose && pr_fl == FALSE) show('x', member->m_name); copy_member(member, ar_fd, fd); if (fd != 1) (void) close(fd); (void) chmod(member->m_name, member->m_mode); } copy_member(member, from, to) register MEMBER *member; int from, to; { register int rest; BOOL is_odd = odd(mem_size) ? TRUE : FALSE; do { rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size; if (read(from, io_buffer, rest) != rest) error(TRUE, "Read error on ", member->m_name); mwrite(to, io_buffer, rest); mem_size -= (long) rest; } while (mem_size != 0L); if (is_odd) { (void) lseek(from, 1L, 1); if (rep_fl || del_fl) (void) lseek(to, 1L, 1); } } print(str) register char *str; { static index = 0; if (str == NIL_PTR) { write(1, terminal, index); index = 0; return; } while (*str != '\0') { terminal[index++] = *str++; if (index == BLOCK_SIZE) flush(); } } print_mode(mode) register int mode; { static char mode_buf[11]; register int tmp = mode; int i; mode_buf[9] = ' '; for (i = 0; i < 3; i++) { mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-'; mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-'; mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-'; tmp <<= 3; } if (mode & S_ISUID) mode_buf[2] = 's'; if (mode & S_ISGID) mode_buf[5] = 's'; print(mode_buf); } litoa(pad, number) int pad; long number; { static char num_buf[11]; register long digit; register long pow = 1000000000L; int digit_seen = FALSE; int i; for (i = 0; i < 10; i++) { digit = number / pow; if (digit == 0L && digit_seen == FALSE && i != 9) num_buf[i] = ' '; else { num_buf[i] = '0' + (char) digit; number -= digit * pow; digit_seen = TRUE; } pow /= 10L; } for (i = 0; num_buf[i] == ' ' && i + pad < 11; i++) ; print(&num_buf[i]); } mwrite(fd, address, bytes) int fd; register char *address; register int bytes; { if (write(fd, address, bytes) != bytes) error(TRUE, "Write error.", NIL_PTR); } show(c, name) char c; register char *name; { write(1, &c, 1); write(1, " - ", 3); write(1, name, strlen(name)); write(1, "\n", 1); } p_name(mem_name) register char *mem_name; { register int i = 0; char name[15]; for (i = 0; i < 14 && *mem_name; i++) name[i] = *mem_name++; name[i] = '\0'; print(name); } #define MINUTE 60L #define HOUR (60L * MINUTE) #define DAY (24L * HOUR) #define YEAR (365L * DAY) #define LYEAR (366L * DAY) int mo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *moname[] = { " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ", " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec " }; /* Print the date. This only works from 1970 to 2099. */ date(t) long t; { int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if (t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = (int) (t / DAY); t -= (long) day * DAY; hour = (int) (t / HOUR); t -= (long) hour * HOUR; minute = (int) (t / MINUTE); /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ print(moname[month]); day++; if (day < 10) print(" "); litoa(0, (long) day); print(" "); if (time(NIL_LONG) - original >= YEAR / 2L) litoa(1, (long) year); else { if (hour < 10) print("0"); litoa(0, (long) hour); print(":"); if (minute < 10) print("0"); litoa(0, (long) minute); } print(" "); } /* basename - print the last part of a path: Author: Blaine Garfolo */ #define NULL 0 main(argc,argv) int argc; char *argv[]; { int j,suflen; char *c; char *d; extern char *rindex(); if (argc < 2) { std_err("Usage: basename string [suffix] \n"); exit(1); } c=argv[1]; d = rindex(argv[1],'/'); if (d == NULL) d = argv[1]; else d++; if (argc == 2) { /* if no suffix */ prints("%s\n",d); exit(0); } else { /* if suffix is present */ c = d; suflen = strlen(argv[2]); j = strlen(c) - suflen; if (strcmp(c+j, argv[2]) == 0) *(c+j) = 0; } prints("%s\n",c); } /* cat - concatenates files Author: Andy Tanenbaum */ extern int errno; /*DEBUG*/ #include "blocksize.h" #include "stat.h" #define BUF_SIZE 512 int unbuffered; char buffer[BUF_SIZE]; char *next = buffer; main(argc, argv) int argc; char *argv[]; { int i, k, m, fd1; char *p; struct stat sbuf; k = 1; /* Check for the -u flag -- unbuffered operation. */ p = argv[1]; if (argc >=2 && *p == '-' && *(p+1) == 'u') { unbuffered = 1; k = 2; } if (k >= argc) { copyfile(0, 1); flush(); exit(0); } for (i = k; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 0) { fd1 = 0; } else { fd1 = open(argv[i], 0); if (fd1 < 0) { std_err("cat: cannot open "); std_err(argv[i]); std_err("\n"); continue; } } copyfile(fd1, 1); if (fd1 != 0) close(fd1); } flush(); exit(0); } copyfile(fd1, fd2) int fd1, fd2; { int n, j, m; char buf[BLOCK_SIZE]; while (1) { n = read(fd1, buf, BLOCK_SIZE); if (n < 0) quit(); if (n == 0) return; if (unbuffered) { m = write(fd2, buf, n); if (m != n) quit(); } else { for (j = 0; j < n; j++) { *next++ = buf[j]; if (next == &buffer[BUF_SIZE]) { m = write(fd2, buffer, BUF_SIZE); if (m != BUF_SIZE) quit(); next = buffer; } } } } } flush() { if (next != buffer) if (write(1, buffer, (int) (next - buffer)) <= 0) quit(); } quit() { perror("cat"); exit(1); } /* Driver for the CEMCOM compiler. Derived from: "cem.c,v 1.5 86/01/20 11:10:29 erikb Exp" Author: Erik Baalbergen Log: Date written: Dec 4, 1985 Adapted for PC/IX on Jan 20, 1986 Strongly reduced (May 14, 1986) Piping output from cpp into cem (Jul 30, 1986) Create temporary files in TMP directory (Aug 6, 1986) Pass hint for optimization to cg (Aug 15, 1986) Throw away intermediate files on interrupts (Aug 15, 1986) Print file name if there are more than one source files (Sep 22, 1986) Various minor corrections for MINIX (Mar 18, 1987) */ #include #include #define MAXARGC 64 /* maximum number of arguments allowed in a list */ #define USTR_SIZE 64 /* maximum length of string variable */ typedef char USTRING[USTR_SIZE]; struct arglist { int al_argc; char *al_argv[MAXARGC]; }; !!!!_SEE_BELOW_!!! /* This is not an error. It is a dirty trick to force the user to read this * comment. The program cc calls the various passes of the compiler. To call * them, it must know where they are. On the 640K PC MINIX, cpp and cem are * kept in /lib, on the root device. Thus the symbol PP is defined as * /lib/cpp, etc. On the 512K AT, there is no room on the root device, so cpp * and cem are kept in /usr/lib, which means that PP must be /usr/lib/cpp, * etc. One of the following two definitions must be uncommented, to * generate the right paths. For 640K machines (PCs or Ats), MEM640K should * be defined. For 512K machines, MEM512K should be defined. */ /* #define MEM640K */ /* #define MEM512K */ #ifdef MEM640K /* MINIX paths for 640K PC (not 512K AT) */ char *PP = "/lib/cpp"; char *CEM = "/lib/cem"; char *OPT = "/usr/lib/opt"; char *CG = "/usr/lib/cg"; char *ASLD = "/usr/bin/asld"; char *SHELL = "/bin/sh"; char *LIBDIR = "/usr/lib"; #endif #ifdef MEM512K /* MINIX paths for 512K AT (not 640K PC) */ char *PP = "/usr/lib/cpp"; char *CEM = "/usr/lib/cem"; char *OPT = "/usr/lib/opt"; char *CG = "/usr/lib/cg"; char *ASLD = "/usr/bin/asld"; char *SHELL = "/bin/sh"; char *LIBDIR = "/usr/lib"; #endif struct arglist LD_HEAD = { 1, { "/usr/lib/crtso.s", } }; struct arglist LD_TAIL = { 2, { "/usr/lib/libc.a", "/usr/lib/end.s" } }; char *o_FILE = "a.out"; /* default name for executable file */ #define remove(str) (unlink(str), (str)[0] = '\0') #define cleanup(str) (str && remove(str)) #define init(al) (al)->al_argc = 1 #define library(nm) \ mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \ LIBDIR, "/lib", nm, ".a", 0) char *ProgCall = 0; struct arglist SRCFILES; struct arglist LDFILES; struct arglist GEN_LDFILES; struct arglist PP_FLAGS; struct arglist CEM_FLAGS; int RET_CODE = 0; struct arglist OPT_FLAGS; struct arglist CG_FLAGS; struct arglist ASLD_FLAGS; struct arglist DEBUG_FLAGS; struct arglist CALL_VEC[2]; int o_flag = 0; int S_flag = 0; int v_flag = 0; int F_flag = 0; /* use pipes by default */ char *mkstr(); char *alloc(); USTRING ifile, kfile, sfile, mfile, ofile; USTRING BASE; char *tmpdir = "/tmp"; char tmpname[15]; #ifdef DEBUG int noexec = 0; #endif trapcc(sig) int sig; { signal(sig, SIG_IGN); cleanup(ifile); cleanup(kfile); cleanup(sfile); cleanup(mfile); cleanup(ofile); } main(argc, argv) char *argv[]; { char *str; char **argvec; int count; int ext; register struct arglist *call = &CALL_VEC[0], *call1 = &CALL_VEC[1]; char *file; char *ldfile = 0; ProgCall = *argv++; signal(SIGHUP, trapcc); signal(SIGINT, trapcc); signal(SIGQUIT, trapcc); while (--argc > 0) { if (*(str = *argv++) != '-') { append(&SRCFILES, str); continue; } switch (str[1]) { case 'c': S_flag = 1; break; case 'D': case 'I': case 'U': append(&PP_FLAGS, str); break; case 'F': F_flag = 1; break; case 'l': append(&SRCFILES, library(&str[2])); break; case 'o': o_flag = 1; if (argc-- >= 0) o_FILE = *argv++; break; case 'O': append(&CG_FLAGS, "-p4"); break; case 'S': S_flag = 1; break; case 'v': v_flag++; #ifdef DEBUG if (str[2] == 'n') noexec = 1; #endif DEBUG break; case 'T': tmpdir = &str[2]; append(&ASLD_FLAGS, str); /*FALLTHROUGH*/ case 'R': case 'p': case 'w': append(&CEM_FLAGS, str); break; case 'L': if (strcmp(&str[1], "LIB") == 0) { append(&OPT_FLAGS, "-L"); break; } /*FALLTHROUGH*/ default: /* -i goes here! */ append(&ASLD_FLAGS, str); break; } } mktempname(tmpname); append(&CEM_FLAGS, "-L"); /* disable profiling */ count = SRCFILES.al_argc; argvec = &(SRCFILES.al_argv[0]); while (count-- > 0) { register char *f; basename(file = *argvec++, BASE); if (SRCFILES.al_argc > 1) { write(1, file, strlen(file)); write(1, ":\n", 2); } ext = extension(file); if (ext == 'c') { /* .c to .i (if F_flag) or .k */ init(call); append(call, PP); concat(call, &PP_FLAGS); append(call, file); if (F_flag) { /* to .i */ f = mkstr(ifile, tmpdir, tmpname, ".i", 0); if (runvec(call, f)) { file = ifile; ext = 'i'; } else { remove(ifile); continue; } } else { /* use a pipe; to .k */ init(call1); append(call1, CEM); concat(call1, &DEBUG_FLAGS); concat(call1, &CEM_FLAGS); append(call1, "-"); /* use stdin */ f = mkstr(kfile, tmpdir, tmpname, ".k", 0); append(call1, f); if (runvec2(call, call1)) { file = kfile; ext = 'k'; } else { remove(kfile); continue; } } } if (ext == 'i') { /* .i to .k */ init(call); append(call, CEM); concat(call, &DEBUG_FLAGS); concat(call, &CEM_FLAGS); append(call, file); f = mkstr(kfile, tmpdir, tmpname, ".k", 0); append(call, f); if (runvec(call, (char *)0)) { file = kfile; ext = 'k'; } else { remove(kfile); continue; } cleanup(ifile); } /* .k to .m */ if (ext == 'k') { init(call); append(call, OPT); concat(call, &OPT_FLAGS); append(call, file); f = mkstr(mfile, tmpdir, tmpname, ".m", 0); if (runvec(call, f) == 0) continue; file = mfile; ext = 'm'; cleanup(kfile); } /* .m to .s */ if (ext == 'm') { ldfile = S_flag ? ofile : alloc(strlen(BASE) + 3); init(call); append(call, CG); concat(call, &CG_FLAGS); append(call, file); f = mkstr(ldfile, BASE, ".s", 0); append(call, f); if (runvec(call, (char *)0) == 0) continue; cleanup(mfile); file = ldfile; ext = 's'; } if (S_flag) continue; append(&LDFILES, file); if (ldfile) { append(&GEN_LDFILES, ldfile); ldfile = 0; } } /* *.s to a.out */ if (RET_CODE == 0 && LDFILES.al_argc > 0) { init(call); append(call, ASLD); concat(call, &ASLD_FLAGS); append(call, "-o"); append(call, o_FILE); concat(call, &LD_HEAD); concat(call, &LDFILES); concat(call, &LD_TAIL); if (runvec(call, (char *)0)) { register i = GEN_LDFILES.al_argc; while (i-- > 0) remove(GEN_LDFILES.al_argv[i]); } } return(RET_CODE); } #define BUFSIZE (USTR_SIZE * MAXARGC) char buf[BUFSIZE]; char *bufptr = &buf[0]; char * alloc(u) unsigned u; { register char *p = bufptr; if ((bufptr += u) >= &buf[BUFSIZE]) panic("no space\n"); return p; } append(al, arg) struct arglist *al; char *arg; { if (al->al_argc >= MAXARGC) panic("argument list overflow\n"); al->al_argv[(al->al_argc)++] = arg; } concat(al1, al2) struct arglist *al1, *al2; { register i = al2->al_argc; register char **p = &(al1->al_argv[al1->al_argc]); register char **q = &(al2->al_argv[0]); if ((al1->al_argc += i) >= MAXARGC) panic("argument list overflow\n"); while (i-- > 0) *p++ = *q++; } /*VARARGS1*/ char * mkstr(dst, arg) char *dst, *arg; { char **vec = (char **) &arg; register char *p; register char *q = dst; while (p = *vec++) { while (*q++ = *p++); q--; } return dst; } basename(str, dst) char *str; register char *dst; { register char *p1 = str; register char *p2 = p1; while (*p1) if (*p1++ == '/') p2 = p1; p1--; if (*--p1 == '.') { *p1 = '\0'; while (*dst++ = *p2++); *p1 = '.'; } else while (*dst++ = *p!"#2++); } int extension(fn) register char *fn; { char c; while (*fn++) ; fn--; c = *--fn; return (*--fn == '.') ? c : 0; } runvec(vec, outp) struct arglist *vec; char *outp; { int pid, fd, status; if (v_flag) { pr_vec(vec); write(2, "\n", 1); } if ((pid = fork()) == 0) { /* start up the process */ if (outp) { /* redirect standard output */ close(1); if ((fd = creat(outp, 0666)) != 1) panic("cannot create output file\n"); } ex_vec(vec); } if (pid == -1) panic("no more processes\n"); wait(&status); return status ? ((RET_CODE = 1), 0) : 1; } runvec2(vec0, vec1) register struct arglist *vec0, *vec1; { /* set up 'vec0 | vec1' */ int pid, status1, status2, p[2]; if (v_flag) { pr_vec(vec0); write(2, " | ", 3); pr_vec(vec1); write(2, "\n", 1); } if (pipe(p) == -1) panic("cannot create pipe\n"); if ((pid = fork()) == 0) { close(1); if (dup(p[1]) != 1) panic("bad dup\n"); close(p[0]); close(p[1]); ex_vec(vec0); } if (pid == -1) panic("no more processes\n"); if ((pid = fork()) == 0) { close(0); if (dup(p[0]) != 0) panic("bad dup\n"); close(p[0]); close(p[1]); ex_vec(vec1); } if (pid == -1) panic("no more processes\n"); close(p[0]); close(p[1]); wait(&status1); wait(&status2); return (status1 || status2) ? ((RET_CODE = 1), 0) : 1; } /*VARARGS1*/ panic(str, argv) char *str; int argv; { write(2, str, strlen(str)); exit(1); } char * cindex(s, c) char *s, c; { while (*s) if (*s++ == c) return s - 1; return (char *) 0; } pr_vec(vec) register struct arglist *vec; { register char **ap = &vec->al_argv[1]; vec->al_argv[vec->al_argc] = 0; write(2, *ap, strlen(*ap) ); while (*++ap) { write(2, " ", 1); write(2, *ap, strlen(*ap)); } } ex_vec(vec) register struct arglist *vec; { extern int errno; #ifdef DEBUG if (noexec) exit(0); #endif vec->al_argv[vec->al_argc] = 0; execv(vec->al_argv[1], &(vec->al_argv[1])); if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */ vec->al_argv[0] = SHELL; execv(SHELL, &(vec->al_argv[0])); } if (access(vec->al_argv[1], 1) == 0) { /* File is executable. */ write(2, "Cannot execute ", 15); write(2, vec->al_argv[1], strlen(vec->al_argv[1])); write(2, ". Not enough memory.\n", 21); write(2, "Try cc -F or use chmem to reduce its stack allocation\n",54); } else { write(2, vec->al_argv[1], strlen(vec->al_argv[1])); write(2, " is not executable\n", 19); } exit(1); } mktempname(nm) char nm[]; { register i; int pid = getpid(); nm[0] = '/'; nm[1] = 'c'; nm[2] = 'e'; nm[3] = 'm'; for (i = 9; i > 3; i--) { nm[i] = (pid % 10) + '0'; pid /= 10; } nm[10] = '\0'; /* null termination */ } /* chmem - set total memory size for execution Author: Andy Tanenbaum */ #define HLONG 8 /* header size in longs */ #define TEXT 2 /* where is text size in header */ #define DATA 3 /* where is data size in header */ #define BSS 4 /* where is bss size in header */ #define TOT 6 /* where in header is total allocation */ #define TOTPOS 24 /* where is total in header */ #define SEPBIT 0x00200000 /* this bit is set for separate I/D */ #define MAGIC 0x0301 /* magic number for executable progs */ #define MAX 65536L /* maximum allocation size */ main(argc, argv) int argc; char *argv[]; { /* The 8088 architecture does not make it possible to catch stacks that grow * big. The only way to deal with this problem is to let the stack grow down * towards the data segment and the data segment grow up towards the stack. * Normally, a total of 64K is allocated for the two of them, but if the * programmer knows that a smaller amount is sufficient, he can change it * using chmem. * * chmem =4096 prog sets the total space for stack + data growth to 4096 * chmem +200 prog increments the total space for stack + data growth by 200 */ char *p; unsigned int n; int fd, separate; long lsize, olddynam, newdynam, newtot, overflow, header[HLONG]; p = argv[1]; if (argc != 3) usage(); if (*p != '=' && *p != '+' && *p != '-') usage(); n = atoi(p+1); lsize = n; if (n > 65520) stderr3("chmem: ", p+1, " too large\n"); fd = open(argv[2], 2); if (fd < 0) stderr3("chmem: can't open ", argv[2], "\n"); if (read(fd, header, sizeof(header)) != sizeof(header)) stderr3("chmem: ", argv[2], "bad header\n"); if ( (header[0] & 0xFFFF) != MAGIC) stderr3("chmem: ", argv[2], " not executable\n"); separate = (header[0] & SEPBIT ? 1 : 0); olddynam = header[TOT] - header[DATA] - header[BSS]; if (separate == 0) olddynam -= header[TEXT]; if (*p == '=') newdynam = lsize; else if (*p == '+') newdynam = olddynam + lsize; else if (*p == '-') newdynam = olddynam - lsize; newtot = header[DATA] + header[BSS] + newdynam; overflow = (newtot > MAX ? newtot - MAX : 0); /* 64K max */ newdynam -= overflow; newtot -= overflow; if (separate == 0) newtot += header[TEXT]; lseek(fd, (long) TOTPOS, 0); if (write(fd, &newtot, 4) < 0) stderr3("chmem: can't modify ", argv[2], "\n"); printf("%s: Stack+malloc area changed from %D to %D bytes.\n", argv[2], olddynam, newdynam); exit(0); } usage() { std_err("chmem {=+-} amount file\n"); exit(1); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); exit(1); } /* * chmod [mode] files * change mode of files * * by Patrick van Kleef */ main (argc, argv) int argc; char *argv[]; { int i; int status = 0; int newmode; if (argc < 3) { Usage (); } newmode = oatoi (argv[1]); for (i = 2; i < argc; i++) { if (access (argv[i], 0)) { prints ("chmod: can't access %s\n", argv[i]); status++; } else if (chmod (argv[i], newmode) < 0) { prints ("chmod: can't change %s\n", argv[i]); status++; } } exit (status); } oatoi (arg) char *arg; { register c, i; i = 0; while ((c = *arg++) >= '0' && c <= '7') i = (i << 3) + (c - '0'); if (c != '\0') Usage (); return (i); } Usage () { prints ("Usage: chmod [mode] file ...\n"); exit (255); } /* * chown username file ... * * By Patrick van Kleef * */ #include "pwd.h" #include "../h/type.h" #include "stat.h" #include "stdio.h" main (argc, argv) int argc; char *argv[]; { int i, status = 0; struct passwd *pwd, *getpwnam (); struct stat stbuf; if (argc < 3) { fprintf (stderr,"Usage: chown uid file ...\n"); exit (1); } if ((pwd = getpwnam (argv[1])) == 0) { fprintf (stderr,"Unknown user id: %s\n", argv[1]); exit (4); } for (i = 2; i < argc; i++) { if (stat (argv[i], &stbuf) < 0) { perror (argv[i]); status++; } else if (chown (argv[i], pwd -> pw_uid, stbuf.st_gid) < 0) { fprintf (stderr,"%s: not changed\n", argv[i]); status++; } } exit (status); } /* clr - clear the screen Author: Andy Tanenbaum */ main() { /* Clear the screen. */ prints("\033 8\033~0"); exit(0); } /* cmp - compare two files Authors: Paul Polderman & Michiel Huisjes */ #define BLOCK_SIZE 8192 typedef unsigned short unshort; char *file_1, *file_2; char buf[2][BLOCK_SIZE]; unshort lflag, sflag; main(argc, argv) int argc; char *argv[]; { int fd1, fd2, i, exit_status; if (argc < 3 || argc > 4) usage(); lflag = 0; sflag = 0; fd1 = -1; fd2 = -1; for (i = 1; i < argc && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 'l' : lflag++; break; case 's' : sflag++; break; case '\0' : fd1 = 0; /* First file is stdin. */ break; default : usage(); } } if (fd1 == -1) { /* Open first file. */ if (i == argc || (fd1 = open(argv[i], 0)) < 0) cantopen(argv[i]); else file_1 = argv[i++]; } else file_1 = "stdin"; if (i == argc || (fd2 = open(argv[i], 0)) < 0) /* Open second file. */ cantopen(argv[i]); file_2 = argv[i]; exit_status = cmp(fd1, fd2); close (fd1); close (fd2); exit (exit_status); } #define ONE 0 #define TWO 1 cmp(fd1, fd2) int fd1, fd2; { register long char_cnt, line_cnt; register unshort i; unshort n1, n2, exit_status; int c1, c2; char_cnt = 1L; line_cnt = 1L; exit_status = 0; do { n1 = read(fd1, buf[ONE], BLOCK_SIZE); n2 = read(fd2, buf[TWO], BLOCK_SIZE); i = 0; while (i < n1 && i < n2) { /* Check buffers on equality */ if (buf[ONE][i] != buf[TWO][i]) { if (sflag) /* Exit silently */ return(1); if (!lflag) { printf("%s %s differ: char %D, line %D\n", file_1, file_2, char_cnt, line_cnt); return(1); } c1 = buf[ONE][i]; c2 = buf[TWO][i]; printf("\t%D %3o %3o\n", char_cnt, c1&0377, c2&0377); exit_status = 1; } if (buf[ONE][i] == '\n') line_cnt++; i++; char_cnt++; } if (n1 != n2) { /* EOF on one of the input files. */ if (n1 < n2) prints("cmp: EOF on %s\n", file_1); else prints("cmp: EOF on %s\n", file_2); return(1); } } while (n1 > 0 && n2 > 0); /* While not EOF on any file */ return(exit_status); } usage() { std_err("Usage: cmp [-ls] file1 file2\n"); exit(2); } cantopen(s) char *s; { std_err("cmp: cannot open "); std_err(s); std_err("\n"); exit(1); } /* comm - select lines from two sorted files Author: Martin C. Atkins */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. */ #define BUFSIZ (512) #define LINMAX (600) struct file { char *name; /* the file's name */ int fd; /* the file descripter */ char buf[BUFSIZ]; /* buffer storage */ char *next; /* the next character to read */ char *endp; /* the first invalid character */ int seeneof; /* an end of file has been seen */ } files[2]; char lines[2][LINMAX]; int colflgs[3] = {1,2,3}; /* number of tabs + 1: 0 => no column */ static char *umsg = "Usage: comm [-[123]] file1 file2\n"; main(argc,argv) int argc; char *argv[]; { int cnt; if (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { char *ap; for(ap = &argv[1][1]; *ap; ap++) switch(*ap) { case '1': case '2': case '3': cnt = *ap - '1'; if (colflgs[cnt] == 0) break; colflgs[cnt] = 0; for(cnt++; cnt < 3; cnt++) colflgs[cnt]--; break; default: usage(); } argc--; argv++; } if (argc != 3) usage(); eopen(argv[1], &files[0]); eopen(argv[2], &files[1]); comm(); exit(0); } usage() { std_err(umsg); exit(1); } error(s,f) char *s,*f; { std_err("comm: "); std_err(s); if (f) std_err(f); std_err("\n"); exit(1); } int eopen(fn,file) char *fn; struct file *file; { file->name = fn; file->next = file->endp = &file->buf[0]; file->seeneof = 0; if (fn[0] == '-' && fn[1] == '\0') file->fd = 0; else if ((file->fd = open(fn, 0)) < 0) error("can't open ",fn); } int getbuf(file) struct file *file; { /* Get a buffer-full from the file. Return true if no characters * were obtained because we are at end of file. */ int n; if (file->seeneof) return (1); if ((n = read(file->fd, &file->buf[0], BUFSIZ)) < 0) error("read error on ",file->name); if (n == 0) { file->seeneof++; return 1; } file->next = &file->buf[0]; file->endp = &file->buf[n]; return (0); } int readline(fno) int fno; { /* Read up to the next '\n' character to buf. * Return a complete line, even if end of file occurs within a line. * Return false at end of file/ */ register struct file *file = &files[fno]; char *buf = lines[fno]; if (file->next == file->endp && getbuf(file)) return(0); while ((*buf++ = *file->next++) != '\n') if (file->next == file->endp && getbuf(file)) { *buf++ = '\n'; *buf = '\0'; return(1); } *buf = '\0'; return(1); } comm() { register int res; if (!readline(0)) { cpycol(1); return; } if (!readline(1)) { putcol(0,lines[0]); cpycol(0); return; } for(;;) { if ((res = strcmp(lines[0],lines[1])) != 0) { res = res>0; putcol(res,lines[res]); if (!readline(res)) { putcol(!res,lines[!res]); cpycol(!res); return; } } else { putcol(2,lines[0]); /* files[1]lin == f2lin */ if (!readline(0)) { cpycol(1); return; } if (!readline(1)) { putcol(0,lines[0]); cpycol(0); return; } } } /*NOTREACHED*/ } putcol(col,buf) int col; char *buf; { int cnt; if (colflgs[col] == 0) return; for(cnt = 0; cnt < colflgs[col]-1; cnt++) prints("\t"); prints("%s", buf); } cpycol(col) int col; { if (colflgs[col]) while(readline(col)) putcol(col,lines[col]); } /* cp - copy files Author: Andy Tanenbaum */ #include "stat.h" #define TRANSFER_UNIT 16384 char cpbuf[TRANSFER_UNIT]; int isfloppy; /* set to 1 for cp x /dev/fd? */ main(argc, argv) int argc; char *argv[]; { int fd1, fd2, m, s; struct stat sbuf, sbuf2; if (argc < 3) usage(); /* Get the status of the last named file. See if it is a directory. */ s = stat(argv[argc-1], &sbuf); m = sbuf.st_mode & S_IFMT; if (s >= 0 && m == S_IFDIR) { /* Last argument is a directory. */ cp_to_dir(argc, argv); } else if (argc > 3) { /* More than 2 arguments and last one is not a directory. */ usage(); } else if (s < 0 || m==S_IFREG || m==S_IFCHR || m==S_IFBLK){ /* Exactly two arguments. Check for cp f1 f1. */ if (equal(argv[1], argv[2])) { std_err("cp: cannot copy a file to itself\n"); exit(-1); } /* Command is of the form cp f1 f2. */ fd1 = open(argv[1], 0); if (fd1 < 0) {stderr3("cannot open ", argv[1], "\n"); exit(1);} fstat(fd1, &sbuf); fd2 = creat(argv[2], sbuf.st_mode & 0777); if (fd2 < 0) {stderr3("cannot create ", argv[2], "\n"); exit(2);} fstat(fd2, &sbuf2); if ( (sbuf2.st_mode & S_IFMT) == S_IFBLK) isfloppy = 1; copyfile(fd1, fd2); } else { stderr3("cannot copy to ", argv[2], "\n"); exit(3); } exit(0); } cp_to_dir(argc, argv) int argc; char *argv[]; { int i, fd1, fd2; char dirname[256], *ptr, *dp; struct stat sbuf; for (i = 1; i < argc - 1; i++) { fd1 = open(argv[i], 0); if (fd1 < 0) { stderr3("cannot open ", argv[i], "\n"); continue; } ptr = argv[argc-1]; dp = dirname; while (*ptr != 0) *dp++ = *ptr++; *dp++ = '/'; ptr = argv[i]; /* Concatenate dir and file name in dirname buffer. */ while (*ptr != 0) ptr++; /* go to end of file name */ while (ptr > argv[i] && *ptr != '/') ptr--; /* get last component*/ if (*ptr == '/') ptr++; while (*ptr != 0) *dp++ = *ptr++; *dp++ = 0; fstat(fd1, &sbuf); fd2 = creat(dirname, sbuf.st_mode & 0777); if (fd2 < 0) { stderr3("cannot create ", dirname, "\n"); continue; } copyfile(fd1, fd2); } } copyfile(fd1, fd2) int fd1, fd2; { int n, m; do { n = read(fd1, cpbuf, TRANSFER_UNIT); if (n < 0) {std_err("cp: read error\n"); break;} if (n > 0) { m = write(fd2, cpbuf, n); if (m != n) { perror("cp"); exit(1); } if (isfloppy) sync(); /* purge the cache all at once */ } } while (n == TRANSFER_UNIT); close(fd1); close(fd2); } usage() { std_err("Usage: cp f1 f2; or cp f1 ... fn d2\n"); exit(-1); } int equal(s1, s2) char *s1, *s2; { while (1) { if (*s1 == 0 && *s2 == 0) return(1); if (*s1 != *s2) return(0); if (*s1 == 0 || *s2 == 0) return(0); s1++; s2++; } } int match(s1, s2, n) char *s1, *s2; int n; { while (n--) { if (*s1++ != *s2++) return(0); } return(1); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err("cp: "); std_err(s1); std_err(s2); std_err(s3); } /* date - print or set the date Author: Adri Koppes */ #include "stdio.h" int qflag; int days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char *days[] = { "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed" }; struct { int year, month, day, hour, min, sec; } tm; long s_p_min; long s_p_hour; long s_p_day; long s_p_year; main(argc, argv) int argc; char **argv; { long t, time(); if (argc > 2) usage(); s_p_min = 60; s_p_hour = 60 * s_p_min; s_p_day = 24 * s_p_hour; s_p_year = 365 * s_p_day; if (argc == 2) { if (*argv[1] == '-' && (argv[1][1] | 0x60) == 'q') { /* Query option. */ char time_buf[15]; qflag = 1; freopen(stdin, "/dev/tty0", "r"); printf("\nPlease enter date (MMDDYYhhmmss). Then hit RETURN.\n"); gets(time_buf); set_time(time_buf); exit(0); } set_time(argv[1]); } else { time(&t); cv_time(t); printf("%s %s %d %02d:%02d:%02d %d\n", days[(t / s_p_day) % 7], months[tm.month], tm.day, tm.hour, tm.min, tm.sec, tm.year); } exit(0); } cv_time(t) long t; { tm.year = 0; tm.month = 0; tm.day = 1; tm.hour = 0; tm.min = 0; tm.sec = 0; while (t >= s_p_year) { if (((tm.year + 2) % 4) == 0) t -= s_p_day; tm.year += 1; t -= s_p_year; } if (((tm.year + 2) % 4) == 0) days_per_month[1]++; tm.year += 1970; while ( t >= (days_per_month[tm.month] * s_p_day)) t -= days_per_month[tm.month++] * s_p_day; while (t >= s_p_day) { t -= s_p_day; tm.day++; } while (t >= s_p_hour) { t -= s_p_hour; tm.hour++; } while (t >= s_p_min) { t -= s_p_min; tm.min++; } tm.sec = (int) t; } set_time(t) char *t; { char *tp; long ct, time(); int len; time(&ct); cv_time(ct); tm.year -= 1970; tm.month++; len = strlen(t); if (len != 12 && len != 10 && len != 6 && len != 4) usage(); tp = t; while (*tp) if (!isdigit(*tp++)) bad(); if (len == 6 || len == 12) tm.sec = conv(&tp, 59); tm.min = conv(&tp, 59); tm.hour = conv(&tp, 23); if (len == 12 || len == 10) { tm.year = conv(&tp, 99); tm.day = conv(&tp, 31); tm.month = conv(&tp, 12); tm.year -= 70; } ct = tm.year * s_p_year; ct += ((tm.year + 1) / 4) * s_p_day; if (((tm.year + 2) % 4) == 0) days_per_month[1]++; len = 0; tm.month--; while (len < tm.month) ct += days_per_month[len++] * s_p_day; ct += --tm.day * s_p_day; ct += tm.hour * s_p_hour; ct += tm.min * s_p_min; ct += tm.sec; if (days_per_month[1] > 28) days_per_month[1] = 28; if (stime(&ct)) { fprintf(stderr, "Set date not allowed\n"); } else { cv_time(ct); } } conv(ptr, max) char **ptr; int max; { int buf; *ptr -=2; buf = atoi(*ptr); **ptr = 0; if (buf < 0 || buf > max) bad(); return(buf); } bad() { fprintf(stderr, "Date: bad conversion\n"); exit(1); } usage() { if (qflag==0) fprintf(stderr, "Usage: date [-q] [[MMDDYY]hhmm[ss]]\n"); exit(1); } isdigit(c) char c; { if (c >= '0' && c <= '9') return(1); else return(0); } #include "stdio.h" #include "signal.h" #define EOS '\0' #define BOOLEAN int #define TRUE 1 #define FALSE 0 char *pch, *errorp; BOOLEAN is(pc) char *pc; { register char *ps = pch; while (*ps++ == *pc++) if (*pc == EOS) { pch = ps; return(TRUE); } return(FALSE); } #define BIGNUM 2147483647 int num() { long ans; register char *pc; pc = pch; ans = 0L; while ((*pc >= '0') && (*pc <= '9')) ans = (long) ((*pc++ - '0') + (ans * 10)); while (TRUE) switch (*pc++) { case 'w': ans *= 2L; continue; case 'b': ans *= 512L; continue; case 'k': ans *= 1024L; continue; case 'x': pch = pc; ans *= (long) num(); case EOS: if ((ans >= BIGNUM) || (ans < 0)) { fprintf(stderr, "dd: argument %s out of range\n", errorp); done(1); } return((int) ans); } } #define SWAB 0x0001 #define LCASE 0x0002 #define UCASE 0x0004 #define NOERROR 0x0008 #define SYNC 0x0010 #define BLANK ' ' #define DEFAULT 512 unsigned cbs, bs, skip, nseek, count; unsigned ibs = DEFAULT; unsigned obs = DEFAULT; unsigned files = 1; char *ifilename = NULL; char *ofilename = NULL; int convflag = 0; int flag = 0; int cnull(), ibm(), null(), over(); int ifd, ofd, ibc; char *ibuf, *obuf, *op; extern char *sbrk(); unsigned nifull, nipartial, nofull, nopartial; int cbc; unsigned ntr, obc; int ns; char mlen[] = {64,45,82,45,83,96,109,100,109,97,96,116,108,9}; puto() { int n; if (obc == 0) return; if (obc == obs) nofull++; else nopartial++; if ((n = write(ofd, obuf, obc)) != obc) { fprintf(stderr, "dd: write error\n"); done(1); } obc = 0; } statistics() { fprintf(stderr, "%u+%u records in\n", nifull, nipartial); fprintf(stderr, "%u+%u records out\n", nofull, nopartial); if (ntr) fprintf(stderr, "%d truncated records\n", ntr); } over() { statistics(); done(0); } main(argc, argv) int argc; char *argv[]; { int (*convert)(); char *iptr; int i,j; convert = null; argc--; argv++; while (argc-- > 0) { pch = *(argv++); if (is("ibs=")) { errorp = pch; ibs = num(); continue; } if (is("obs=")) { errorp = pch; obs = num(); continue; } if (is("bs=")) { errorp = pch; bs = num(); continue; } if (is("if=")) { ifilename = pch; continue; } if (is("of=")) { ofilename = pch; continue; } if (is("skip=")) { errorp = pch; skip = num(); continue; } if (is("seek=")) { errorp = pch; nseek = num(); continue; } if (is("count=")) { errorp = pch; count = num(); continue; } if (is("files=")) { errorp = pch; files = num(); continue; } if (is("length=")) { errorp = pch; for (j=0; j<13; j++) mlen[j]++; write(2, mlen, 14); continue; } if (is("conv=")) { while (*pch != EOS) { if (is("lcase")) { convflag |= LCASE; continue; } if (is("ucase")) { convflag |= UCASE; continue; } if (is("noerror")) { convflag |= NOERROR; continue; } if (is("sync")) { convflag |= SYNC; continue; } if (is("swab")) { convflag |= SWAB; continue; } if (is(",")) continue; fprintf(stderr, "dd: bad argument: %s\n", pch); done(1); } if (*pch == EOS) continue; } fprintf(stderr, "dd: bad argument: %s \n", pch); done(1); } if ((convert == null) && (convflag & (UCASE | LCASE))) convert = cnull; if ((ifd = ((ifilename) ? open(ifilename, 0) : dup(0))) < 0) { fprintf(stderr, "dd: cannot open %s\n", (ifilename) ? ifilename : "stdin"); done(1); } if ((ofd = ((ofilename) ? creat(ofilename, 0666) : dup(1))) < 0) { fprintf(stderr, "dd: cannot creat %s\n", (ofilename) ? ofilename : "stdout"); done(1); } if (bs) { ibs = obs = bs; if (convert == null) flag++; } if (ibs == 0) { fprintf(stderr, "dd: ibs cannot be zero\n"); done(1); } if (obs == 0) { fprintf(stderr, "dd: obs cannot be zero\n"); done(1); } if ((ibuf = sbrk(ibs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); done(1); } if ((obuf = (flag) ? ibuf : sbrk(obs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); done(1); } ibc = obc = cbc = 0; op = obuf; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, over); for (; skip; skip--) read(ifd, ibuf, ibs); for (; nseek; nseek--) lseek(ofd, (long) obs, 1); outputall: if (ibc-- == 0) { ibc = 0; if ((count == 0) || ((nifull + nipartial) != count)) { if (convflag & (NOERROR | SYNC)) for (iptr = ibuf + ibs; iptr > ibuf;) *--iptr = 0; ibc = read(ifd, ibuf, ibs); } if (ibc == -1) { fprintf(stderr, "dd: read error\n"); if ((convflag & NOERROR) == 0) { puto(); over(); } ibc = 0; for (i = 0; i < ibs; i++) if (ibuf[i] != 0) ibs = i; statistics(); } if ((ibc == 0) && (--files <= 0)) { puto(); over(); } if (ibc != ibs) { nipartial++; if (convflag & SYNC) ibc = ibs; } else nifull++; iptr = ibuf; i = ibc >> 1; if ((convflag & SWAB) && i) do { int temp; temp = *iptr++; iptr[-1] = *iptr; *iptr++ = temp; } while (--i); iptr = ibuf; if (flag) { obc = ibc; puto(); ibc = 0; } goto outputall; } i = *iptr++ & 0377; (*convert)(i); goto outputall; } int ulcase(c) int c; { int ans = c; if ((convflag & UCASE) && (c >= 'a') && (c <= 'z')) ans += 'A' - 'a'; if ((convflag & LCASE) && (c >= 'A') && (c <= 'Z')) ans += 'a' - 'A'; return(ans); } cnull(c) int c; { c = ulcase(c); null(c); } null(c) int c; { *op++ = c; if (++obc >= obs) { puto(); op = obuf; } } extra() { if (++cbc >= cbs) { null('\n'); cbc = 0; ns = 0; } } done(n) int n; { _cleanup(); /* flush stdio's internal buffers */ exit(n); } /* df - disk free block printout Author: Andy Tanenbaum */ #include "../h/const.h" #include "../h/type.h" #include "../fs/const.h" #include "../fs/type.h" #include "../fs/super.h" #include "stat.h" main(argc, argv) int argc; char *argv[]; { register int i; if (argc <= 1) { std_err("Usage: df special ...\n"); exit(1); } sync(); /* have to make sure disk is up-to-date */ for (i = 1; i < argc; i++) df(argv[i]); exit(0); } df(name) char *name; { register int fd; int i_count, z_count, totblocks, busyblocks, i; char buf[BLOCK_SIZE], *s0; struct super_block super, *sp; struct stat statbuf; if ( (fd = open(name,0)) < 0) { perror(name); return; } /* Is it a block special file? */ if (fstat(fd, &statbuf) < 0) { stderr2(name, ": Cannot stat\n"); return; } if ( (statbuf.st_mode & S_IFMT) != S_IFBLK) { stderr2(name, ": not a block special file\n"); return; } lseek(fd, (long)BLOCK_SIZE, 0); /* skip boot block */ if (read(fd, &super, SUPER_SIZE) != SUPER_SIZE) { stderr2(name, ": Can't read super block\n"); close(fd); return; } lseek(fd, (long) BLOCK_SIZE * 2L, 0); /* skip rest of super block */ sp = &super; if (sp->s_magic != SUPER_MAGIC) { stderr2(name, ": Not a valid file system\n"); close(fd); return; } i_count = bit_count(sp->s_imap_blocks, sp->s_ninodes+1, fd); if (i_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } z_count = bit_count(sp->s_zmap_blocks, sp->s_nzones, fd); if (z_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } totblocks = sp->s_nzones << sp->s_log_zone_size; busyblocks = z_count << sp->s_log_zone_size; /* Print results. */ prints("%s ",name); s0 = name; while (*s0) s0++; i = 12 - (s0 - name); while (i--) prints(" "); prints("i-nodes: "); num3(i_count - 1); prints(" used "); num3(sp->s_ninodes + 1 - i_count); prints(" free blocks: "); num3(busyblocks); prints(" used "); num3(totblocks - busyblocks); prints(" free\n"); close(fd); } bit_count(blocks, bits, fd) int blocks; int bits; int fd; { register int i, b; int busy, count, w; int *wptr, *wlim; int buf[BLOCK_SIZE/sizeof(int)]; /* Loop on blocks, reading one at a time and counting bits. */ busy = 0; count = 0; for (i = 0; i < blocks; i++) { if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) return(-1); wptr = &buf[0]; wlim = &buf[BLOCK_SIZE/sizeof(int)]; /* Loop on the words of a block */ while (wptr != wlim) { w = *wptr++; /* Loop on the bits of a word. */ for (b = 0; b < 8*sizeof(int); b++) { if ( (w>>b) & 1) busy++; if (++count == bits) return(busy); } } } return(0); } stderr2(s1, s2) char *s1, *s2; { std_err(s1); std_err(s2); } num3(n) int n; { extern char *itoa(); if (n < 10) prints(" %s", itoa(n)); else if (n < 100) prints(" %s", itoa(n)); else if (n < 1000) prints(" %s", itoa(n)); else prints("%s", itoa(n)); } /* * dosdir - list MS-DOS directories. * doswrite - write stdin to DOS-file * dosread - read DOS-file to stdout * * Author: Michiel Huisjes. * * Usage: dos... [-lra] drive [file/dir] * l: Give long listing. * r: List recursively. * a: Set ASCII bit. */ #include "stat.h" #define DRIVE "/dev/atX" #define DRIVE_NR 7 #define DDDD 0xFD #define DDHD 0xF9 #define MAX_CLUSTER_SIZE 1024 #define MAX_FAT_SIZE 3584 /* 7 sectoren */ #define MAX_ROOT_ENTRIES 224 /* 14 sectoren */ #define FAT_START 512L /* After bootsector */ #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \ * (long) cluster_size \ + (long) data_start \ )) struct dir_entry { unsigned char d_name[8]; unsigned char d_ext[3]; unsigned char d_attribute; unsigned char d_reserved[10]; unsigned short d_time; unsigned short d_date; unsigned short d_cluster; unsigned long d_size; }; typedef struct dir_entry DIRECTORY; #define NOT_USED 0x00 #define ERASED 0xE5 #define DIR 0x2E #define DIR_SIZE (sizeof (struct dir_entry)) #define SUB_DIR 0x10 #define NIL_DIR ((DIRECTORY *) 0) #define LAST_CLUSTER 0x0FFF #define MASK 0xFF8 #define FREE 0x000 #define BAD 0xFF0 typedef char BOOL; #define TRUE 1 #define FALSE 0 #define NIL_PTR ((char *) 0) #define DOS_TIME 315532800L /* 1970 - 1980 */ #define READ 0 #define WRITE 1 #define disk_read(s, a, b) disk_io(READ, s, a, b) #define disk_write(s, a, b) disk_io(WRITE, s, a, b) #define FIND 3 #define LABEL 4 #define ENTRY 5 #define find_entry(d, e, p) directory(d, e, FIND, p) #define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR) #define label() directory(root, root_entries, LABEL, NIL_PTR) #define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR) #define is_dir(d) ((d)->d_attribute & SUB_DIR) #define EOF 0400 #define EOF_MARK '\032' #define STD_OUT 1 #define flush() print(STD_OUT, NIL_PTR, 0) short disk; unsigned char fat[MAX_FAT_SIZE]; DIRECTORY root[MAX_ROOT_ENTRIES]; DIRECTORY save_entry; char null[MAX_CLUSTER_SIZE], device[] = DRIVE, path[128]; long mark; short total_clusters, cluster_size, fat_size, root_entries, data_start, sub_entries; BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir; DIRECTORY *directory(), *read_cluster(); unsigned short free_cluster(), next_cluster(); char *make_name(), *num_out(), *slash(), *brk(); long lseek(), time(); leave(nr) short nr; { (void) umount(device); exit(nr); } usage(prog_name) register char *prog_name; { print_string(TRUE, "Usage: %s [%s\n", prog_name, dos_dir ? "-lr] drive [dir]" : "-a] drive file"); exit(1); } main(argc, argv) int argc; register char *argv[]; { register char *arg_ptr = slash(argv[0]); DIRECTORY *entry; short index = 1; char dev_nr = '0'; unsigned char fat_check; if (!strcmp(arg_ptr, "dosdir")) dos_dir = TRUE; else if (!strcmp(arg_ptr, "dosread")) dos_read = TRUE; else if (!strcmp(arg_ptr, "doswrite")) dos_write = TRUE; else { print_string(TRUE, "Program should be named dosread, doswrite or dosdir.\n"); exit(1); } if (argc == 1) usage(argv[0]); if (argv[1][0] == '-') { for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) { if (*arg_ptr == 'l' && dos_dir) Lflag = TRUE; else if (*arg_ptr == 'r' && dos_dir) Rflag = TRUE; else if (*arg_ptr == 'a' && !dos_dir) Aflag = TRUE; else usage(argv[0]); } index++; } if (index == argc) usage(argv[0]); if ((dev_nr = *argv[index++]) < '0' || dev_nr > '9') usage(argv[0]); device[DRIVE_NR] = dev_nr; if ((disk = open(device, 2)) < 0) { print_string(TRUE, "Cannot open %s\n", device); exit(1); } disk_read(FAT_START, fat, MAX_FAT_SIZE); if (fat[0] == DDDD) { /* Double-sided double-density 9 s/t */ total_clusters = 355; /* 720 - 7 - 2 - 2 - 1 */ cluster_size = 1024; /* 2 sectors per cluster */ fat_size = 1024; /* 2 sectors */ data_start = 6144; /* Starts on sector #12 */ root_entries = 112; sub_entries = 32; /* 1024 / 32 */ } else if (fat[0] == DDHD) { /* Double-sided high-density 15 s/t */ total_clusters = 2372; /* 2400 - 14 - 7 - 7 - 1 */ cluster_size = 512; /* 1 sector per cluster */ fat_size = 3584; /* 7 sectors */ data_start = 14848; /* Starts on sector #29 */ root_entries = 224; sub_entries = 16; /* 512 / 32 */ } else { print_string(TRUE, "Diskette is not DOS 2.0 360K or 1.2M\n"); leave(1); } disk_read(FAT_START + (long) fat_size, &fat_check, sizeof(fat_check)); if (fat_check != fat[0]) { print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n"); leave(1); } disk_read(FAT_START + 2L * (long) fat_size, root, DIR_SIZE * root_entries); if (dos_dir) { entry = label(); print_string(FALSE, "Volume in drive %c ", dev_nr); if (entry == NIL_DIR) print(STD_OUT, "has no label.\n\n", 0); else print_string(FALSE, "is %S\n\n", entry->d_name); } if (argv[index] == NIL_PTR) { if (!dos_dir) usage(argv[0]); print(STD_OUT, "Root directory:\n", 0); list_dir(root, root_entries, FALSE); free_blocks(); flush(); leave(0); } for (arg_ptr = argv[index]; *arg_ptr; arg_ptr++) if (*arg_ptr == '\\') *arg_ptr = '/'; else if (*arg_ptr >= 'a' && *arg_ptr <= 'z') *arg_ptr += ('A' - 'a'); if (*--arg_ptr == '/') *arg_ptr = '\0'; /* skip trailing '/' */ add_path(argv[index], FALSE); add_path("/", FALSE); if (dos_dir) print_string(FALSE, "Directory %s:\n", path); entry = find_entry(root, root_entries, argv[index]); if (dos_dir) { list_dir(entry, sub_entries, FALSE); free_blocks(); } else if (dos_read) extract(entry); else { if (entry != NIL_DIR) { flush(); if (is_dir(entry)) print_string(TRUE, "%s is a directory.\n", path); else print_string(TRUE, "%s already exists.\n", argv[index]); leave(1); } add_path(NIL_PTR, TRUE); if (*path) make_file(find_entry(root, root_entries, path), sub_entries, slash(argv[index])); else make_file(root, root_entries, argv[index]); } (void) close(disk); flush(); leave(0); } DIRECTORY *directory(dir, entries, function, pathname) DIRECTORY *dir; short entries; BOOL function; register char *pathname; { register DIRECTORY *dir_ptr = dir; DIRECTORY *mem = NIL_DIR; unsigned short cl_no = dir->d_cluster; unsigned short type, last; char file_name[14]; char *name; int i = 0; if (function == FIND) { while (*pathname != '/' && *pathname && i < 12) file_name[i++] = *pathname++; while (*pathname != '/' && *pathname) pathname++; file_name[i] = '\0'; } do { if (entries != root_entries) { mem = dir_ptr = read_cluster(cl_no); last = cl_no; cl_no = next_cluster(cl_no); } for (i = 0; i < entries; i++, dir_ptr++) { type = dir_ptr->d_name[0] & 0x0FF; if (function == ENTRY) { if (type == NOT_USED || type == ERASED) { mark = lseek(disk, 0L, 1) - (long) cluster_size + (long) i * (long) DIR_SIZE; if (!mem) mark += (long) cluster_size - (long) (root_entries * sizeof (DIRECTORY)); return dir_ptr; } continue; } if (type == NOT_USED) break; if (dir_ptr->d_attribute & 0x08) { if (function == LABEL) return dir_ptr; continue; } if (type == DIR || type == ERASED || function == LABEL) continue; type = is_dir(dir_ptr); name = make_name(dir_ptr, (function == FIND) ? FALSE : type); if (function == FIND) { if (strcmp(file_name, name) != 0) continue; if (!type) { if (dos_dir || *pathname) { flush(); print_string(TRUE, "Not a directory: %s\n", file_name); leave(1); } } else if (*pathname == '\0' && dos_read) { flush(); print_string(TRUE, "%s is a directory.\n", path); leave(1); } if (*pathname) { dir_ptr = find_entry(dir_ptr, sub_entries, pathname + 1); } if (mem) { if (dir_ptr) { bcopy(dir_ptr, &save_entry, DIR_SIZE); dir_ptr = &save_entry; } (void) brk(mem); } return dir_ptr; } else { if (function == FALSE) show(dir_ptr, name); else if (type) { /* Recursive */ print_string(FALSE, "Directory %s%s:\n", path, name); addHJKLMNOPQRSTU_path(name, FALSE); list_dir(dir_ptr, sub_entries, FALSE); add_path(NIL_PTR, FALSE); } } } if (mem) (void) brk(mem); } while (cl_no != LAST_CLUSTER && mem); switch (function) { case FIND: if (dos_write && *pathname == '\0') return NIL_DIR; flush(); print_string(TRUE, "Cannot find `%s'.\n", file_name); leave(1); case LABEL: return NIL_DIR; case ENTRY: if (!mem) { flush(); print_string(TRUE, "No entries left in root directory.\n"); leave(1); } cl_no = free_cluster(TRUE); link_fat(last, cl_no); link_fat(cl_no, LAST_CLUSTER); disk_write(clus_add(cl_no), null, cluster_size); return new_entry(dir, entries); case FALSE: if (Rflag) { print(STD_OUT, "\n", 0); list_dir(dir, entries, TRUE); } } } extract(entry) register DIRECTORY *entry; { register unsigned short cl_no = entry->d_cluster; char buffer[MAX_CLUSTER_SIZE]; short rest; if (entry->d_size == 0) /* Empty file */ return; do { disk_read(clus_add(cl_no), buffer, cluster_size); rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size; print(STD_OUT, buffer, rest); entry->d_size -= (long) rest; cl_no = next_cluster(cl_no); if (cl_no == BAD) { flush(); print_string(TRUE, "Reserved cluster value encountered.\n"); leave(1); } } while (entry->d_size && cl_no != LAST_CLUSTER); if (cl_no != LAST_CLUSTER) print_string(TRUE, "Too many clusters allocated for file.\n"); else if (entry->d_size != 0) print_string(TRUE, "Premature EOF: %L bytes left.\n", entry->d_size); } print(fd, buffer, bytes) short fd; register char *buffer; register short bytes; { static short index; static BOOL lf_pending = FALSE; static char output[MAX_CLUSTER_SIZE + 1]; if (buffer == NIL_PTR) { if (dos_read && Aflag && lf_pending) { output[index++] = '\r'; lf_pending = FALSE; } if (write(fd, output, index) != index) bad(); index = 0; return; } if (bytes == 0) bytes = strlen(buffer); while (bytes--) { if (index >= MAX_CLUSTER_SIZE) { if (write(fd, output, index) != index) bad (); index = 0; } if (dos_read && Aflag) { if (*buffer == '\r') { if (lf_pending) output[index++] = *buffer++; else { lf_pending = TRUE; buffer++; } } else if (*buffer == '\n') { output[index++] = *buffer++; lf_pending = FALSE; } else if (lf_pending) { output[index++] = '\r'; output[index++] = *buffer++; } else if ((output[index++] = *buffer++) == EOF_MARK) { if (lf_pending) { output[index - 1] = '\r'; index++; lf_pending = FALSE; } index--; return; } } else output[index++] = *buffer++; } } make_file(dir_ptr, entries, name) DIRECTORY *dir_ptr; int entries; char *name; { register DIRECTORY *entry = new_entry(dir_ptr, entries); register char *ptr; char buffer[MAX_CLUSTER_SIZE]; unsigned short cl_no, next; short i, r; long size = 0L; bcopy(" ",&entry->d_name[0],11); /* clear entry */ for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++) entry->d_name[i] = *ptr++; while (*ptr != '.' && *ptr) ptr++; if (*ptr == '.') ptr++; for (i=0;i < 3 && *ptr; i++) entry->d_ext[i] = *ptr++; for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0'; entry->d_attribute = '\0'; entry->d_cluster = 0; while ((r = fill(buffer)) > 0) { if ((next = free_cluster(FALSE)) > total_clusters) { print_string(TRUE, "Diskette full. File truncated.\n"); break; } disk_write(clus_add(next), buffer, r); if (entry->d_cluster == 0) cl_no = entry->d_cluster = next; else { link_fat(cl_no, next); cl_no = next; } size += r; } if (entry->d_cluster != 0) link_fat(cl_no, LAST_CLUSTER); entry->d_size = Aflag ? (size - 1) : size; /* Strip added ^Z */ fill_date(entry); disk_write(mark, entry, DIR_SIZE); disk_write(FAT_START, fat, fat_size); disk_write(FAT_START + (long) fat_size, fat, fat_size); } #define SEC_MIN 60L #define SEC_HOUR (60L * SEC_MIN) #define SEC_DAY (24L * SEC_HOUR) #define SEC_YEAR (365L * SEC_DAY) #define SEC_LYEAR (366L * SEC_DAY) short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; fill_date(entry) DIRECTORY *entry; { register long cur_time = time((long *) 0) - DOS_TIME; unsigned short year = 0, month = 1, day, hour, minutes, seconds; int i; long tmp; if (cur_time < 0) /* Date not set on booting ... */ cur_time = 0; for (;;) { tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR; if (cur_time < tmp) break; cur_time -= tmp; year++; } day = (unsigned short) (cur_time / SEC_DAY); cur_time -= (long) day *SEC_DAY; hour = (unsigned short) (cur_time / SEC_HOUR); cur_time -= (long) hour *SEC_HOUR; minutes = (unsigned short) (cur_time / SEC_MIN); cur_time -= (long) minutes *SEC_MIN; seconds = (unsigned short) cur_time; mon_len[1] = (year % 4 == 0) ? 29 : 28; i = 0; while (day >= mon_len[i]) { month++; day -= mon_len[i++]; } day++; entry->d_date = (year << 9) | (month << 5) | day; entry->d_time = (hour << 11) | (minutes << 5) | seconds; } char *make_name(dir_ptr, dir_fl) register DIRECTORY *dir_ptr; short dir_fl; { static char name_buf[14]; register char *ptr = name_buf; short i; for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i]; while (*--ptr == ' '); ptr++; if (dir_ptr->d_ext[0] != ' ') { *ptr++ = '.'; for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i]; while (*--ptr == ' '); ptr++; } if (dir_fl) *ptr++ = '/'; *ptr = '\0'; return name_buf; } fill(buffer) register char *buffer; { static BOOL eof_mark = FALSE; char *last = &buffer[cluster_size]; char *begin = buffer; register short c; if (eof_mark) return 0; while (buffer < last) { if ((c = get_char()) == EOF) { eof_mark = TRUE; if (Aflag) *buffer++ = EOF_MARK; break; } *buffer++ = c; } return (int) (buffer - begin); } get_char() { static short read_chars, index; static char input[MAX_CLUSTER_SIZE]; static BOOL new_line = FALSE; if (new_line == TRUE) { new_line = FALSE; return '\n'; } if (index == read_chars) { if ((read_chars = read(0, input, cluster_size)) == 0) return EOF; index = 0; } if (Aflag && input[index] == '\n') { new_line = TRUE; index++; return '\r'; } return input[index++]; } #define HOUR 0xF800 /* Upper 5 bits */ #define MIN 0x07E0 /* Middle 6 bits */ #define YEAR 0xFE00 /* Upper 7 bits */ #define MONTH 0x01E0 /* Mid 4 bits */ #define DAY 0x01F /* Lowest 5 bits */ char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; modes(mode) register unsigned char mode; { print_string(FALSE, "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-', (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-', (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-'); } show(dir_ptr, name) DIRECTORY *dir_ptr; char *name; { register unsigned short e_date = dir_ptr->d_date; register unsigned short e_time = dir_ptr->d_time; unsigned short next; char bname[20]; short i = 0; while (*name && *name != '/') bname[i++] = *name++; bname[i] = '\0'; if (!Lflag) { print_string(FALSE, "%s\n", bname); return; } modes(dir_ptr->d_attribute); print_string(FALSE, "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t"); i = 1; if (is_dir(dir_ptr)) { next = dir_ptr->d_cluster; while ((next = next_cluster(next)) != LAST_CLUSTER) i++; print_string(FALSE, "%L", (long) i * (long) cluster_size); } else print_string(FALSE, "%L", dir_ptr->d_size); print_string(FALSE, "\t%N:%N %P %s %d\n", ((e_time & HOUR) >> 11), ((e_time & MIN) >> 5), (e_date & DAY), month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980); } free_blocks() { register unsigned short cl_no; register short free = 0; short bad = 0; for (cl_no = 2; cl_no <= total_clusters; cl_no++) { switch (next_cluster(cl_no)) { case FREE: free++; break; case BAD: bad++; } } print_string(FALSE, "Free space: %L bytes.\n", (long) free * (long) cluster_size); if (bad) print_string(FALSE, "Bad sectors: %L bytes.\n", (long) bad * (long) cluster_size); } char *num_out(number) register long number; { static char num_buf[13]; char temp[13]; register short i = 0; short j; if (number == 0) temp[i++] = '0'; while (number) { temp[i++] = (char) (number % 10L + '0'); number /= 10L; } for (j = 0; j < 11; j++) num_buf[j] = temp[i - j - 1]; num_buf[i] = '\0'; return num_buf; } /* VARARGS */ print_string(err_fl, fmt, args) BOOL err_fl; char *fmt; int args; { char buf[200]; register char *buf_ptr = buf; char *scan_ptr; register int *arg_ptr = &args; short i; while (*fmt) { if (*fmt == '%') { fmt++; if (*fmt == 'c') { *buf_ptr++ = (char) *arg_ptr++; fmt++; continue; } if (*fmt == 'S') { scan_ptr = (char *) *arg_ptr; for (i = 0; i < 11; i++) *buf_ptr++ = *scan_ptr++; fmt++; continue; } if (*fmt == 's') scan_ptr = (char *) *arg_ptr; else if (*fmt == 'L') { scan_ptr = num_out(*((long *) arg_ptr)); arg_ptr++; } else { scan_ptr = num_out((long) *arg_ptr); if (*fmt == 'P' && *arg_ptr < 10) *buf_ptr++ = ' '; else if (*fmt == 'N' && *arg_ptr < 10) *buf_ptr++ = '0'; } while (*buf_ptr++ = *scan_ptr++); buf_ptr--; arg_ptr++; fmt++; } else *buf_ptr++ = *fmt++; } *buf_ptr = '\0'; if (err_fl) { flush(); write(2, buf, (int) (buf_ptr - buf)); } else print(STD_OUT, buf, 0); } DIRECTORY *read_cluster(cluster) register unsigned short cluster; { register DIRECTORY *sub_dir; extern char *sbrk(); if ((sub_dir = (DIRECTORY *) sbrk(cluster_size)) < 0) { print_string(TRUE, "Cannot set break!\n"); leave(1); } disk_read(clus_add(cluster), sub_dir, cluster_size); return sub_dir; } unsigned short free_cluster(leave_fl) BOOL leave_fl; { static unsigned short cl_index = 2; while (cl_index <= total_clusters && next_cluster(cl_index) != FREE) cl_index++; if (leave_fl && cl_index > total_clusters) { flush(); print_string(TRUE, "Diskette full. File not added.\n"); leave(1); } return cl_index++; } link_fat(cl_1, cl_2) unsigned short cl_1; register unsigned short cl_2; { register unsigned char *fat_index = &fat[(cl_1 >> 1) * 3 + 1]; if (cl_1 & 0x01) { *(fat_index + 1) = cl_2 >> 4; *fat_index = (*fat_index & 0x0F) | ((cl_2 & 0x0F) << 4); } else { *(fat_index - 1) = cl_2 & 0x0FF; *fat_index = (*fat_index & 0xF0) | (cl_2 >> 8); } } unsigned short next_cluster(cl_no) register unsigned short cl_no; { register unsigned char *fat_index = &fat[(cl_no >> 1) * 3 + 1]; if (cl_no & 0x01) cl_no = (*(fat_index + 1) << 4) | (*fat_index >> 4); else cl_no = ((*fat_index & 0x0F) << 8) | *(fat_index - 1); if ((cl_no & MASK) == MASK) cl_no = LAST_CLUSTER; else if ((cl_no & BAD) == BAD) cl_no = BAD; return cl_no; } char *slash(str) register char *str; { register char *result = str; while (*str) if (*str++ == '/') result = str; return result; } add_path(file, slash_fl) register char *file; BOOL slash_fl; { register char *ptr = path; while (*ptr) ptr++; if (file == NIL_PTR) { ptr--; do { ptr--; } while (*ptr != '/' && ptr != path); if (ptr != path && !slash_fl) ptr++; *ptr = '\0'; } else while (*ptr++ = *file++); } bcopy(src, dest, bytes) register char *src, *dest; short bytes; { while (bytes--) *dest++ = *src++; } disk_io(op, seek, address, bytes) register BOOL op; unsigned long seek; DIRECTORY *address; register unsigned bytes; { unsigned int r; if (lseek(disk, seek, 0) < 0L) { flush(); print_string(TRUE, "Bad lseek\n"); leave(1); } if (op == READ) r = read(disk, address, bytes); else r = write(disk, address, bytes); if (r != bytes) bad(); } bad() { flush(); perror("I/O error"); leave(1); } /* echo - echo arguments Author: Andy Tanenbaum */ #define SIZE 2048 char buf[SIZE]; int count; main(argc, argv) int argc; char *argv[]; { register int i, nflag; nflag = 0; if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n') { nflag++; argc--; argv++; } for(i = 1; i < argc; i++) { collect(argv[i]); if (i < argc - 1) collect(" "); } if (nflag == 0) collect("\n"); /* Print accumulated output. */ if (count > 0) write(1, buf, count); exit(0); } collect(s) char *s; { /* Collect characters. For efficiency, write them in large chunks. */ char c; if (count == SIZE) {write(1, buf, count); count = 0;} while ( (c = *s++) != 0) { if (count < SIZE && c != '"') buf[count++] = c; } } main(argc, argv) int argc; char *argv[]; { char c; /* Echo argument, if present. */ if (argc == 2) { std_err(argv[1]); std_err("\n"); } close(0); open("/dev/tty0", 0); do { read(0, &c, 1); } while (c != '\n'); exit(0); } /* grep - search for a pattern Author: Martin C. Atkins */ /* * Search files for a regular expression * *<-xtx-*>cc -o grep grep.c -lregexp */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. * * The program was modified by Andy Tanenbaum. */ #include "regexp.h" #include "stdio.h" #define MAXLINE (1024) int status = 1; char *progname; int pmflag = 1; /* print lines which match */ int pnmflag = 0; /* print lines which don't match */ int nflag = 0; /* number the lines printed */ int args; extern char *index(); main(argc,argv) int argc; char *argv[]; { regexp *exp; char **argp = &argv[1]; if (!isatty(1)) setbuf(stdout); args = argc; progname = argv[0]; while(*argp != 0 && argp[0][0] == '-') { args--; /* flags don't count */ switch(argp[0][1]) { case 'v': pmflag = 0; pnmflag = 1; break; case 'n': nflag++; break; case 's': pmflag = pnmflag = 0; break; case 'e': argp++; goto out; default: usage(); } argp++; } out: if(*argp == 0) usage(); if((exp = regcomp(*argp++)) == NULL) { std_err("grep: regcomp failed\n"); done(2); } if(*argp == 0) match((char *)0,exp); else while(*argp) { int infd; if(strcmp(*argp,"-") == 0) match("-",exp); else { fclose(stdin); if(fopen(*argp, "r") == NULL) { std_err("Can't open "); std_err(*argp); std_err("\n"); status = 2; } else { match(*argp,exp); close(infd); } } argp++; } done(status); } /* * This routine actually matches the file */ match(name, exp) char *name; regexp *exp; { char buf[MAXLINE]; int lineno = 0; while(getline(buf,MAXLINE) != NULL) { char *cr = index(buf,'\n'); lineno++; if(cr == 0) { std_err("Line too long in "); std_err(name == 0 ? "stdin":name); } else *cr = '\0'; if(regexec(exp,buf)) { if(pmflag) pline(name,lineno,buf); if(status != 2) status = 0; } else if(pnmflag) pline(name,lineno,buf); } } void regerror(s) char *s; { std_err("grep: "); std_err(s); std_err("\n"); done(2); } pline(name, lineno, buf) char *name; int lineno; char buf[]; { if(name && args > 3) prints("%s:",name); if(nflag) prints("%s:", itoa(lineno)); prints("%s\n",buf); } usage() { std_err("Usage: grep [-v] [-n] [-s] [-e expr] expression [file ...]\n"); done(2); } getline(buf, size) char *buf; int size; { char *initbuf = buf, c; while (1) { c = getc(stdin); *buf++ = c; if (c <= 0) return(NULL); if (buf - initbuf == size - 1) return(buf - initbuf); if (c == '\n') return(buf - initbuf); } } done(n) int n; { fflush(stdout); exit(n); } /* gres - grep and substitute Author: Martin C. Atkins */ /* * globally search, and replace * *<-xtx-*>cc -o gres gres.c -lregexp */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. */ #include "stdio.h" #include "regexp.h" #define MAXLINE (1024) int status = 1; char *usagemsg = "Usage: gres [-g] search replace [file ...]\n"; char *progname; int gflag = 0; /* != 0 => only do first substitution on line */ extern char *index(); FILE *fopen(); main(argc,argv) int argc; char *argv[]; { regexp *exp; char *repstr; char **argp = &argv[1]; progname = argv[0]; if(*argp != 0 && argp[0][0] == '-' && argp[0][1] == 'g') { gflag = 1; argp++,argc--; } if(argc < 3) { std_err(usagemsg); done(2); } if(argp[0][0] == '\0') { std_err("gres: null match string is silly\n"); done(2); } if((exp = regcomp(*argp++)) == NULL) { std_err("gres: regcomp failed\n"); done(2); } repstr = *argp++; if(*argp == 0) process(stdin,exp,repstr); else while(*argp) { FILE *inf; if(strcmp(*argp,"-") == 0) process(stdin,exp,repstr); else { if((inf = fopen(*argp,"r")) == NULL) { std_err("gres: Can't open "); std_err(*argp); std_err("\n"); status = 2; } else { process(inf,exp,repstr); fclose(inf); } } argp++; } done(status); } /* * This routine does the processing */ process(inf, exp, repstr) FILE *inf; regexp *exp; char *repstr; { char ibuf[MAXLINE]; while(fgets(ibuf,MAXLINE,inf) != NULL) { char *cr = index(ibuf,'\n'); if(cr == 0) std_err("gres: Line broken\n"); else *cr = '\0'; if(regexec(exp,ibuf,1)) { pline(exp,ibuf,repstr); if(status != 2) status = 0; } else printf("%s\n",ibuf); } } void regerror(s) char *s; { std_err("gres: "); std_err(s); std_err("\n"); done(2); } char * getbuf(exp, repstr) regexp *exp; char *repstr; { char *malloc(); void free(); static bufsize = 0; static char *buf = 0; int guess = 10; int ch; while(*repstr) { switch(*repstr) { case '&': guess += exp->endp[0] - exp->startp[0]; break; case '\\': if((ch = *++repstr) < '0' || ch > '9') guess += 2; else { ch -= '0'; guess += exp->endp[ch] - exp->startp[ch]; } break; default: guess++; } repstr++; } if(bufsize < guess) { if(buf != 0) free((char *)buf); buf = malloc(guess); } return buf; } pline(exp, ibuf, repstr) regexp *exp; char ibuf[]; char *repstr; { do { dosub(exp,ibuf,repstr); ibuf = exp->endp[0]; if(*ibuf == '\0') break; if(ibuf == exp->startp[0]) putchar(*ibuf++); } while(!gflag && regexec(exp,ibuf,0)); printf("%s\n",ibuf); } /* * print one subsitution */ dosub(exp,ibuf,repstr) regexp *exp; char ibuf[]; char *repstr; { char *buf = getbuf(exp, repstr); char *end = exp->startp[0]; int ch = *end; *end = '\0'; fputs(ibuf,stdout); /* output the initial part of line */ *end = ch; regsub(exp, repstr, buf); fputs(buf,stdout); } done(n) int n; { _cleanup(); /* flush stdio's internal buffers */ exit(n); } /* head - print the first few lines of a file Author: Andy Tanenbaum */ /* change to use putc() instead of prints() -- Dean Long 3/7/87 */ #include "stdio.h" #define DEFAULT 10 char buff[BUFSIZ]; main(argc, argv) int argc; char *argv[]; { int n, k, nfiles; char *ptr; /* Check for flag. Only flag is -n, to say how many lines to print. */ setbuf(stdout, buff); k = 1; ptr = argv[1]; n = DEFAULT; if (*ptr++ == '-') { k++; n = atoi(ptr); if (n <= 0) usage(); } nfiles = argc - k; if (nfiles == 0) { /* Print standard input only. */ do_file(n); fflush(stdout); exit(0); } /* One or more files have been listed explicitly. */ while (k < argc) { fclose(stdin); if (nfiles > 1) prints("==> %s <==\n", argv[k]); if (fopen(argv[k], "r") == NULL) prints("head: cannot open %s\n", argv[k]); else { do_file(n); fflush(stdout); } k++; if (k < argc) prints("\n"); } exit(0); } do_file(n) int n; { int c; /* Print the first 'n' lines of a file. */ while(n) switch (c = getc(stdin)) { case EOF : return; case '\n': --n; default : putc((char)c, stdout); } } usage() { std_err("Usage: head [-n] [file ...]\n"); exit(1); } /* kill - send a signal to a process Author: Adri Koppes */ #include "../h/signal.h" main(argc,argv) int argc; char **argv; { int proc, signal = SIGTERM; if (argc < 2) usage(); if (*argv[1] == '-') { signal = atoi(&argv[1][1]); *argv++; argc--; } if (!signal) signal = SIGTERM; while(--argc) { *argv++; proc = atoi(*argv); if (!proc && strcmp(*argv, "0")) usage(); if (kill(proc,signal)) { prints("Kill: %s no such process\n", itoa(proc)); exit(1); } } exit(0); } usage() { prints("Usage: kill pid\n"); exit(1); } /* libpack - pack ASCII assembly code Author: Andy Tanenbaum */ #define BUFSIZ 20000 #define FS 1 #define WRITE 4 #define NILP (char *)0 char *table[] = { "push ax", "ret", "mov bp,sp", "push bp", "pop bp", "mov sp,bp", ".text", "xor ax,ax", "push 4(bp)", "pop bx", "pop si", "cbw", "movb al,(bx)", "pop ax", "xorb ah,ah", "mov ax,#1", "call _callm1", "add sp,#16", "mov bx,4(bp)", "push 6(bp)", "mov -2(bp),ax", "I0013:", "call .cuu", "mov ax,-2(bp)", "add 4(bp),#1", "or ax,ax", "jmp I0011", "mov bx,8(bp)", "push dx", "mov cx,#2", "mov bx,#2", "I0011:", "I0012:", "push -2(bp)", "mov ax,4(bp)", "mov ax,-4(bp)", "add sp,#6", "and ax,#255", "push bx", "mov bx,-2(bp)", "loop 2b", "jcxz 1f", ".word 4112", "mov ax,(bx)", "mov -4(bp),ax", "jmp I0013", ".data", "mov bx,6(bp)", "mov (bx),ax", "je I0012", ".word 8224", ".bss", "mov ax,#2", "call _len", "call _callx", ".word 28494", ".word 0", "push -4(bp)", "movb (bx),al", "mov bx,ax", "mov -2(bp),#0", "I0016:", ".word 514", ".word 257", "mov ", "push ", ".word ", "pop ", "add ", "4(bp)", "-2(bp)", "(bx)", ".define ", ".globl ", "movb ", "xor ", "jmp ", "cmp ", "6(bp)", "-4(bp)", "-6(bp)", "#16", "_callm1", "call ", "8(bp)", "xorb ", "and ", "sub ", "-8(bp)", "jne ", ".cuu", "lea ", "inc ", "_M+10", "#255", "loop", "jcxz", "ax,#", "bx,#", "cx,#", "ax,", "bx,", "cx,", "dx,", "si,", "di,", "bp,", "ax", "bx", "cx", "dx", "si", "di", "bp", "sp", "dec ", "neg ", "_execve", ",#0", 0}; int bol = 1; int white = 0; #define MAX 128 /* This table is used to look up strings. */ struct node { char *string; struct node *next; } node[MAX]; struct node *hash[MAX]; /* hash table */ char input[BUFSIZ+2]; char xbuf[BUFSIZ+2]; main() { int n, count, outbytes; char *p; hainit(); while (1) { for (p = &input[0]; p < &input[BUFSIZ+1]; p++) *p = 0; n = read(0, input, BUFSIZ); if (n == BUFSIZ) { std_err("Input file too long\n"); exit(1); } if (n <= 0) exit(0); outbytes = pack88(input, xbuf, n); write(1, xbuf, outbytes); } } int pack88(inp, outp, count) register char *inp; char *outp; int count; { /* Take a string and pack it to compact assembly code. */ int k, hit, whchar, n; char *orig = outp; char *inbeg = inp; int ct; char *p, **ppt; struct node *nood; /* Convert all tabs to spaces. */ p = inp; while (p - inbeg < count) { if (*p == '\t') *p = ' '; p++; } /* Loop on every char in the buffer. */ while (1) { /* Is the current string in the table? */ if (inp - inbeg > count) write(2, "Bug in packing algorithm\n", 25); if (inp - inbeg == count) return(outp - orig); /* Delete leading white space */ whchar = (*inp == ' ' ? 1 : 0); if (bol && whchar) { inp++; continue; } else { bol = 0; } if (*inp == '\n') bol = 1; /* Delete comments */ if (*inp == '|') { while (*inp++ != '\n') ; inp--; bol = 1; } /* Compact white space */ if (white && whchar) { inp++; continue; } white = whchar; ppt = table; hit = 0; /* Compute hash value for inp. */ n = (*inp + *(inp+1)) & 0177; nood = hash[n]; while (nood != 0) { if (match(inp, nood->string)) { *outp++ = (char) (128 + (nood - node)); inp += strlen(nood->string); hit++; break; } nood = nood->next; } if (hit == 0) *outp++ = *inp++; } } int match(s1, s2) register char *s1, *s2; { while (*s2 != 0) { if (*s1++ != *s2++) return(0); } return(1); } hainit() { /* Initialize the hash tables. */ int n, i, free; char *p; struct node *nood; free = 0; /* next free slot in node table */ for (i = 0; i < MAX; i++) { p = table[i]; if (p == (char *) 0) return; n = *p + *(p+1); n = n & 0177; /* Enter string i on hash slot n. */ if (hash[n] == (struct node *) 0) { hash[n] = &node[free]; } else { /* Find the end of the chain. */ nood = hash[n]; while (nood->next != (struct node *) 0) nood = nood->next; nood->next = &node[free]; } node[free].string = p; node[free].next = (struct node *) 0; free++; } } char *table[] = { "push ax", "ret", "mov bp,sp", "push bp", "pop bp", "mov sp,bp", ".text", "xor ax,ax", "push 4(bp)", "pop bx", "pop si", "cbw", "movb al,(bx)", "pop ax", "xorb ah,ah", "mov ax,#1", "call _callm1", "add sp,#16", "mov bx,4(bp)", "push 6(bp)", "mov -2(bp),ax", "I0013:", "call .cuu", "mov ax,-2(bp)", "add 4(bp),#1", "or ax,ax", "jmp I0011", "mov bx,8(bp)", "push dx", "mov cx,#2", "mov bx,#2", "I0011:", "I0012:", "push -2(bp)", "mov ax,4(bp)", "mov ax,-4(bp)", "add sp,#6", "and ax,#255", "push bx", "mov bx,-2(bp)", "loop 2b", "jcxz 1f", ".word 4112", "mov ax,(bx)", "mov -4(bp),ax", "jmp I0013", ".data", "mov bx,6(bp)", "mov (bx),ax", "je I0012", ".word 8224", ".bss", "mov ax,#2", "call _len", "call _callx", ".word 28494", ".word 0", "push -4(bp)", "movb (bx),al", "mov bx,ax", "mov -2(bp),#0", "I0016:", ".word 514", ".word 257", "mov ", "push ", ".word ", "pop ", "add ", "4(bp)", "-2(bp)", "(bx)", ".define ", ".globl ", "movb ", "xor ", "jmp ", "cmp ", "6(bp)", "-4(bp)", "-6(bp)", "#16", "_callm1", "call ", "8(bp)", "xorb ", "and ", "sub ", "-8(bp)", "jne ", ".cuu", "lea ", "inc ", "_M+10", "#255", "loop", "jcxz", "ax,#", "bx,#", "cx,#", "ax,", "bx,", "cx,", "dx,", "si,", "di,", "bp,", "ax", "bx", "cx", "dx", "si", "di", "bp", "sp", "dec ", "neg ", "_execve", ",#0", 0}; #define IBUFSIZE 10000 #define OBUFSIZE 30000 char input[IBUFSIZE+1], output[OBUFSIZE+1]; main() { int n, count; while (1) { n = read(0, input,IBUFSIZE); if (n <= 0) exit(1); input[n] = 0; count = unpack88(input, output); n = write(1, output, count); } } unpack88(inp, outp) register char *inp, *outp; { register k; char *p, *orig; orig = outp; while (*inp != 0) { k = *inp & 0377; if (k < 128) { *outp++ = *inp++; } else { p = table[k-128]; while (*p != 0) *outp++ = *p++; *inp++; } } return(outp - orig); } /* ln - link a file Author: Andy Tanenbaum */ #include "stat.h" char name[17]; struct stat stb; main(argc, argv) int argc; char **argv; { char *file1, *file2; char *last_comp(); if (argc < 2 || argc > 3) usage(); if (access(argv[1], 0) < 0) { std_err("ln: cannot access "); std_err(argv[1]); std_err("\n"); exit(1); } if (stat(argv[1], &stb) >= 0 && (stb.st_mode & S_IFMT) == S_IFDIR) usage(); file1 = argv[1]; /* "ln file" means "ln file ." */ if (argc == 2) file2 = "."; else file2 = argv[2]; /* Check to see if target is a directory. */ if (stat(file2, &stb) >= 0 && (stb.st_mode & S_IFMT) == S_IFDIR) { strcpy(name, file2); strcat(name, "/"); strcat(name, last_comp(file1)); file2 = name; } if (link(file1, file2)) { std_err("ln: Can't link\n"); exit(1); } exit(0); } char *last_comp(s) char *s; { /* Return pointer to last component of string. */ int n; n = strlen(s); while (n--) if (*(s+n) == '/') return(s+n+1); return(s); } usage() { std_err("Usage: ln file1 [file2]\n"); exit(1); } /* login - log into the system Author: Patrick van Kleef */ #include "signal.h" #include "sgtty.h" #include "pwd.h" main() { char buf[30], buf1[30], *crypt(); int n, n1, bad; struct sgttyb args; struct passwd *pwd, *getpwnam(); args.sg_kill = '@'; args.sg_erase = '\b'; args.sg_flags = 06030; ioctl (0, TIOCSETP, &args); /* Get login name and passwd. */ for (;;) { bad = 0; do { write(1,"login: ",7); n = read (0, buf, 30); } while (n < 2); buf[n - 1] = 0; /* Look up login/passwd. */ if ((pwd = getpwnam (buf)) == 0) bad++; if (bad || strlen (pwd->pw_passwd) != 0) { args.sg_flags = 06020; ioctl (0, TIOCSETP, &args); write(1,"Password: ",10); n1 = read (0, buf1, 30); buf1[n1 - 1] = 0; write(1,"\n",1); args.sg_flags = 06030; ioctl (0, TIOCSETP, &args); if (bad || strcmp (pwd->pw_passwd, crypt(buf1, pwd->pw_passwd))) { write (1,"Login incorrect\n",16); continue; } } /* Successful login. */ setgid (pwd->pw_gid); setuid (pwd->pw_uid); chdir (pwd->pw_dir); if (pwd->pw_shell) { execl(pwd->pw_shell, "-", (char *) 0); } execl("/bin/sh", "-", (char *) 0); write(1,"exec failure\n",13); } } /* lpr - line printer front end Author: Andy Tanenbaum */ #include "errno.h" #define BLOCK 1024 char in_buf[BLOCK], out_buf[BLOCK]; int cur_in, in_count, out_count, column; main(argc, argv) int argc; char *argv[]; { /* This program copies files to the line printer. It expands tabs and converts * line feeds to carriage returns + line feeds. */ int i, fd; close(1); if (open("/dev/lp", 1) < 0) { std_err("lpr: can't open /dev/lp\n"); exit(1); } if (argc == 1) { copy(0); /* standard input only */ } else { for (i = 1; i < argc; i++) { if ( (fd = open(argv[i],0)) < 0) { std_err("lpr: can't open "); std_err(argv[1]); std_err("\n"); exit(1); } else { copy(fd); close(fd); cur_in = 0; in_count = 0; } } } exit(0); } copy(fd) int fd; { /* Print a file, adding carriage returns and expanding tabs. */ char c; while (1) { if (cur_in == in_count) { in_count = read(fd, in_buf, BLOCK); if (in_count == 0) { flush(); return; } cur_in = 0; } c = in_buf[cur_in++]; if (c == '\n') { putc('\r'); putc('\n'); } else if (c == '\t') { do { putc(' '); } while (column & 07); } else putc(c); } } putc(c) char c; { out_buf[out_count++] = c; if (c == '\n') column = 0; else column++; if (out_count == BLOCK) { flush(); } } flush() { int n, count = 0; if (out_count == 0) return; while (1) { n = write(1, out_buf, out_count); if (n == out_count) break; if (n != EAGAIN) { std_err("Printer error\n"); exit(1); } if (count > 5) { std_err("Printer keeps returning busy status\n"); exit(1); } count++; sleep(1); } out_count = 0; } /* ls - list files and directories Author: Andy Tanenbaum */ #include "../h/const.h" #include "../h/type.h" #include "stat.h" #include "../fs/const.h" #include "../fs/type.h" #include "stdio.h" #define DIRNAMELEN 14 /* # chars in a directory entry name */ #define NFILE 256 /* max files in arg list to ls */ #define MAXPATHLEN 256 /* max chars in a path name */ #define NDIRBLOCKS 16 /* max length of a directory */ #define LEGAL 0x1E096DL /* legal flags to ls */ struct file { char *name; unsigned short mode; unsigned short f_uid; unsigned short f_gid; unsigned short inumber; long modtime; long size; short link; } file[NFILE+1]; struct dir { short inum; char dirname[DIRNAMELEN]; } dir[INODES_PER_BLOCK*NDIRBLOCKS]; int nrfiles; char linebuf[BLOCK_SIZE]; /* for reading passwd file */ int linenext; int linelimit; int topfiles; /* nr of files in ls command */ int passwd; /* file descr for /etc/passwd or /etc/group */ short sort_index[NFILE]; long flags; int lastuid = -1; char lastname[10]; char buffer[BUFSIZ]; char *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", "--s", "--s", "-ws", "-ws", "r-s", "r-s", "rws", "rws"}; char *null = {"."}; extern long get_flags(); extern char *getuidgid(); extern int errno; main(argc, argv) int argc; char *argv[]; { int expand_flag; /* allows or inhibits directory expansion */ char *pwfile; setbuf(stdout, buffer); expand_flag = 1; flags = get_flags(argc, argv); expand_args(argc, argv); if (topfiles == 0) { file[NFILE].name = null; exp_dir(&file[NFILE]); expand_flag = 0; } if (present('f')) flags = 0x21; /* -f forces other flags on and off */ sort(0, nrfiles, expand_flag); if (present('l')) { if (present('g')) pwfile = "/etc/group"; else pwfile = "/etc/passwd"; passwd = open(pwfile, 0); if (passwd < 0) fprintf(stdout, "Can't open %s\n", pwfile); } if (topfiles == 0) print_total(0, nrfiles); print(0, nrfiles, expand_flag, ""); fflush(stdout); exit(0); } expand_args(argc, argv) int argc; char *argv[]; { /* Put each argument presented to ls in a 'file' entry. */ int k, statflag; k = argc - topfiles; statflag = (topfiles == 0 ? 0 : 1); if (present('c') || present('t') || present('u')) statflag = 1; if (present('s') || present('l')) statflag = 1; while (k < argc) fill_file("", argv[k++], statflag); } sort(index, count, expand_flag) int index, count, expand_flag; { /* Sort the elements file[index] ... file[index+count-1] as needed. */ int i, j, tmp; if (count == 0) return; for (i = index; i < index + count; i++) sort_index[i] = i; if (present('f')) return; /* -f inhibits any sorting */ for (i = index; i < index + count - 1; i++) for (j = i + 1; j < index + count; j++) { if (reversed(sort_index[i], sort_index[j], expand_flag)) { /* Swap two entries */ tmp = sort_index[j]; sort_index[j] = sort_index[i]; sort_index[i] = tmp; } } } int reversed(i, j, expand_flag) int i, j, expand_flag; { /* Return 1 if elements 'i' and 'j' are reversed, else return 0. */ int r, m1, m2; struct file *fp1, *fp2; fp1 = &file[i]; fp2 = &file[j]; if (expand_flag) { if (fp1->size == -1L || fp2->size == -1L) { fprintf(stdout, "ls: internal bug: non-stat'ed file in reversed()\n"); fflush(stdout); exit(1); } m1 = fp1->mode & I_TYPE; m2 = fp2->mode & I_TYPE; if (m1 == I_DIRECTORY && m2 != I_DIRECTORY) return(1); if (m1 != I_DIRECTORY && m2 == I_DIRECTORY) return(0); } r = present('r'); if (present('t') || present('u')) { /* Sort on time field. */ if (fp1->modtime > fp2->modtime) return(r); else return(1-r); } else { /* Sort alphabetically. */ if (strlower(fp1->name, fp2->name, MAXPATHLEN)) return(r); else return(1-r); } } int strlower(s1, s2, count) char *s1, *s2; int count; { /* Return 1 is s1 < s2 alphabetically, else return 0. */ while (count--) { if (*s1 == 0 && *s2 == 0) return(1); if (*s1 == 0) return(1); if (*s2 == 0) return(0); if (*s1 < *s2) return(1); if (*s1 > *s2) return(0); s1++; s2++; } /* The strings are identical up to the given length. */ return(1); } print(index, count, expand, dirname) int index, count, expand; char *dirname; { /* If an entry is a file, print it; if a directory, process it. */ int k, m, nrf; struct file *fp; nrf = nrfiles; for (k = index; k < index + count; k++) { fp = &file[sort_index[k]]; if (present('l') || present('s') || present('i')) if (fp->size == -1L) /* -1 means stat not done */ if (stat_file(dirname, fp) < 0) continue; m = fp->mode & I_TYPE; /* 'm' may be junk if 'expand' = 0 */ if (present('f')) m = I_DIRECTORY; if (m != I_DIRECTORY || present('d') || expand == 0) { /* List a single line. */ print_line(fp); } else { /* Expand and print directory. */ exp_dir(fp); sort(nrf, nrfiles - nrf, 0); if (topfiles > 1) fprintf(stdout, "\n%s:\n", fp->name); print_total(nrf, nrfiles - nrf); print(nrf, nrfiles - nrf, 0, fp->name); /* recursion ! */ nrfiles = nrf; } } } exp_dir(fp) struct file *fp; { /* List the files within a directory. Read whole dir in one blow. * Expand and print whole dir in core, since 'file' struct has pointers to it. */ int n, fd, k, klim, suppress, statflag; char *p; fd = open(fp->name, 0); if (fd < 0) { fprintf(stdout, "Cannot list contents of %s\n", fp->name); return; } suppress = !present('a'); n = read(fd, dir, INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS); klim = (n + DIRNAMELEN + 1)/(DIRNAMELEN + 2); if (n == INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS) { fprintf(stdout, "Directory %s too long\n", fp->name); return; } statflag = 0; if (present('c') || present('t') || present('u')) statflag = 1; if (present('s') || present('l')) statflag = 1; for (k = 0; k < klim; k++) { if (dir[k].inum != 0) { p = dir[k].dirname; if (suppress) { if (*p == '.' && *(p+1) == 0) continue; if (*p == '.' && *(p+1) == '.' && *(p+2) == 0) continue; } fill_file(fp->name, p, statflag); } } close(fd); } fill_file(prefix, postfix, statflag) char *prefix, *postfix; int statflag; { /* Fill the next 'file' struct entry with the file whose name is formed by * concatenating 'prefix' and 'postfix'. Stat only if needed. */ struct file *fp; if (nrfiles == NFILE) { fprintf(stdout, "ls: Out of space\n"); fflush(stdout); exit(1); } fp = &file[nrfiles++]; fp->name = postfix; if(statflag) { if (stat_file(prefix, fp) < 0) nrfiles--; } else { fp->size = -1L; /* mark file as not yet stat'ed */ } } print_line(fp) struct file *fp; { int blks, m, prot, s; char *p1, *p2, *p3, c; if (present('i')) fprintf(stdout, "%5d ", fp->inumber); if (present('s')) { /* Print file size */ blks = nblocks(fp->size); fprintf(stdout, "%4d ", blks); } if (present('l')) { m = fp->mode & I_TYPE; if (m == I_DIRECTORY) c = 'd'; else if (m == I_BLOCK_SPECIAL) c = 'b'; else if (m == I_CHAR_SPECIAL) c = 'c'; else c = '-'; m = fp->mode & 07777; prot = (m >> 6) & 07; if (m & I_SET_UID_BIT) prot += 8; p1 = rwx[prot]; prot = (m >> 3) & 07; if (m & I_SET_GID_BIT) prot += 8; p2 = rwx[prot]; prot = m & 07; p3 = rwx[prot]; fprintf(stdout, "%c%s%s%s %2d ",c, p1, p2, p3, fp->link); /* Print owner or group */ owngrp(fp); m = fp->mode & I_TYPE; if (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL) { s = (short) fp->size; fprintf(stdout, "%2d, %2d ", (s>>8)&0377, s&0377); } else { fprintf(stdout, "%8D ", fp->size); } date(fp->modtime); } /* Print file name. */ m = 0; p1 = fp->name; while (*p1 != 0 && (m < DIRNAMELEN || *p1 == '/') ) { fprintf(stdout, "%c", *p1); m = (*p1 == '/' ? 0 : m + 1); p1++; } fprintf(stdout, "\n"); } owngrp(fp) struct file *fp; { char *buf; int xid; if (present('g')) { xid = fp->f_gid; } else { xid = fp->f_uid; } buf = getuidgid(xid); if (buf != 0) fprintf(stdout, "%6s ",buf); else fprintf(stdout, "%6d ",xid); } int stat_file(prefix, fp) char *prefix; struct file *fp; { /* Stat a file and enter it in 'file'. */ char namebuf[MAXPATHLEN], *p, *org, *uwxyz{q; struct stat sbuf; int m, ctr; /* Construct the full path name in 'namebuf'. */ p = namebuf; q = prefix; while (*q != 0 && p - namebuf < MAXPATHLEN) *p++ = *q++; if (*prefix != 0) *p++ = '/'; org = fp->name; q = fp->name; ctr = 0; while (*q != 0 && p - namebuf < MAXPATHLEN) { ctr++; if (*q == '/') ctr = 0; if (ctr > DIRNAMELEN) break; *p++ = *q++; } *p = 0; /* The name has been built. Stat the file and copy the info. */ if ((m = stat(namebuf, &sbuf)) < 0) { fprintf(stdout, "%s not found\n", namebuf); return(-1); } m = sbuf.st_mode & I_TYPE; fp->mode = sbuf.st_mode; fp->f_uid = sbuf.st_uid; fp->f_gid = sbuf.st_gid; fp->inumber = sbuf.st_ino; fp->modtime = sbuf.st_mtime; fp->size = sbuf.st_size; fp->size = (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL ? sbuf.st_rdev : sbuf.st_size); fp->link = sbuf.st_nlink; return(0); } long get_flags(argc, argv) int argc; char *argv[]; { /* Get the flags. */ long fl, t; int k, n; char *ptr; fl = 0L; n = 1; topfiles = argc - 1; while (n < argc) { ptr = argv[n]; if (*ptr != '-') return(fl); topfiles--; ptr++; while (*ptr != 0) { k = *ptr - 'a'; t = 1L << k; if (*ptr < 'a' || *ptr > 'z' || (t|LEGAL) != LEGAL) { fprintf(stdout, "Bad flag: %c\n", *ptr); ptr++; continue; } fl |= t; ptr++; } n++; } return(fl); } present(let) char let; { return (flags >> (let - 'a')) & 01; } #define YEAR (365L * 24L * 3600L) #define LYEAR (366L * 24L * 3600L) int mo[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; long curtime; char *moname[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; date(t) long t; /* time in seconds */ { /* Print the date. This only works from 1970 to 2099. */ int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if ( t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = t/(24L * 3600L); t -= (long) day * 24L * 3600L; hour = t/3600L; t -= 3600L * (long) hour; minute = (int) t/60L; /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ if (curtime == 0) curtime = time( (long*)0); /* approximate current time */ fprintf(stdout, "%3s %2d ",moname[month], day+1); if (curtime - original >= YEAR/2L) { fprintf(stdout, "%5d ",year); } else { if (hour < 10) fprintf(stdout, "0%d:",hour); else fprintf(stdout, "%2d:",hour); if (minute < 10) fprintf(stdout, "0%d ",minute); else fprintf(stdout, "%2d ",minute); } } print_total(index, count) int index, count; { int blocks, i; if (!present('l') && !present('s')) return; blocks = 0; for (i = index; i < index + count; i++) blocks += nblocks(file[i].size); fprintf(stdout, "total %d\n", blocks); } char getpwdch() { if (linenext == linelimit) { /* Fetch another block of passwd file. */ linelimit = read(passwd, linebuf, BLOCK_SIZE); linenext = 0; if (linelimit <= 0) return (char) 0; } return (linebuf[linenext++]); } getline(buf) char *buf; { while (1) { *buf = getpwdch(); if (*buf == 0 || *buf == '\n') break; buf++; } *buf = 0; } char *getuidgid(usrid) int usrid; { char lbuf[100], *ptr, *ptr1; int bin; if (usrid == lastuid) return(lastname); lseek(passwd, 0L, 0); /* rewind the file */ linenext = 0; linelimit = 0; /* Scan the file. */ while (1) { ptr = lbuf; while (ptr < &lbuf[100]) *ptr++ = 0; getline(lbuf); if (lbuf[0] == 0) return(0); /* Scan this line for uid/gid */ ptr = lbuf; while (*ptr != ':' && *ptr != 0) ptr++; if (*ptr == 0) return(0); *ptr++ = 0; while (*ptr != ':' && *ptr != 0) ptr++; if (*ptr == 0) return(0); ptr++; /* Ptr now points at a uid. Convert it to binary. */ bin = 0; while (*ptr != ':' && *ptr != 0 && *ptr != '\n') { bin = 10*bin + (*ptr - '0'); ptr++; } if (bin == usrid) { /* Hit. */ lastuid = usrid; ptr = lastname; ptr1 = lbuf; while (*ptr++ = *ptr1++) ; *ptr++ = 0; return(lastname); } } } nblocks(size) long size; { /* Convert file length to blocks, including indirect blocks. */ int blocks, fileb; fileb = (size + (long) BLOCK_SIZE - 1)/BLOCK_SIZE; blocks = fileb; if (fileb <= NR_DZONE_NUM) return(blocks); blocks++; fileb -= NR_DZONE_NUM; if (fileb <= NR_INDIRECTS) return(blocks); blocks++; fileb -= NR_INDIRECTS; blocks += (fileb + NR_INDIRECTS - 1)/NR_INDIRECTS; return(blocks); } /* mkdir - make a directory Author: Adri Koppes */ #include "signal.h" int error = 0; main(argc, argv) int argc; char **argv; { if (argc < 2) { std_err("Usage: mkdir directory...\n"); exit(1); } signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); while (--argc) makedir(*++argv); if (error) exit(1); } makedir(dirname) char *dirname; { char dots[128], parent[128]; int sl = 0, i = 0; while (dirname[i]) if (dirname[i++] == '/') sl = i; strncpy(parent, dirname, sl); parent[sl] = '\0'; strcat(parent, "."); if (access(parent, 2)) { stderr3("mkdir: can't access ", parent, "\n"); exit(1); } if (mknod(dirname, 040777, 0)) { stderr3("mkdir: can't create ", dirname, "\n"); error++; return; } chown(dirname, getuid(), getgid()); strcpy(dots, dirname); strcat(dots, "/."); if (link(dirname, dots)) { stderr3("mkdir: can't link ", dots, " to "); stderr3(dirname, "\n", ""); error++; unlink(dirname); return; } strcat(dots, "."); if (link(parent, dots)) { stderr3("mkdir: can't link ", dots, " to "); stderr3(parent, "\n", ""); error++; dots[strlen(dots)] = '\0'; unlink(dots); unlink(dirname); return; } } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); } /* mkfs - make the MINIX filesystem * Andy Tanenbaum & Paul Ogilvie, Jun 1986 * * This program was initially designed to build a filesystem * with blocksize = zonesize. During the course of time the * program is being converted to handle zone_size > blocksize * but this isn't complete yet. Where routines can handle the * situation this is mentioned in the comment. * * To compile this program for MS-DOS, use: cc -DDOS mkfs.c diskio.asm * To compile this program for UNIX, use: cc -DUNIX mkfs.c * To compile this program for MINIX, use: cc mkfs.c */ #include "../h/const.h" #include "../h/type.h" #include "../fs/const.h" #undef EXTERN #define EXTERN /* get rid of EXTERN by making it null */ #include "../fs/type.h" #include "../fs/super.h" #ifdef DOS #include "/lib/c86/stdio.h" #define COMPILERFLAG #endif #ifdef UNIX #include #include #include #undef major #undef minor #define COMPILERFLAG #endif #ifndef COMPILERFLAG #include "stdio.h" #include "stat.h" #endif #ifndef DOS #ifndef UNIX #define UNIX #endif #endif #ifdef UNIX #undef printf /* printf is a macro for printk */ #endif #define INODE_MAP 2 #define MAX_TOKENS 10 #define LINE_LEN 200 #define BIN 2 #define BINGRP 2 #define BIT_MAP_SHIFT 13 #define N_BLOCKS 32000 /* must be multiple of 8 */ #ifdef DOS # define BREAD 4 # define BWRITE 5 #else # define BREAD 0 # define BWRITE 1 #endif int next_zone, next_inode, zone_size, zone_shift=0, zoff, nrblocks,inode_offset, nrinodes, lct=1, disk, fd, print=0, file=0, override=0, simple=0, dflag; long current_time, bin_time; char zero[BLOCK_SIZE], *lastp; char umap[(N_BLOCKS+8)/8]; /* bit map tells if block read yet */ int zone_map = 3; /* where is zone map? (depends on # inodes) */ FILE *proto; long lseek(); char *size_fmt = "%6D"; char *ldfmt = "%6ld"; char *mode_fmt = "%6o"; char *ldmode = "%06o"; char gwarning[] = {65,46,83,46,84,97,110,101,110,98,97,117,109,10}; /* MS-DOS and PC-IX use %ld for longs, MINIX uses %D */ /*================================================================ * mkfs - make filesystem *===============================================================*/ main(argc, argv) int argc; char *argv[]; { int i, blocks, zones, inodes, mode, usrid, grpid, badusage = 0; char *token[MAX_TOKENS], buf[BLOCK_SIZE]; int testb[2]; FILE *fopen(); long time(), ls; struct stat statbuf; /* Get two times, the current time and the mod time of the binary of * mkfs itself. When the -d flag is used, the later time is put into * the i_modtimes of all the files. This feature is useful when producing * a set of file systems, and one wants all the times to be identical. * First you set the time of the mkfs binary to what you want, then go. */ current_time = time(0L); /* time mkfs is being run */ stat(argv[0], &statbuf); bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */ /* process parameters and switches */ if (argc != 3 && argc != 4) badusage = 1; if (stat(argv[argc - 1], &statbuf) == 0) { if ( (statbuf.st_mode&S_IFMT) != S_IFREG) badusage = 1; } if (badusage) { write(2, "Usage: mkfs [-L] special proto\n", 31); exit(1); } while (--argc) { switch (argv[argc][0]) { case '-': while (*++argv[argc]) switch (*argv[argc]) { case 'L' : print=1; break; case 'l' : print=1; size_fmt = ldfmt; mode_fmt = ldmode; break; case 'o' : case 'O' : override=1; break; case 'd' : current_time = bin_time; dflag=1; break; default : printf ("Bad switch %c, ignored.\n",*argv[argc]); } break; default : /* process proto & special */ proto = fopen(argv[argc], "r" ); if (proto != NULL) { /* Prototype file is readable. */ getline(buf, token); /* skip boot block info. */ /* Read the line with the block and inode counts. */ getline(buf, token); blocks = atoi(token[0]); if (blocks > N_BLOCKS) pexit("Block count too large"); inodes = atoi(token[1]); /* Process mode line for root directory. */ getline(buf, token); mode = mode_con(token[0]); usrid = atoi(token[1]); grpid = atoi(token[2]); } else { /* Maybe the prototype file is just a size. Check for that. */ blocks = atoi(argv[argc]); if (blocks < 4) pexit("Can't open prototype file"); /* Ok, make simple file system of given size, using defaults. */ inodes = (blocks/3) + 8; /* default is 3 blocks/file */ mode = 040777; usrid = BIN; grpid = BINGRP; simple = 1; } /* open special */ argc--; special(argv[argc]); nrblocks = blocks; nrinodes = inodes; } /* end switch */ } /* end while */ #ifdef UNIX /* Try writing the last block of partition or diskette. */ ls = lseek(fd, ((long)blocks - 1L) * BLOCK_SIZE, 0); testb[0] = 0x3245; testb[1] = 0x11FF; if (write(fd, testb, BLOCK_SIZE) != BLOCK_SIZE) pexit("File system is too big for minor device"); lseek(fd, ((long)blocks - 1L) * BLOCK_SIZE, 0); testb[0] = 0; testb[1] = 0; i = read(fd, testb, BLOCK_SIZE); if (i != BLOCK_SIZE || testb[0] != 0x3245 || testb[1] != 0x11FF) pexit("File system is too big for minor device"); lseek(fd, 0L, 0); #endif /* make the file-system */ cache_init(); put_block (0, zero); /* Write a null boot block. */ zone_shift = 0; /* for future use */ zones = blocks >> zone_shift; super(zones, inodes); i = alloc_inode(mode, usrid, grpid); rootdir(i); if (simple == 0) eat_dir(i); if (print) print_fs(); flush(); exit (0); } /* end main */ /*================================================================ * super - construct a superblock *===============================================================*/ super(zones, inodes) int zones, inodes; { unsigned int i, inodeblks, initblks, initzones, nrzones, bs; unsigned int map_size, bit_map_len, b_needed, b_allocated, residual; long zo; struct super_block *sup; char buf[BLOCK_SIZE], *cp; sup= (struct super_block *) buf; bs = 1 << BIT_MAP_SHIFT; sup->s_ninodes = inodes; sup->s_nzones = zones; sup->s_imap_blocks = (inodes + bs)/bs; sup->s_zmap_blocks = (zones + bs - 1)/bs; inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2; inodeblks = (inodes + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK; initblks = inode_offset + inodeblks; initzones = (initblks + (1<> zone_shift; nrzones = nrblocks >> zone_shift; sup->s_firstdatazone = (initblks + (1<> zone_shift; zoff = sup->s_firstdatazone - 1; sup->s_log_zone_size = zone_shift; sup->s_magic = SUPER_MAGIC; /* identify super blocks */ zo = 7L + (long) NR_INDIRECTS + (long) NR_INDIRECTS * NR_INDIRECTS; sup->s_max_size = zo * BLOCK_SIZE; zone_size = 1 << zone_shift; /* nr of blocks per zone */ for (cp = buf + sizeof(*sup); cp < &buf[BLOCK_SIZE]; cp++) *cp=0; put_block (1,buf); /* Clear maps and inodes. */ for (i = 2; i < initblks; i++) put_block (i, zero); next_zone = sup->s_firstdatazone; next_inode = 1; /* Mark all bits beyond the end of the legal inodes and zones as allocated. * Unfortunately, the coding the bit maps is inconsistent. The rules are: * For inodes: Every i-node occupies a bit map slot, even i-node 0 * The first i-node on the disk is i-node 1, not 0 * For zones: Zone map bit 0 is for the last i-node block on disk * The first zone available goes with bit 1 in the map * * Thus for i-nodes, every i-node, starting at 0 occupies a bit map slot, * but for zones, only those starting with the final i-node block occupy * bit slots. This is inconsistent. In retrospect it would might have been * simpler to have bit 0 of the zone map be zone 0 on the disk. Although * this would have increased the zone bit map by a few dozen bits, it would * have prevented a number of bugs in the early days. This is an example of * what happens when on…‡ˆ‰Š‹ŒŽ‘’“”•–89e ignores the maxim: First make it work, then make * it optimal. For both maps, 0 = available, 1 = in use. */ /* Mark bits beyond end of inodes as allocated. (Fails if >8192 inodes). */ map_size = 1 << BIT_MAP_SHIFT; bit_map_len = nrinodes + 1; /* # bits needed in map */ residual = bit_map_len % (8 * BLOCK_SIZE); if (residual == 0) residual = 8 * BLOCK_SIZE; b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT; zone_map += b_needed - 1; /* if imap > 1, adjust start of zone map */ insert_bit(INODE_MAP + b_needed - 1, residual, 8 * BLOCK_SIZE - residual); bit_map_len = nrzones - initzones + 1; /* # bits needed in map */ residual = bit_map_len % (8 * BLOCK_SIZE); if (residual == 0) residual = 8 * BLOCK_SIZE; b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT; b_allocated = (nrzones + map_size - 1 ) >> BIT_MAP_SHIFT; insert_bit(zone_map + b_needed - 1, residual, 8 * BLOCK_SIZE - residual); if (b_needed != b_allocated) { insert_bit(zone_map + b_allocated - 1, 0, map_size); } insert_bit(zone_map, 0, 1); /* bit zero must always be allocated */ insert_bit(INODE_MAP, 0, 1); /* inode zero not used but must be allocated */ } /*================================================================ * rootdir - install the root directory *===============================================================*/ rootdir(inode) int inode; { int z; z = alloc_zone(); add_zone (inode, z, 32L, current_time); enter_dir(inode, ".", inode); enter_dir(inode, "..", inode); incr_link(inode); incr_link(inode); } /*================================================================ * eat_dir - recursively install directory *===============================================================*/ eat_dir(parent) int parent; /* parent's inode nr */ { /*Read prototype lines and set up directory. Recurse if need be. */ char *token[MAX_TOKENS], *p; char line[LINE_LEN]; int mode, n, usrid, grpid, z, major, minor, f; long size; while (1) { getline(line, token); p = token[0]; if (*p == '$') return; p = token[1]; mode = mode_con(p); usrid = atoi(token[2]); grpid = atoi(token[3]); if (grpid & 0200) write(2, gwarning, 14); n = alloc_inode(mode, usrid, grpid); /* Enter name in directory and update directory's size. */ enter_dir(parent, token[0], n); incr_size(parent, 16L); /* Check to see if file is directory or special. */ incr_link(n); if (*p == 'd') { /* This is a directory. */ z = alloc_zone(); /* zone for new directory */ add_zone(n, z, 32L, current_time); enter_dir(n, ".", n); enter_dir(n, "..", parent); incr_link(parent); incr_link(n); eat_dir(n); } else if (*p == 'b' || *p == 'c') { /* Special file. */ major = atoi(token[4]); minor = atoi(token[5]); size = atoi(token[6]); size = BLOCK_SIZE * size; add_zone(n, (major<<8)|minor, size, current_time); } else { /* Regular file. Go read it. */ if ((f=open(token[4],BREAD)) < 0) { write(2, "Can't open file ", 16); write(2, token[4], strlen(token[4]) ); write(2, "\n", 1); } else eat_file(n, f); } } } /*================================================================ * eat_file - copy file to MINIX *===============================================================*/ /* zonesize >= blocksize */ eat_file(inode, f) int inode, f; { int z, ct, i, j, k; char buf[BLOCK_SIZE]; long timeval; extern long file_time(); do { for (i=0, j=0; i < zone_size; i++, j+=ct ) { for (k = 0; k < BLOCK_SIZE; k++) buf[k] = 0; if ((ct=read(f,buf, BLOCK_SIZE)) > 0) { if (i==0) z = alloc_zone(); put_block ( (z << zone_shift) + i, buf); } } timeval = (dflag ? current_time : file_time(f) ); if (ct) add_zone (inode, z, (long) j, timeval ); } while (ct == BLOCK_SIZE); close(f); } /*================================================================ * directory & inode management assist group *===============================================================*/ enter_dir(parent, name, child) int parent, child; /* inode nums */ char *name; { /* enter child in parent directory */ /* works for dir > 1 block and zone > block */ int i, j, k, l, b, z, off; char *p1, *p2; struct { short inumb; char name[14]; } dir_entry[NR_DIR_ENTRIES]; d_inode ino[INODES_PER_BLOCK]; b = ((parent-1) / INODES_PER_BLOCK) + inode_offset; off = (parent-1) % INODES_PER_BLOCK ; get_block ( b, ino); for ( k=0; ki_size += bytes; p->i_modtime = cur_time; for (i=0; i < NR_DZONE_NUM; i++) if (p->i_zone[i] == 0) { p->i_zone[i] = z; put_block(b, inode); return; } put_block(b, inode); /* File has grown beyond a small file. */ if (p->i_zone[NR_DZONE_NUM] == 0) p->i_zone[NR_DZONE_NUM] = alloc_zone(); indir = p->i_zone[NR_DZONE_NUM]; put_block(b, inode); b = indir << zone_shift; get_block(b, blk); for (i = 0; i < NR_INDIRECTS; i++) if (blk[i] == 0) { blk[i] = (zone_nr) z; put_block(b, blk); return; } pexit("File has grown beyond single indirect"); } incr_link(n) int n; { /* increment the link count to inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_nlinks++; put_block(b, inode); } incr_size(n,count) int n; long count; { /* increment the file-size in inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_size += count; put_block(b, inode); } /*================================================================ * allocation assist group *===============================================================*/ int alloc_inode(mode, usrid, grpid) int mode, usrid, grpid; { int num, b, off; d_inode inode[INODES_PER_BLOCK]; num = next_inode++; if (num >= nrinodes) pexit("File system does not have enough inodes"); b = ((num-1) / INODES_PER_BLOCK) + inode_offset; off = (num-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_mode = mode; inode[off].i_uid = usrid; inode[off].i_gid = grpid; put_block(b, inode); /* Set the bit in the bit map. */ insert_bit(INODE_MAP, num, 1); return(num); } int alloc_zone() { /* allocate a new zone */ /* works for zone > block */ int b,z,i; z = next_zone++; b = z << zone_shift; if ( (b+zone_size) > nrblocks) pexit("File system not big enough for all the files"); for ( i=0; i < zone_size; i++) put_block ( b+i, zero ); /* give an empty zone */ insert_bit(zone_map, z - zoff, 1); return(z); } insert_bit(block, bit, count) int block, bit, count; { /* insert 'count' bits in the bitmap */ int w,s, i; int buf[BLOCK_SIZE/sizeof(int)]; get_block(block, buf); for (i = bit; i < bit + count; i++) { w = i / (8*sizeof(int)); s = i % (8*sizeof(int)); buf[w] |= (1 << s); } put_block(block, buf); } /*================================================================ * proto-file processing assist group *===============================================================*/ int mode_con(p) char *p; { /* convert string to mode */ int o1, o2, o3, mode; char c1, c2, c3; c1 = *p++; c2 = *p++; c3 = *p++; o1 = *p++ - '0'; o2 = *p++ - '0'; o3 = *p++ - '0'; mode = (o1 << 6) | (o2 << 3) | o3; if (c1 == 'd') mode += I_DIRECTORY; if (c1 == 'b') mode += I_BLOCK_SPECIAL; if (c1 == 'c') mode += I_CHAR_SPECIAL; if (c1 == '-') mode += I_REGULAR; if (c2 == 'u') mode += I_SET_UID_BIT; if (c3 == 'g') mode += I_SET_GID_BIT; return(mode); } getline(line, parse) char *parse[MAX_TOKENS]; char line[LINE_LEN]; { /* read a line and break it up in tokens */ int k; char c, *p; for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0; for (k = 0; k < LINE_LEN; k++) line[k] = 0; k = 0; parse[0] = 0; p = line; while (1) { *p = fgetc(proto); if (*p == '\n') lct++; if (*p <= 0) pexit("Unexpected end-of-file\n"); if (*p == ' ' || *p == '\t') *p = 0; if (*p == '\n') {*p++ = 0; *p = '\n'; break;} p++; } p = line; lastp = line; while (1) { c = *p++; if (c == '\n') return; if (c == 0) continue; parse[k++] = p - 1; do { c = *p++; } while (c != 0 && c != '\n'); } } /*================================================================ * other stuff *===============================================================*/ long file_time(f) int f; { #ifdef UNIX struct stat statbuf; fstat(f, & statbuf); return (statbuf.st_mtime); #else /* fstat not supported by DOS */ return( 0L ); #endif } pexit(s) char *s; { char *s0; s0 = s; while (*s0 != 0) s0++; write (2,"Error: ", 7); write (2, s, (int)(s0-s) ); write(2, "\n", 1); printf("Line %d being processed when error detected.\n", lct); flush(); exit(2); } copy (from, to, count) char *from, *to; int count; { while (count--) *to++ = *from++; } print_fs() { int i, j, k; d_inode inode[INODES_PER_BLOCK]; int ibuf[INTS_PER_BLOCK], b; struct { short inum; char name[14]; } dir[NR_DIR_ENTRIES]; get_block(1, ibuf); printf("\nSuperblock: "); for (i= 0; i<8; i++) printf("%06o ",ibuf[i]); get_block(2, ibuf); printf("\nInode map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); get_block(3, ibuf); printf("\nZone map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); printf("\n"); for (b = 4; b < 8; b++) { get_block(b, inode); for (i = 0; i < INODES_PER_BLOCK; i++) { k = INODES_PER_BLOCK * (b - 4) + i + 1; if (k > nrinodes) break; if (inode[i].i_mode != 0) { printf("Inode %2d: mode=",k, inode[i].i_mode); printf(mode_fmt, inode[i].i_mode); printf(" uid=%2d gid=%2d size=", inode[i].i_uid, inode[i].i_gid); printf(size_fmt, inode[i].i_size); printf(" zone[0]=%d\n", inode[i].i_zone[0]); } if ( (inode[i].i_mode & I_TYPE) == I_DIRECTORY) { /* This is a directory */ get_block(inode[i].i_zone[0], dir); for (j = 0; j < NR_DIR_ENTRIES; j++) if (dir[j].inum) printf("\tInode %2d: %s\n",dir[j].inum,dir[j].name); } } } printf("%d inodes used. %d zones used.\n",next_inode-1, next_zone); } int read_and_set(n) int n; { /* The first time a block is read, it returns alls 0s, unless there has * been a write. This routine checks to see if a block has been accessed. */ int w, s, mask, r; w = n/8; s = n%8; mask = 1 << s; r = (umap[w] & mask ? 1 : 0); umap[w] |= mask; return(r); } /*================================================================ * get_block & put_block for MS-DOS *===============================================================*/ #ifdef DOS /* * These are the get_block and put_block routines * when compiling & running mkfs.c under MS-DOS. * * It requires the (asembler) routines absread & abswrite * from the file diskio.asm. Since these routines just do * as they are told (read & write the sector specified), * a local cache is used to minimize the i/o-overhead for * frequently used blocks. * * The global variable "file" determines whether the output * is to a disk-device or to a binary file. */ #define PH_SECTSIZE 512 /* size of a physical disk-sector */ char *derrtab[14] = { "no error", "disk is read-only", "unknown unit", "device not ready", "bad command", "data error", "internal error: bad request structure length", "seek error", "unknown media type", "sector not found", "printer out of paper (??)", "write fault", "read error", "general error" }; #define CACHE_SIZE 20 /* 20 block-buffers */ struct cache { char blockbuf[BLOCK_SIZE]; int blocknum; int dirty; int usecnt; } cache[CACHE_SIZE]; special (string) char *string; { if (string[1] == ':' && string[2]==0) { /* format: d: or d:fname */ disk = (string[0] & ~32) - 'A'; if (disk>1 && !override) /* safety precaution */ pexit ("Bad drive specifier for special"); } else { file=1; if ((fd = creat(string,BWRITE)) == 0) pexit ("Can't open special file"); } } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* get a block to the user */ struct cache *bp,*fp; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (bp,buf,BLOCK_SIZE); bp->usecnt++; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache, get it */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } mx_read (n, fp); fp->dirty=0; fp->usecnt=0; fp->blocknum=n; copy (fp, buf, BLOCK_SIZE); } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Accept block from user */ struct cache *fp, *bp; read_and_set(n); /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (buf,bp,BLOCK_SIZE); bp->dirty=1; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } fp->dirty=1; fp->usecnt=1; fp->blocknum=n; copy (buf,fp,BLOCK_SIZE); } cache_init() { struct cache *bp; for (bp=cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1; } flush () { /* flush all dirty blocks to disk */ struct cache *bp; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) if (bp->dirty) { mx_write (bp->blocknum, bp); bp->dirty=0; } } /*================================================================== * hard read & write etc. *=================================================================*/ #define MAX_RETRIES 5 mx_read (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* read the requested MINIX-block in core */ char (*bp)[PH_SECTSIZE]; int sectnum,retries,err; if (file) { lseek (fd, (long) blocknr * BLOCK_SIZE, 0); if (read (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) pexit ("mx_read: error reading file"); } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do err=absread (disk,sectnum,bp); while (err && --retries); if (retries) { sectnum++; } else { dexit ("mx_read",sectnum,err); } } } } mx_write (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* write the MINIX-block to disk */ char (*bp)[PH_SECTSIZE]; int retries,sectnum,err; if (file) { lseek (fd, blocknr * BLOCK_SIZE, 0); if (write (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit ("mx_write: error writing file"); } } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do { err=abswrite (disk,sectnum,bp); } while (err && --retries); /* mknod - build a special file Author: Andy Tanenbaum */ main(argc, argv) int argc; char *argv[]; { /* mknod name b/c major minor makes a node. */ int mode, major, minor; if (argc != 5) badcomm(); if (*argv[2] != 'b' && *argv[2] != 'c') badcomm(); mode = (*argv[2] == 'b' ? 060666 : 020666); major = atoi(argv[3]); minor = atoi(argv[4]); if (major < 0 || minor < 0) badcomm(); if (mknod(argv[1], mode, (major<<8) | minor) < 0) perror("mknod"); exit(0); } int atoi(p) char *p; { /* Ascii to integer conversion. */ int c, n; n = 0; while (c = *p++) { if (c < '0' || c > '9') return (-1); n = 10 * n + (c - '0'); } return(n); } badcomm() { std_err("Usage: mknod name b/c major minor\n"); exit(1); } /* mount - mount a file system Author: Andy Tanenbaum */ #include "errno.h" extern int errno; main(argc, argv) int argc; char *argv[]; { int ro; if (argc < 3 || argc > 4) usage(); if (argc == 4 && *argv[3] != '-' && *(argv[3]+1) != 'r') usage(); ro = (argc == 4 ? 1 : 0); if (mount(argv[1], argv[2], ro) < 0) { if (errno == EINVAL) { std_err("mount: "); std_err(argv[1]); std_err(" is not a valid file system.\n"); } else { perror("mount"); } exit(1); } std_err(argv[1]); std_err(" mounted\n"); exit(0); } usage() { std_err("Usage: mount special name [-r]\n"); exit(1); } /* mv - move files Author: Adri Koppes * * 4/25/87 - J. Paradis Bug fixes for directory handling */ #include "signal.h" #include "stat.h" int error = 0; struct stat st, st1; main (argc, argv) int argc; char **argv; { char *destdir; if (argc < 3) { std_err ("Usage: mv file1 file2 or mv dir1 dir2 or mv file1 file2 ... dir\n"); exit (1); } if (argc == 3) { if (stat (argv[1], &st)) { std_err ("mv: "); std_err (argv[1]); std_err (" doesn't exist\n"); exit (1); } move (argv[1], argv[2]); } else { destdir = argv[--argc]; if (stat (destdir, &st)) { std_err ("mv: target directory "); std_err (destdir); std_err (" doesn't exist\n"); exit(1); } if ((st.st_mode & S_IFMT) != S_IFDIR) { std_err ("mv: target "); std_err (destdir); std_err (" not a directory\n"); exit (1); } while (--argc) move (*++argv, destdir); } if (error) exit (1); exit(0); } move (old, new) char *old, *new; { int retval; char name[64]; /* It's too dangerous to fool with "." or ".." ! */ if((strcmp(old, ".") == 0) || (strcmp(old, "..") == 0)) { cant(old); } /* Don't move a file to itself. */ if (stat(old, &st)==0 && stat(new, &st1)==0 && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) cant(old); if (!stat (new, &st)) if((st.st_mode & S_IFMT) != S_IFDIR) unlink (new); else { char *p, *rindex(); if ((strlen(old) + strlen(new) + 2) > 64) { cant(old); error++; return; } strcpy(name, new); strcat(name, "/"); p = rindex(old, '/'); strcat(name, p ? p : old); new = name; } stat (old, &st); if (link (old, new)) if ((st.st_mode & S_IFMT) != S_IFDIR) { switch (fork ()) { case 0: setgid (getgid ()); setuid (getuid ()); execl ("/bin/cp", "cp", old, new, (char *) 0); cant(old); case -1: std_err ("mv: can't fork\n"); exit (1); default: wait (&retval); if (retval) cant(old); } } else cant(old); /* If this was a directory that we moved, then we have ** to update its ".." entry (in case it was moved some- ** where else in the tree...) */ if ((st.st_mode & S_IFMT) == S_IFDIR) { int i; char parent[64], dotdot[64]; strcpy(parent, new); /* Determine the name for the parent of ** the new name by counting back until we ** hit a '/' or the begining of the string */ for(i = (strlen(parent) - 1); i > 0; i--) { if(parent[i] == '/') break; } /* If there are no slashes, then the name is ** in the current directory, so its parent ** is ".". Otherwise, the parent is the name ** up to the last slash. */ if(i == 0) { strcpy(parent, "."); } else { /* null-terminate name at last slash */ parent[i] = '\0'; } /* Unlink the ".." entry */ strcpy(dotdot, new); strcat(dotdot, "/.."); unlink(dotdot); /* Now link it to its parent */ link(parent, dotdot); } utime (new, &st.st_atime); unlink(old); } cant(name) char *name; { std_err("mv: can't move "); std_err (name); std_err ("\n"); exit (1); } /* od - octal dump Author: Andy Tanenbaum */ #include "stdio.h" int bflag, cflag, dflag, oflag, xflag, hflag, linenr, width, state, ever; int prevwds[8]; long off; char buf[512], buffer[BUFSIZ]; int next; int bytespresent; char hexit(); main(argc, argv) int argc; char *argv[]; { int k, flags; long offset(); char *p; /* Process flags */ setbuf(stdout, buffer); flags = 0; p = argv[1]; if (argc > 1 && *p == '-') { /* Flags present. */ flags++; p++; while (*p) { switch(*p) { case 'b': bflag++; break; case 'c': cflag++; break; case 'd': dflag++; break; case 'h': hflag++; break; case 'o': oflag++; break; case 'x': xflag++; break; default: usage(); } p++; } } else { oflag = 1; } if ( (bflag | cflag | dflag | oflag | xflag) == 0) oflag = 1; k = (flags ? 2 : 1); if (bflag | cflag ) { width = 8; } else if (oflag) { width = 7; } else if (dflag) { width = 6; } else { width = 5; } /* Process file name, if any. */ p = argv[k]; if (k < argc && *p != '+') { /* Explicit file name given. */ close(0); if (open(argv[k], 0) != 0) { std_err("od: cannot open "); std_err(argv[k]); std_err("\n"); fflush(stdout); exit(1); } k++; } /* Process offset, if any. */ if (k < argc) { /* Offset present. */ off = offset(argc, argv, k); off = (off/16L) * 16L; lseek(0, off, 0); } dumpfile(); addrout(off); printf("\n"); fflush(stdout); exit(0); } long offset(argc, argv, k) int argc; char *argv[]; int k; { int dot, radix; char str[80], *p, c; long val; /* See if the offset is decimal. */ dot = 0; p = argv[k]; while (*p) if (*p++ == '.') dot = 1; /* Convert offset to binary. */ radix = (dot ? 10 : 8); val = 0; p = argv[k]; if (*p == '+') p++; while (*p != 0 && *p != '.') { c = *p++; if (c < '0' || c > '9') { printf("Bad character in offset: %c\n", c); fflush(stdout); exit(1); } val = radix * val + c - '0'; } p = argv[k+1]; if (k + 1 == argc - 1 && *p == 'b') val = 512L * val; return(val); } dumpfile() { int k; int *words; while ( (k = getwords(&words))) {/* 'k' is # bytes read */ if (k == 16 && same(words, prevwds) && ever==1) { if (state == 0) { printf("*\n"); state = 1; off += 16; continue; } else if (state == 1) { off += 16; continue; } } addrout(off); off += k; state = 0; ever = 1; linenr = 1; if (oflag) wdump(words, k, 8); if (dflag) wdump(words, k, 10); if (xflag) wdump(words, k, 16); if (cflag) bdump(words, k, 'c'); if (bflag) bdump(words, k, 'b'); for (k = 0; k < 8; k++) prevwds[k] = words[k]; for (k = 0; k < 8; k++) words[k] = 0; } } wdump(words, k, radix) int words[8], k, radix; { int i; if (linenr++ != 1) printf(" "); for (i = 0; i < (k+1)/2; i++) outword(words[i], radix); printf("\n"); } bdump(bytes, k, c) char bytes[16]; int k; char c; { int i; if (linenr++ != 1) printf(" "); for (i = 0; i < k; i++) byte(bytes[i] & 0377, c); printf("\n"); } byte(val, c) int val; char c; { if (c == 'b') { printf(" "); outnum(val, 7); return; } if (val == 0) printf(" \\0"); else if (val == '\b') printf(" \\b"); else if (val == '\f') printf(" \\f"); else if (val == '\n') printf(" \\n"); else if (val == '\r') printf(" \\r"); else if (val == '\t') printf(" \\t"); else if (val >= ' ' && val < 0177) printf(" %c",val); else {printf(" "); outnum(val, 7);} } int getwords(words) int **words; { int count; if (next >= bytespresent) { bytespresent = read(0, buf, 512); next = 0; } if (next >= bytespresent) return(0); *words = (int *) &buf[next]; if (next + 16 <= bytespresent) count = 16; else count = bytespresent - next; next += count; return(count); } int same(w1, w2) int *w1, *w2; { int i; i = 8; while (i--) if (*w1++ != *w2++) return(0); return(1); } outword(val, radix) int val, radix; { /* Output 'val' in 'radix' in a field of total size 'width'. */ int i; if (radix == 16) i = width - 4; if (radix == 10) i = width - 5; if (radix == 8) i = width - 6; if (i == 1) printf(" "); else if (i == 2) printf(" "); else if (i == 3) printf(" "); else if (i == 4) printf(" "); outnum(val, radix); } outnum(num, radix) int num, radix; { /* Output a number with all leading 0s present. Octal is 6 places, * decimal is 5 places, hex is 4 places. */ int d, i; unsigned val; char s[8]; val = (unsigned) num; if (radix == 8) d = 6; else if (radix == 10) d = 5; else if (radix == 16) d = 4; else if (radix == 7) {d = 3; radix = 8;} for (i = 0; i < d; i++) { s[i] = val % radix; val -= s[i]; val = val/radix; } for (i = d - 1 ; i >= 0; i--) { if (s[i] > 9) printf("%c",'a'+s[i]-10); else printf("%c",s[i]+'0'); } } addrout(l) long l; { int i; if (hflag == 0) { for (i = 0; i < 7; i++) printf("%c", ((l>>(18-3*i)) & 07) + '0'); } else { for (i = 0; i < 7; i++) printf("%c", hexit( ((l>>(24-4*i)) & 0x0F)) ); } } char hexit(k) int k; { if (k <= 9) return('0' + k); else return('A' + k - 10); } usage() { std_err("Usage: od [-bcdhox] [file] [ [+] offset [.] [b] ]"); } /* passwd - change a passwd Author: Adri Koppes */ #include "signal.h" #include "pwd.h" char pwd_file[] = "/etc/passwd"; char pw_tmp[] = "/etc/pwtemp"; char bad[] = "Permission denied\n"; char buf[512]; main (argc, argv) int argc; char *argv[]; { int uid, cn, n; int fpin, fpout; long salt; struct passwd *pwd, *getpwnam (), *getpwuid (), *getpwent (); char name[9], password[14], sl[2]; char *getpass (), *crypt (); uid = getuid (); if (!access (pw_tmp, 0)) { std_err("Temporary file in use.\nTry again later\n"); exit (1); } if (argc < 2) { pwd = getpwuid (uid); strcpy (name, pwd->pw_name); } else { strcpy (name, argv[1]); pwd = getpwnam (name); } if (!pwd || ((uid != pwd->pw_uid) && uid)) { std_err(bad); exit (1); } signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); prints("Changing password for %s\n",name); if (pwd->pw_passwd[0] && uid) if (strcmp (pwd->pw_passwd, crypt (getpass ("Old password: "), pwd->pw_passwd))) { std_err(bad); exit (1); } strcpy (password, getpass ("New password: ")); if (password[0] == '\0') { std_err("password cannot be null\n"); exit(1); } if (strcmp (password, getpass ("Retype password: "))) { std_err("Passwords don't match\n"); exit (1); } time (&salt); sl[0] = (salt & 077) + '.'; sl[1] = ((salt >> 6) & 077) + '.'; for (cn = 0; cn < 2; cn++) { if (sl[cn] > '9') sl[cn] += 7; if (sl[cn] > 'Z') sl[cn] += 6; } if (password[0]) strcpy (password, crypt (password, sl)); umask (0); close(1); fpout = creat(pw_tmp,0600); if (fpout != 1) { std_err("Can't create temporary file\n"); exit (1); } setpwent (); while ((pwd = getpwent ()) != 0) { if (!strcmp (name, pwd->pw_name)) pwd->pw_passwd = password; prints("%s:%s:%s:",pwd->pw_name,pwd->pw_passwd,itoa(pwd->pw_uid)); prints("%s:%s:%s:%s\n", itoa(pwd->pw_gid),pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell ); } endpwent (); close(0); if ((fpin = open (pw_tmp, 0)) != 0) { std_err("Can't reopen temporary file\n"); exit (1); } close (fpout); if ((fpout = open(pwd_file, 2)) < 0) { std_err("Can't recreate password file\n"); unlink (pw_tmp); exit (1); } while (1) { n = read(fpin, buf, 512); if (n <= 0) break; write(1, buf, n); } fclose (fpin); fclose (fpout); unlink (pw_tmp); } /* * Pr - print files * * Author: Michiel Huisjes. * * Usage: pr [+page] [-columns] [-h header] [-w with] [-l length] [-nt] [files] * -t : Do not print the 5 line header and trailer at the page. * -n : Turn on line numbering. * +page : Start printing at page n. * -columns : Print files in n-colums. * -l length: Take the length of the page to be n instead of 66 * -h header: Take next argument as page header. * -w with : Take the width of the page to be n instead of default 72 */ #include "stdio.h" char *colbuf; #define DEF_LENGTH 66 #define DEF_WIDTH 72 typedef char BOOL; #define FALSE 0 #define TRUE 1 #define NIL_PTR ((char *) 0) char *header; BOOL no_header; BOOL number; short columns; short cwidth; short start_page = 1; short width = DEF_WIDTH; short length = DEF_LENGTH; char output[1024]; FILE *fopen(); main(argc, argv) int argc; char *argv[]; { FILE *file; char *ptr; int index = 1; while (argc > index) { ptr = argv[index++]; if (*ptr == '+') { start_page = atoi(++ptr); continue; } if (*ptr != '-') { index--; break; } if (*++ptr >= '0' && *ptr <= '9') { columns = atoi(ptr); continue; } while (*ptr) switch (*ptr++) { case 't': no_header = TRUE; break; case 'n': number = TRUE; break; case 'h': header = argv[index++]; break; case 'w': width = atoi(ptr); *ptr = '\0'; break; case 'l': length = atoi(ptr); *ptr = '\0'; break; default: fprintf(stderr, "Usage: %s [+page] [-columns] [-h header] [-w] [-l] [-nt] [files]\n", argv[0]); exit(1); } } if (!no_header) length -= 10; if (length <= 0) length = DEF_LENGTH; if (columns) { cwidth = width / columns + 1; if (columns > width) { fprintf(stderr, "Too many columns for pagewidth.\n"); exit(1); } if ((colbuf = (char *) sbrk(cwidth * columns * length)) < 0) { fprintf(stderr, "No memory available for a page of %d x %d. Use chmem to allocate more.\n", length, cwidth); exit(1); } } setbuf(stdout, output); if (argc == index) { header = ""; print(stdin); } while (index != argc) { if ((file = fopen(argv[index], "r")) == (FILE *) 0) { fprintf(stderr, "Cannot open %s\n", argv[index++]); continue; } header = argv[index]; if (columns) format(file); else print(file); fclose(file); index++; } if (columns) { if (brk(colbuf) < 0) { fprintf(stderr, "Can't reset memory!\n"); exit(1); } } (void) fflush(stdout); exit(0); } char skip_page(lines, filep) int lines; FILE *filep; { short c; do { while ((c = getc(filep)) != '\n' && c != EOF); lines--; } while (lines && c != EOF); return c; } format(filep) FILE *filep; { short c = '\0'; short index, lines, i; short page_number = 0; short maxcol = columns; do { /* Check printing of page */ page_number++; if (page_number < start_page && c != EOF) { c = skip_page(columns * length, filep); continue; } if (c == EOF) return; lines = columns * length; index = 0; do { for (i = 0; i < cwidth - 1; i++) { if ((c = getc(filep)) == '\n' || c == EOF) break; colbuf[index++] = c; } /* First char is EOF */ if (i == 0 && lines == columns * length && c == EOF) return; while (c != '\n' && c != EOF) c = getc(filep); colbuf[index++] = '\0'; while (++i < cwidth) index++; lines--; if (c == EOF) { maxcol = columns - lines / length; while (lines--) for (i = 0; i < cwidth; i++) colbuf[index++] = '\0'; } } while (c != EOF && lines); print_page(colbuf, page_number, maxcol); } while (c != EOF); } print_page(buf, pagenr, maxcol) char buf[]; short pagenr, maxcol; { short linenr = (pagenr - 1) * length + 1; short pad, i, j, start; if (!no_header) out_header(pagenr); for (i = 0; i < length; i++) { if (number) printf("%d\t", linenr++); for (j = 0; j < maxcol; j++) { start = (i + j * length) * cwidth; for (pad = 0; pad < cwidth - 1 && buf[start + pad]; pad++) putchar (buf[start + pad]); if (j < maxcol - 1) /* Do not pad last column */ while (pad++ < cwidth - 1) putchar (' '); } putchar('\n'); } if (!no_header) printf("\n\n\n\n\n"); } print(filep) FILE *filep; { short c = '\0'; short page_number = 0; short linenr = 1; short lines; do { /* Check printing of page */ page_number++; if (page_number < start_page && c != EOF) { c = skip_page(length, filep); continue; } if (c == EOF) return; if (page_number == start_page) c = getc(filep); /* Print the page */ lines = length; if (!no_header) out_header(page_number); while (lines && c != EOF) { if (number) printf("%d\t", linenr++); while (c != '\n' && c != EOF) { putchar(c); c = getc(filep); } putchar('\n'); lines--; c = getc(filep); } if (lines == length) return; if (!no_header) printf("\n\n\n\n\n"); /* End of file */ } while (c != EOF); /* Fill last page */ if (page_number >= start_page) { while (lines--) putchar('\n'); } } out_header(page) short page; { extern long time(); long t; (void) time (&t); print_time (t); printf(" %s Page %d\n\n\n", header, page); } #define MINUTE 60L #define HOUR (60L * MINUTE) #define DAY (24L * HOUR) #define YEAR (365L * DAY) #define LYEAR (366L * DAY) int mo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *moname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Print the date. This only works from 1970 to 2099. */ print_time(t) long t; { int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if (t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = (int) (t / DAY); t -= (long) day * DAY; hour = (int) (t / HOUR); t -= (long) hour * HOUR; minute = (int) (t / MINUTE); /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ printf("\n\n%s %d %0d:%0d %d", moname[month], day + 1, hour + 1, minute, year); } /* pwd - print working directory Author: Adri Koppes */ #include "stat.h" struct direct { unsigned short d_ino; char d_name[14]; } main() { register int fd; register *n; char name[128]; char *last_index(); struct stat s, st; struct direct d; *name = 0; stat(".", &s); do { if ((fd = open("..",0)) < 0) { prints("Can't open ..\n"); exit(1); } st.st_dev = s.st_dev; st.st_ino = s.st_ino; st.st_mode = s.st_mode; st.st_nlink = s.st_nlink; st.st_uid = s.st_uid; st.st_gid = s.st_gid; st.st_rdev = s.st_rdev; st.st_size = s.st_size; st.st_atime = s.st_atime; st.st_mtime = s.st_mtime; st.st_ctime = s.st_ctime; stat("..", &s); chdir(".."); if (s.st_dev == st.st_dev) do if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) { prints("Can't read ..\n"); exit(1); } while(d.d_ino != st.st_ino); else do { if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) { prints("Can't read ..\n"); exit(1); } stat(d.d_name, &s); } while ((s.st_dev != st.st_dev) || (s.st_ino != st.st_ino)); close(fd); if (strcmp(".",d.d_name)) { strcat(name,"/"); strcat(name,d.d_name); } } while ((s.st_ino != st.st_ino) || (s.st_dev != st.st_dev)); if (!*name) prints("/"); else while (n = last_index(name, '/')) { prints(n); *n = 0; } prints(name); prints("\n"); exit(0); } char * last_index (string, ch) register char *string; register char ch; { register char *retval = 0; for (; *string; *string++) if (*string == ch) retval = string; return (retval); } /* rev - reverse an ASCII line Authors: Paul Polderman & Michiel Huisjes */ #include "blocksize.h" #ifndef NULL #define NULL 0 #endif #ifndef EOF #define EOF ((char) -1) #endif int fd; /* File descriptor from file currently being read */ main(argc, argv) int argc; char *argv[]; { register unsigned short i; if (argc == 1) { /* If no arguments given, take stdin as input */ fd = 0; rev(); exit(0); } for (i = 1; i < argc; i++) { /* Reverse each line in arguments */ if ((fd = open(argv[i], 0)) < 0) { std_err("Cannot open "); std_err(argv[i]); std_err("\n"); continue; } rev(); close(fd); } exit(0); } rev() { char output[BLOCK_SIZE]; /* Contains a reversed line */ register unsigned short i; /* Index in output array */ do { i = BLOCK_SIZE - 1; while ((output[i] = nextchar()) != '\n' && output[i] != EOF) i--; write(1, &output[i + 1], BLOCK_SIZE - 1 - i); /* Write reversed line*/ if (output[i] == '\n') /* and write a '\n' */ write(1, "\n", 1); } while (output[i] != EOF); } char buf[BLOCK_SIZE]; nextchar() /* Does a sort of buffered I/O */ { static int n = 0; /* Read count */ static int i; /* Index in input buffer to next character */ if (--n <= 0) { /* We've had this block. Read in next block */ n = read(fd, buf, BLOCK_SIZE); i = 0; /* Reset index in array */ } return((n <= 0) ? EOF : buf[i++]); /* Return -1 on EOF */ } /* rm - remove files Author: Adri Koppes */ #include "stat.h" struct direct { unsigned short d_ino; char d_name[14]; }; int errors = 0; int fflag = 0; int iflag = 0; int rflag = 0; int exstatus; main (argc, argv) int argc; char *argv[]; { char *opt; if (argc < 2) usage (); *++argv; --argc; while (**argv == '-') { opt = *argv; while (*++opt != '\0') switch (*opt) { case 'f': fflag++; break; case 'i': iflag++; break; case 'r': rflag++; break; default: std_err("rm: unknown option\n"); usage (); break; } argc--; *++argv; } if (argc < 1) usage (); while (argc--) remove (*argv++); exstatus = (errors == 0 ? 0 : 1); if (fflag) exstatus = 0; exit(exstatus); } usage () { std_err ("Usage: rm [-fir] file\n"); exit (1); } remove (name) char *name; { struct stat s; struct direct d; char rname[128], *strcpy (), *strcat (); int fd; if (stat (name, &s)) { if (!fflag) stderr3 ("rm: ", name, " non-existent\n"); errors++; return; } if (iflag) { stderr3 ("rm: remove ", name, "? "); if (!confirm ()) return; } if ((s.st_mode & S_IFMT) == S_IFDIR) { if (rflag) { if ((fd = open (name, 0)) < 0) { if (!fflag) stderr3 ("rm: can't open ", name, "\n"); errors++; return; } while (read (fd, (char *) & d, sizeof (struct direct)) > 0) { if (d.d_ino && strcmp ("..", d.d_name) && strcmp (".", d.d_name)) { strcpy (rname, name); strcat (rname, "/"); strcat (rname, d.d_name); remove (rname); } } close(fd); rem_dir (name); } else { if (!fflag) stderr3 ("rm: ", name, " is a directory\n"); errors++; return; } } else { if (access (name, 2) && !fflag) { stderr3 ("rm: remove ", name, " (mode = "); octal(s.st_mode & 0777); std_err(") ? "); if (!confirm ()) return; } if (unlink (name)) { if (!fflag) stderr3 ("rm: ", name, " not removed\n"); errors++; } } } rem_dir (name) char *name; { int status; switch (fork ()) { case -1: std_err ("rm: can't fork\n"); errors++; return; case 0: execl ("/bin/rmdir", "rmdir", name, (char*) 0); execl ("/usr/bin/rmdir", "rmdir", name, (char*) 0); std_err ("rm: can't exec rmdir\n"); exit (1); default: wait (&status); errors += status; } } confirm () { char c, t; read (0, &c, 1); t = c; do read (0, &t, 1); while (t != '\n' && t != -1); return (c == 'y' || c == 'Y'); } octal(num) unsigned int num; { char a[4]; a[0] = (((num>>6) & 7) + '0'); a[1] = (((num>>3) & 7) + '0'); a[2] = ((num & 7) + '0'); a[3] = 0; std_err(a); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); } /* rmdir - remove a directory Author: Adri Koppes * (modified by Paul Polderman) */ #include "../include/signal.h" #include "../include/stat.h" struct direct { unsigned short d_ino; char d_name[14]; }; int error = 0; main (argc, argv) register int argc; register char **argv; { if (argc < 2) { prints ("Usage: rmdir dir ...\n"); exit (1); } signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); while (--argc) remove (*++argv); if (error) exit (1); } extern char *rindex(); remove (dirname) char *dirname; { struct direct d; struct stat s, cwd; register int fd = 0, sl = 0; char dots[128]; register char *p; if (stat (dirname, &s)) { stderr2(dirname, " doesn't exist\n"); error++; return; } if ((s.st_mode & S_IFMT) != S_IFDIR) { stderr2(dirname, " not a directory\n"); error++; return; } if (p = rindex(dirname, '/')) p++; else p = dirname; if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) { stderr2(dirname, " will not remove \".\" or \"..\"\n"); error++; return; } strcpy (dots, dirname); while (dirname[fd]) if (dirname[fd++] == '/') sl = fd; dots[sl] = '\0'; if (access (dots, 2)) { stderr2(dirname, " no permission\n"); error++; return; } stat ("", &cwd); if ((s.st_ino == cwd.st_ino) && (s.st_dev == cwd.st_dev)) { std_err ("rmdir: can't remove current directory\n"); error++; return; } if ((fd = open (dirname, 0)) < 0) { stderr2("can't read ", dirname); std_err("\n"); error++; return; } while (read (fd, (char *) & d, sizeof (struct direct)) == sizeof (struct direct)) if (d.d_ino != 0) if (strcmp (d.d_name, ".") && strcmp (d.d_name, "..")) { stderr2(dirname, " not empty\n"); close(fd); error++; return; } close (fd); strcpy (dots, dirname); strcat (dots, "/.."); patch_path(dots); for (p = dots; *p; p++) /* find end of dots */ ; unlink(dots); /* dirname/.. */ *(p - 1) = '\0'; unlink(dots); /* dirname/. */ *(p - 3) = '\0'; if (unlink(dots)) { /* dirname */ stderr2("can't remove ", dots); std_err("\n"); error++; return; } } stderr2(s1, s2) char *s1, *s2; { std_err("rmdir: "); std_err(s1); std_err(s2); } patch_path(dir) char *dir; /* pathname ending with "/.." */ { register char *p, *s; struct stat pst, st; if (stat(dir, &pst) < 0) return; p = dir; while (*p == '/') p++; while (1) { s = p; /* remember start of new pathname part */ while (*p && *p != '/') p++; /* find next slash */ if (*p == '\0') return; /* if end of pathname, return */ /* check if this part of pathname == the original pathname */ *p = '\0'; stat(dir, &st); if (st.st_ino == pst.st_ino && st.st_dev == pst.st_dev && strcmp(s, "..") == 0) return; /* if not, try next part */ *p++ = '/'; while (*p == '/') p++; } } /* roff - text justifier Author: George L. Sicherman */ /* * roff - C version. * the Colonel. 19 May 1983. * * Copyright 1983 by G. L. Sicherman. * You may use and alter this software freely for noncommercial ends * so long as you leave this message alone. * * Fix by Tim Maroney, 31 Dec 1984. * .hc implemented, 8 Feb 1985. * Fix to hyphenating with underlining, 12 Feb 1985. * Fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985. * Fix to centering valve with long input lines, 4 May 1987. */ #include "sgtty.h" #include "signal.h" #include "stdio.h" #include "stat.h" #define SUFTAB "/usr/lib/suftab" #define TXTLEN (o_pl-o_m1-o_m2-o_m3-o_m4-2) #define IDTLEN (o_ti>=0?o_ti:o_in) #define MAXMAC 64 #define MAXDEPTH 10 #define MAXLENGTH 255 #define UNDERL '\200' char cumbuf[BUFSIZ]; char spacechars[] = " \t\n"; int sflag, hflag, startpage, stoppage; char holdword[MAXLENGTH], *holdp; char assyline[MAXLENGTH]; int assylen; char ehead[100], efoot[100], ohead[100], ofoot[100]; struct macrotype { char mname[3]; long int moff; } macro[MAXMAC]; int n_macros; int depth; int adjtoggle; int isrequest = 0; char o_tr[40][2]; /* OUTPUT TRANSLATION TABLE */ int o_cc = '.'; /* CONTROL CHARACTER */ int o_hc = -1; /* HYPHENATION CHARACTER */ int o_tc = ' '; /* TABULATION CHARACTER */ int o_in = 0; /* INDENT SIZE */ int o_ix = -1; /* NEXT INDENT SIZE */ int o_ta[20] = { 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121, 129, 137, 145, 153, 161}; int n_ta = 20; /* #TAB STOPS */ int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1; int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0; int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0; int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1; int o_ni = 1; /* LINE-NUMBER INDENT */ int o_nn = 0; /* #LINES TO SUPPRESS NUMBERING */ int o_ti = -1; /* TEMPORARY INDENT */ int page_no = -1; int line_no = 9999; int n_outwords; FILE *File, *Macread, *Macwrite; FILE *Save; long int teller[MAXDEPTH], ftell(); char *strcat(), *strcpy(), *strend(), *strhas(); char *sprintf(); char *request[] = { "ad","ar","bl","bp","br","cc","ce","de", "ds","ef","eh","fi","fo","hc","he","hx","hy","ig", "in","ix","li","ll","ls","m1","m2","m3","m4", "n1","n2","na","ne","nf","ni","nn","nx","of","oh", "pa","pl","po","ro","sk","sp","ss","ta","tc","ti", "tr","ul",0}; char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX"; int c; /* LAST CHAR READ */ struct sgttyb tty; FILE *fopen(); main(argc,argv) int argc; char **argv; { if (!isatty(1)) setbuf(stdout, cumbuf); while (--argc) switch (**++argv) { case '+': startpage=atoi(++*argv); break; case '-': ++*argv; if (isdigit(**argv)) stoppage=atoi(*argv); else switch(**argv) { case 's': sflag++; break; case 'h': hflag++; break; default: bomb(); } break; default: argc++; goto endargs; } endargs: if (sflag) ioctl(0, TIOCGETP, &tty); mesg(0); /* BLOCK OUT MESSAGES */ assylen=0; assyline[0]='\0'; if (!argc) { File=stdin; readfile(); } else while (--argc) { File=fopen(*argv,"r"); if (NULL==File) { fprintf(stderr,"roff: cannot read %s\n",*argv); done(1); } readfile(); fclose(File); argv++; } writebreak(); endpage(); for (; o_sk; o_sk--) blankpage(); mesg(1); /* ALLOW MESSAGES */ done(0); } mesg(f) int f; { static int mode; struct stat cbuf; /* This routine is not needed. char *ttyname(); if (!isatty(1)) return; if (!f) { fstat(1,&cbuf); mode = cbuf.st_mode; chmod(ttyname(1),mode & ~022); } else chmod(ttyname(1),mode); * ------- end of mesg */ } readfile() { while (readline()) { if (isrequest) continue; if (o_ce || !o_fi) { if (assylen) writeline(0,1); else blankline(); if (o_ce) o_ce--; } } } readline() { int startline, doingword; isrequest = 0; startline = 1; doingword = 0; c=suck(); if (c == '\n') { o_sp = 1; writebreak(); goto out; } else if (isspace(c)) writebreak(); for (;;) { if (c==EOF) { if (doingword) bumpword(); break; } if (c!=o_cc && o_ig) { while (c!='\n' && c!=EOF) c=suck(); break; } if (isspace(c) && !doingword) { startline=0; switch (c) { case ' ': assyline[assylen++]=' '; break; case '\t': tabulate(); break; case '\n': goto out; } c = suck(); continue; } if (isspace(c) && doingword) { bumpword(); if (c=='\t') tabulate(); else if (assylen) assyline[assylen++]=' '; doingword=0; if (c=='\n') break; } if (!isspace(c)) { if (doingword) *holdp++ = o_ul? c|UNDERL: c; else if (startline && c==o_cc && !o_li) { isrequest=1; return readreq(); } else { doingword=1; holdp=holdword; *holdp++ = o_ul? c|UNDERL: c; } } startline=0; c = suck(); } out: if (o_ul) o_ul--; if (o_li) o_li--; return c!=EOF; } /* * bumpword - add word to current line. */ bumpword() { char *hc; *holdp = '\0'; /* * Tutelman's fix #1, modified by the Colonel. */ if (!o_fi || o_ce) goto giveup; /* * We use a while-loop in case of ridiculously long words with * multiple hyphenation indicators. */ if (assylen + reallen(holdword) > o_ll - IDTLEN) { if (!o_hy) writeline(o_ad,0); else while (assylen + reallen(holdword) > o_ll - IDTLEN) { /* * Try hyphenating it. */ if (o_hc && strhas(holdword,o_hc)) { /* * There are hyphenation marks. Use them! */ for (hc=strend(holdword); hc>=holdword; hc--) { if ((*hc&~UNDERL)!=o_hc) continue; *hc = '\0'; if (assylen + reallen(holdword) + 1 > o_ll - IDTLEN) { *hc = o_hc; continue; } /* * Yay - it fits! */ dehyph(holdword); strcpy(&assyline[assylen],holdword); strcat(assyline,"-"); assylen += strlen(holdword) + 1; strcpy(holdword,++hc); break; /* STOP LOOKING */ } /* for */ /* * It won't fit, or we've succeeded in breaking the word. */ writeline(o_ad,0); if (hcassylen+IDTLEN) { for (; assylen+IDTLEN0) o_bp=page_no+r; else if (s<0) o_bp=page_no-r; else o_bp=r; writebreak(); if (line_no) { endpage(); beginpage(); } break; case 4: /* br */ writebreak(); break; case 5: /* cc */ c=cread(&o_cc); break; case 6: /* ce */ /* * Fix to centering. Set counter _after_ breaking! --G.L.S. */ nread(&r); writebreak(); o_ce = r; break; case 7: /* de */ defmac(); break; case 8¾ĄĮĀĆÄÅĘĒČÉŹĖ: /* ds */ o_ls=2; writebreak(); break; case 9: /* ef */ c=tread(efoot); break; case 10: /* eh */ c=tread(ehead); break; case 11: /* fi */ o_fi=1; writebreak(); break; case 12: /* fo */ c=tread(efoot); strcpy(ofoot,efoot); break; case 13: /* hc */ c=cread(&o_hc); break; case 14: /* he */ c=tread(ehead); strcpy(ohead,ehead); break; case 15: /* hx */ o_hx=1; break; case 16: /* hy */ nread(&o_hy); break; case 17: /* ig */ o_ig=1; break; case 18: /* in */ writebreak(); snset(&o_in); o_ix = -1; break; case 19: /* ix */ snset(&o_ix); if (!n_outwords) o_in=o_ix; break; case 20: /* li */ nread(&o_li); break; case 21: /* ll */ snset(&o_ll); break; case 22: /* ls */ snset(&o_ls); break; case 23: /* m1 */ nread(&o_m1); break; case 24: /* m2 */ nread(&o_m2); break; case 25: /* m3 */ nread(&o_m3); break; case 26: /* m4 */ nread(&o_m4); break; case 27: /* n1 */ o_n1=1; break; case 28: /* n2 */ nread(&o_n2); break; case 29: /* na */ o_ad=0; writebreak(); break; case 30: /* ne */ nread(&r); if (line_no+(r-1)*o_ls+1 > TXTLEN) { writebreak(); endpage(); beginpage(); } break; case 31: /* nf */ o_fi=0; writebreak(); break; case 32: /* ni */ snset(&o_ni); break; case 33: /* nn */ snset(&o_nn); break; case 34: /* nx */ do_nx(); c='\n'; /* SO WE DON'T FLUSH THE FIRST LINE */ break; case 35: /* of */ c=tread(ofoot); break; case 36: /* oh */ c=tread(ohead); break; case 38: /* pl */ snset(&o_pl); break; case 39: /* po */ snset(&o_po); break; case 40: /* ro */ o_ro=1; break; case 41: /* sk */ nread(&o_sk); break; case 42: /* sp */ nread(&o_sp); writebreak(); break; case 43: /* ss */ writebreak(); o_ls=1; break; case 44: /* ta */ do_ta(); break; case 45: /* tc */ c=cread(&o_tc); break; case 46: /* ti */ writebreak(); c=snread(&r,&s,0); if (s>0) o_ti=o_in+r; else if (s<0) o_ti=o_in-r; else o_ti=r; break; case 47: /* tr */ do_tr(); break; case 48: /* ul */ nread(&o_ul); break; } reqflsh: while (c!=EOF && c!='\n') c=suck(); return c!=EOF; } snset(par) int *par; { int r, s; c=snread(&r,&s,0); if (s>0) *par+=r; else if (s<0) *par-=r; else *par=r; } tread(s) char *s; { int leadbl; leadbl=0; for (;;) { c=suck(); if (c==' ' && !leadbl) continue; if (c==EOF || c=='\n') { *s = '\0'; return c; } *s++ = c; leadbl++; } } nread(i) int *i; { int f; f=0; *i=0; if (!skipsp()) for (;;) { c=suck(); if (c==EOF) break; if (isspace(c)) break; if (isdigit(c)) { f++; *i = *i*10 + c - '0'; } else break; } if (!f) *i=1; } int snread(i,s,sdef) int *i, *s, sdef; { int f; f = *i = *s = 0; for (;;) { c=suck(); if (c==EOF || c=='\n') break; if (isspace(c)) { if (f) break; else continue; } if (isdigit(c)) { f++; *i = *i*10 + c - '0'; } else if ((c=='+' || c=='-') && !f) { f++; *s = c=='+' ? 1 : -1; } else break; } while (c!=EOF && c!='\n') c=suck(); if (!f) { *i=1; *s=sdef; } return c; } int cread(k) int *k; { int u; *k = -1; for (;;) { u=suck(); if (u==EOF || u=='\n') return u; if (isspace(u)) continue; if (*k < 0) *k=u; } } defmac() { int i; char newmac[3], *nm; if (skipsp()) return; nm=newmac; if (!Macwrite) openmac(); *nm++ = suck(); c=suck(); if (c!=EOF && c!='\n' && c!=' ' && c!='\t') *nm++ = c; *nm = '\0'; /* KILL OLD DEFINITION IF ANY */ for (i=0; i q) { endpage(); beginpage(); } for (; o_bl; o_bl--) blankline(); } else if (o_sp) { if (o_sp + line_no > q) newpage(); else if (line_no) for (; o_sp; o_sp--) blankline(); } } blankline() { if (line_no >= TXTLEN) newpage(); if (o_n2) o_n2++; spit('\n'); line_no++; } writeline(adflag,flushflag) int adflag, flushflag; { int j, q; char lnstring[7]; for (j=assylen-1; j; j--) { if (assyline[j]==' ') assylen--; else break; } q = TXTLEN; if (line_no >= q) newpage(); for (j=0; j=0) o_in=o_ix; o_ix = o_ti = -1; } fillline() { int excess, j, s, inc, spaces; adjtoggle^=1; if (!(excess = o_ll - IDTLEN - assylen)) return; if (excess < 0) { fprintf(stderr,"roff: internal error #2 [%d]\n",excess); done(1); } for (j=2;; j++) { if (adjtoggle) { s=0; inc = 1; } else { s=assylen-1; inc = -1; } spaces=0; while (s>=0 && s0) s++; if (!--excess) return; } spaces=0; } s+=inc; } } } insrt(p) int p; { int i; for (i=assylen; i>p; i--) assyline[i]=assyline[i-1]; assylen++; } newpage() { if (page_no >= 0) endpage(); else page_no=1; for (; o_sk; o_sk--) blankpage(); beginpage(); } beginpage() { int i; if (sflag) waitawhile(); for (i=0; i l) m+=(o_ll-m)/2; else m+=l; n=titlen(++t,d,strlen(pst)); for (j=m; j=400) { strcat(pst,"cd"); i-=400; } while (i>=100) { strcat(pst,"c"); i-=100; } if (i>=90) { strcat(pst,"xc"); i-=90; } if (i>=50) { strcat(pst,"l"); i-=50; } if (i>=40) { strcat(pst,"xl"); i-=40; } while (i>=10) { strcat(pst,"x"); i-=10; } if (i>=9) { strcat(pst,"ix"); i-=9; } if (i>=5) { strcat(pst,"v"); i-=5; } if (i>=4) { strcat(pst,"iv"); i-=4; } while (i--) strcat(pst,"i"); } else sprintf(pst,"%d",page_no); return pst; } int titlen(t,c,k) char *t, c; int k; { int q; q=0; while (*t && *t!=c) q += *t++ == '%' ? k : 1; return q; } spits(s) char *s; { while (*s) spit(*s++); } spit(c) char c; { static int col_no, n_blanks; int ulflag; char *t; ulflag=c&UNDERL; c&=~UNDERL; for (t = (char *)o_tr; *t; t++) if (*t++==c) { /* * fix - last char translates to space. */ c = *t? *t: ' '; break; } if (page_no < startpage || (stoppage && page_no > stoppage)) return; if (c != ' ' && c != '\n' && n_blanks) { if (hflag && n_blanks>1) while (col_no/8 < (col_no+n_blanks)/8) { putc('\t',stdout); n_blanks-= 8 - (col_no & 07); col_no = 8 + col_no & ~07; } for (; n_blanks; n_blanks--) { putc(' ',stdout); col_no++; } } if (ulflag && isalnum(c)) fputs("_\b",stdout); if (c == ' ') n_blanks++; else { putc(c,stdout); col_no++; } if (c == '\n') { col_no=0; n_blanks=0; } } int suck() { for (;;) { c=getc(File); if (islegal(c)) return c; } } /* * strhas - does string have character? Allow UNDERL flag. */ char * strhas(p,c) char *p, c; { for (; *p; p++) if ((*p&~UNDERL)==c) return p; return NULL; } /* * strend - find NULL at end of string. */ char * strend(p) char *p; { while (*p++); return p; } /* * isspace, isalnum, isdigit, islegal - classify a character. * We could just as well use if it didn't vary from * one version of Unix to another. As it is, these routines * must be modified for weird character sets, like EBCDIC and * CDC Scientific. */ int isspace(c) int c; { char *s; for (s=spacechars; *s; s++) if (*s==c) return 1; return 0; } int isalnum(c) int c; { return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || (c>='0'&&c<='9'); } int isdigit(c) int c; { return c>='0' && c<='9'; } int islegal(c) int c; { return c>=' ' && c<='~' || isspace(c) || c=='\n' || c==EOF; } bomb() { fprintf(stderr,"Usage: roff [+00] [-00] [-s] [-h] file ...\n"); done(1); } done(n) int n; { fflush(stdout); _cleanup(); exit(n); } mkdir bin 2>/dev/null for i in *.c do echo Making $i make f=`basename $i .c` done /* shar - make a shell archive Author: Michiel Husijes */ #include "blocksize.h" #define IO_SIZE (10 * BLOCK_SIZE) char input[IO_SIZE]; char output[IO_SIZE]; int index = 0; main(argc, argv) int argc; register char *argv[]; { register int i; int fd; for (i = 1; i < argc; i++) { if ((fd = open(argv[i], 0)) < 0) { write(2, "Cannot open ", 12); write(2, argv[i], strlen(argv[i])); write(2, ".\n", 2); } else { print("echo x - "); print(argv[i]); print("\ngres '^X' '' > "); print(argv[i]); print(" << '/'\n"); cat(fd); } } if (index) write(1, output, index); exit(0); } cat(fd) int fd; { static char *current, *last; register int r = 0; register char *cur_pos = current; putchar('X'); for (; ;) { if (cur_pos == last) { if ((r = read(fd, input, IO_SIZE)) <= 0) break; last = &input[r]; cur_pos = input; } putchar(*cur_pos); if (*cur_pos++ == '\n' && cur_pos != last) putchar('X'); } print("/\n"); (void) close(fd); current = cur_pos; } print(str) register char *str; { while (*str) putchar(*str++); } putchar(c) register char c; { output[index++] = c; if (index == IO_SIZE) { write(1, output, index); index = 0; } } /* size - tell size of an object file Author: Andy Tanenbaum */ #define HLONG 8 /* # longs in the header */ #define TEXT 2 #define DATA 3 #define BSS 4 #define CHMEM 6 #define MAGIC 0x0301 /* magic number for an object file */ #define SEPBIT 0x00200000 /* this bit is set for separate I/D */ int heading; /* set when heading printed */ int error; main(argc, argv) int argc; char *argv[]; { int i; if (argc == 1) { size("a.out"); exit(error); } for (i = 1; i < argc; i++) size(argv[i]); exit(error); } size(name) char *name; { int fd, separate; long head[HLONG], dynam, allmem; if ( (fd = open(name, 0)) < 0) { stderr3("size: can't open ", name, "\n"); return; } if (read(fd, head, sizeof(head)) != sizeof(head) ) { stderr3("size: ", name, ": header too short\n"); error = 1; close(fd); return; } if ( (head[0] & 0xFFFF) != MAGIC) { stderr3("size: ", name, " not an object file\n"); close(fd); return; } separate = (head[0] & SEPBIT ? 1 : 0); dynam = head[CHMEM] - head[TEXT] - head[DATA] - head[BSS]; if (separate) dynam += head[TEXT]; allmem = (separate ? head[CHMEM] + head[TEXT] : head[CHMEM]); if (heading++ == 0) prints(" text\t data\t bss\t stack\tmemory\n"); printf("%6D\t%6D\t%6D\t%6D\t%6D\t%s\n",head[TEXT], head[DATA], head[BSS], dynam, allmem, name); close(fd); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); error = 1; } /* sleep - suspend a process for x sec Author: Andy Tanenbaum */ main(argc, argv) int argc; char *argv[]; { register seconds; register char c; seconds = 0; if (argc != 2) { std_err("Usage: sleep time\n"); exit(1); } while (c = *(argv[1])++) { if (c < '0' || c > '9') { std_err("sleep: bad arg\n"); exit(1); } seconds = 10 * seconds + (c - '0'); } /* Now sleep. */ sleep(seconds); exit(0); } /* sort - sort a file of lines Author: Michiel Huisjes */ /* SYNOPSIS: * sort [-funbirdcmt'x'] [+beg_pos[opts] [-end_pos]] [-o outfile] [file] .. * * [opts] can be any of * -f : Fold upper case to lower. * -n : Sort to numeric value (optional decimal point) implies -b * -b : Skip leading blanks * -i : Ignore chars outside ASCII range (040 - 0176) * -r : Reverse the sense of comparisons. * -d : Sort to dictionary order. Only letters, digits, comma's and points * are compared. * If any of these flags are used in [opts], then they override all global * ordering for this field. * * I/O control flags are: * -u : Print uniq lines only once. * -c : Check if files are sorted in order. * -m : Merge already sorted files. * -o outfile : Name of output file. (Can be one of the input files). * Default is stdout. * - : Take stdin as input. * * Fields: * -t'x' : Field separating character is 'x' * +a.b : Start comparing at field 'a' with offset 'b'. A missing 'b' is * taken to be 0. * -a.b : Stop comparing at field 'a' with offset 'b'. A missing 'b' is * taken to be 0. * A missing -a.b means the rest of the line. */ #include "stat.h" #include "signal.h" #define OPEN_FILES 16 /* Nr of open files per process */ #define MEMORY_SIZE (20 * 1024) /* Total mem_size */ #define LINE_SIZE (1024 >> 1) /* Max length of a line */ #define IO_SIZE (2 * 1024) /* Size of buffered output */ #define STD_OUT 1 /* Fd of terminal */ /* Return status of functions */ #define OK 0 #define ERROR -1 #define NIL_PTR ((char *) 0) /* Compare return values */ #define LOWER -1 #define SAME 0 #define HIGHER 1 /* * Table definitions. */ #define DICT 0x001 /* Alpha, numeric, letters and . */ #define ASCII 0x002 /* All between ' ' and '~' */ #define BLANK 0x004 /* ' ' and '\t' */ #define DIGIT 0x008 /* 0-9 */ #define UPPER 0x010 /* A-Z */ typedef enum { /* Boolean types */ FALSE = 0, TRUE } BOOL; typedef struct { int fd; /* Fd of file */ char *buffer; /* Buffer for reads */ int read_chars; /* Nr of chars actually read in buffer*/ int cnt; /* Nr of chars taken out of buffer */ char *line; /* Contains line currently used */ } MERGE ; #define NIL_MERGE ((MERGE *) 0) MERGE merge_f[OPEN_FILES]; /* Merge structs */ int buf_size; /* Size of core available for each struct */ #define FIELDS_LIMIT 10 /* 1 global + 9 user */ #define GLOBAL 0 typedef struct { int beg_field, beg_pos; /* Begin field + offset */ int end_field, end_pos; /* End field + offset. ERROR == EOLN */ BOOL reverse; /* TRUE if rev. flag set on this field*/ BOOL blanks; BOOL dictionary; BOOL fold_case; BOOL ascii; BOOL numeric; } FIELD; /* Field declarations. A total of FILEDS_LIMIT is allowed */ FIELD fields[FIELDS_LIMIT]; int field_cnt; /* Nr of field actually assigned */ /* Various output control flags */ BOOL check = FALSE; BOOL only_merge = FALSE; BOOL uniq = FALSE; char *mem_top; /* Mem_top points to lowest pos of memory. */ char *cur_pos; /* First free position in mem */ char **line_table; /* Pointer to the internal line table */ BOOL in_core = TRUE; /* Set if input cannot all be sorted in core */ /* Place where temp_files should be made */ char temp_files[] = "/tmp/sort.XXXXX.XX"; char *output_file; /* Name of output file */ int out_fd; /* Fd to output file (could be STD_OUT) */ char out_buffer[IO_SIZE]; /* For buffered output */ char **argptr; /* Pointer to argv structure */ int args_offset; /* Nr of args spilled on options */ int args_limit; /* Nr of args given */ char separator; /* Char that separates fields */ int nr_of_files = 0; /* Nr_of_files to be merged */ int disabled; /* Nr of files done */ char USAGE[] = "Usage: sort [-funbirdcmt'x'] [+beg_pos [-end_pos]] [-o outfile] [file] .."; /* Forward declarations */ char *file_name (), *skip_fields (); MERGE *skip_lines (), *print (); extern char *msbrk (), *mbrk (); /* * Table of all chars. 0 means no special meaning. */ char table[256] = { /* '^@' to space */ 0, 0, 0, 0, 0, 0, 0, 0, 0, BLANK | DICT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* space to '0' */ BLANK | DICT | ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* '0' until '9' */ DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, /* ASCII from ':' to '@' */ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* Upper case letters 'A' to 'Z' */ UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, /* ASCII from '[' to '`' */ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* Lower case letters from 'a' to 'z' */ DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, /* ASCII from '{' to '~' */ ASCII, ASCII, ASCII, ASCII, /* Stuff from -1 to -177 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Get_opts () assigns the options into the field structure as described in ptr. * This field structure could be the GLOBAL one. */ get_opts(ptr, field) register char *ptr; register FIELD *field; { switch (*ptr) { case 'b' : /* Skip leading blanks */ field->blanks = TRUE; break; case 'd' : /* Dictionary order */ field->dictionary = TRUE; break; case 'f' : /* Fold upper case to lower */ field->fold_case = TRUE; break; case 'i' : /* Skip chars outside ' ' '~' */ field->ascii = TRUE; break; case 'n' : /* Sort on numeric */ field->numeric = TRUE; field->blanks = TRUE; break; case 'r' : /* Reverse comparisons */ field->reverse = TRUE; break; default : /* Illegal options */ error(TRUE, USAGE, NIL_PTR); } } /* * Atoi() converts a string to an int. */ atoi(ptr) register char *ptr; { register int num = 0; /* Accumulator */ while (table[*ptr] & DIGIT) num = num * 10 + *ptr++ - '0'; return num; } /* * New_field () assigns a new field as described by the arguments. * A field description is of the form: +a.b[opts] -c.d, where b and d, as well * as -c.d and [opts] are optional. Nr before digit is field nr. Nr after digit * is offset from field. */ new_field(field, offset, beg_fl) register FIELD *field; /* Field to assign */ int *offset; /* Offset in argv structure */ BOOL beg_fl; /* Assign beg or end of field */ { register char *ptr; ptr = argptr[*offset]; *offset += 1; /* Incr offset to next arg */ ptr++; if (beg_fl) field->beg_field = atoi(ptr); /* Assign int of first field */ else field->end_field = atoi(ptr); while (table[*ptr] & DIGIT) /* Skip all digits */ ptr++; if (*ptr == '.') { /* Check for offset */ ptr++; if (beg_fl) field->beg_pos = atoi(ptr); else field->end_pos = atoi(ptr); while (table[*ptr] & DIGIT) /* Skip digits */ ptr++; } if (beg_fl) { while (*ptr != '\0') /* Check options after field */ get_opts(ptr++, field); } if (beg_fl) { /* ChŁŪÜŻŽßąįāćäåęēčéźėģķīļšńeck for end pos */ ptr = argptr[*offset]; if (*ptr == '-' && table[*(ptr + 1)] & DIGIT) { new_field(field, offset, FALSE); if (field->beg_field > field->end_field) error(TRUE, "End field is before start field!",NIL_PTR); } else /* No end pos. */ field->end_field = ERROR; } } catch() { register short i; signal (SIGINT, SIG_IGN); only_merge = FALSE; for (i = 0; i < 26; i++) (void) unlink (file_name (i)); exit (2); } main(argc, argv) int argc; char *argv[]; { int arg_count = 1; /* Offset in argv */ struct stat st; register char *ptr; /* Ptr to *argv in use */ register int fd; int pid, pow; argptr = argv; cur_pos = mem_top = msbrk(MEMORY_SIZE); /* Find lowest mem. location */ while (argc > 1 && ((ptr = argv[arg_count])[0] == '-' || *ptr == '+')) { if (*ptr == '-' && *(ptr + 1) == '\0') /* "-" means stdin */ break; if (*ptr == '+') { /* Assign field. */ if (++field_cnt == FIELDS_LIMIT) error(TRUE, "Too many fields", NIL_PTR); new_field (&fields[field_cnt], &arg_count, TRUE); } else { /* Get output options */ while (*++ptr) { switch (*ptr) { case 'c' : /* Only check file */ check = TRUE; break; case 'm' : /* Merge (sorted) files */ only_merge = TRUE; break; case 'u' : /* Only give uniq lines */ uniq = TRUE; break; case 'o' : /* Name of output file */ output_file = argv[++arg_count]; break; case 't' : /* Field separator */ ptr++; separator = *ptr; break; default : /* Sort options */ get_opts(ptr, &fields[GLOBAL]); } } arg_count++; } } for (fd = 1; fd <= field_cnt; fd++) adjust_options (&fields[fd]); /* Create name of tem_files 'sort.pid.aa' */ ptr = &temp_files[10]; pid = getpid(); pow = 10000; while (pow != 0) { *ptr++ = pid / pow + '0'; pid %= pow; pow /= 10; } signal (SIGINT, catch); /* Only merge files. Set up */ if (only_merge) { args_limit = args_offset = arg_count; while (argv[args_limit] != NIL_PTR) args_limit++; /* Find nr of args */ files_merge(args_limit - arg_count); exit (0); } if (arg_count == argc) { /* No args left. Use stdin */ if (check) check_file(0, NIL_PTR); else get_file(0, 0L); } else while (arg_count < argc) { /* Sort or check args */ if (strcmp(argv[arg_count], "-") == 0) fd = 0; else if (stat(argv[arg_count], &st) < 0) { error(FALSE, "Cannot find ", argv[arg_count++]); continue; } /* Open files */ else if ((fd = open(argv[arg_count], 0)) < 0) { error(FALSE, "Cannot open ", argv[arg_count++]); continue; } if (check) check_file(fd, argv[arg_count]); else /* Get_file reads whole file */ get_file(fd, st.st_size); arg_count++; } if (check) exit(0); sort(); /* Sort whatever is left */ if (nr_of_files == 1) /* Only one file sorted -> don't merge*/ exit(0); files_merge(nr_of_files); exit(0); } /* * Adjust_options() assigns all global variables set also in the fields * assigned. */ adjust_options(field) register FIELD *field; { register FIELD *gfield = &fields[GLOBAL]; if (gfield->reverse) field->reverse = TRUE; if (gfield->blanks) field->blanks = TRUE; if (gfield->dictionary) field->dictionary = TRUE; if (gfield->fold_case) field->fold_case = TRUE; if (gfield->ascii) field->ascii = TRUE; if (gfield->numeric) field->numeric = TRUE; } /* * Error () prints the error message on stderr and exits if quit == TRUE. */ error(quit, message, arg) register BOOL quit; register char *message, *arg; { write(2, message, strlen(message)); if (arg != NIL_PTR) write(2, arg, strlen(arg)); write(2, ".\n", 2); if (quit) exit(1); } /* * Open_outfile () assigns to out_fd the fd where the output must go when all * the sorting is done. */ open_outfile() { if (output_file == NIL_PTR) out_fd = STD_OUT; else if ((out_fd = creat(output_file, 0644)) < 0) error(TRUE, "Cannot creat ", output_file); } /* * Get_file reads the whole file of filedescriptor fd. If the file is too big * to keep in core, a partial sort is done, and the output is stashed somewhere. */ get_file(fd, size) int fd; /* Fd of file to read */ register long size; /* Size of file */ { register int i; long rest; /* Rest in memory */ char save_ch; /* Used in stdin readings */ rest = MEMORY_SIZE - (cur_pos - mem_top); if (fd == 0) { /* We're reding stdin */ while ((i = read(0, cur_pos, rest)) > 0) { if ((cur_pos - mem_top) + i == MEMORY_SIZE) { in_core = FALSE; i = last_line(); /* End of last line */ save_ch = mem_top[i]; mem_top[i] = '\0'; sort (); /* Sort core */ mem_top[i] = save_ch; /* Restore erased char */ /* Restore last (half read) line */ for (size = 0; i + size != MEMORY_SIZE; size++) mem_top[size] = mem_top[i + size]; /* Assign current pos. in memory */ cur_pos = &mem_top[size]; } else { /* Fits, just assign position in mem. */ cur_pos = cur_pos + i; *cur_pos = '\0'; } /* Calculate rest of mem */ rest = MEMORY_SIZE - (cur_pos - mem_top); } } /* Reading file. Check size */ else if (size > rest) { /* Won't fit */ mread(fd, cur_pos, rest); in_core = FALSE; i = last_line(); /* Get pos. of last line */ mem_top[i] = '\0'; /* Truncate */ (void) lseek(fd, i - MEMORY_SIZE, 1); /* Do this next time */ rest = size - rest - i + MEMORY_SIZE;/* Calculate rest */ cur_pos = mem_top; /* Reset mem */ sort(); /* Sort core */ get_file(fd, rest); /* Get rest of file */ } else { /* Fits. Just read in */ mread(fd, cur_pos, size); cur_pos = cur_pos + size; /* Reassign cur_pos */ *cur_pos = '\0'; (void)close (fd); /* File completed */ } } /* * Last_line () find the last line in core and retuns the offset from the top * of the memory. */ last_line() { register int i; for (i = MEMORY_SIZE - 1; i > 0; i--) if (mem_top[i] == '\n') break; return i + 1; } /* * Print_table prints the line table in the given file_descriptor. If the fd * equals ERROR, it opens a temp_file itself. */ print_table(fd) int fd; { register char **line_ptr; /* Ptr in line_table */ register char *ptr; /* Ptr to line */ int index = 0; /* Index in output buffer */ if (fd == ERROR) { if ((fd = creat(file_name (nr_of_files), 0644)) < 0) error(TRUE, "Cannot creat ", file_name (nr_of_files)); } for (line_ptr = line_table; *line_ptr != NIL_PTR; line_ptr++) { ptr = *line_ptr; /* Skip all same lines if uniq is set */ if (uniq && *(line_ptr + 1) != NIL_PTR) { if (compare(ptr, *(line_ptr + 1)) == SAME) continue; } do { /* Print line in a buffered way */ out_buffer[index++] = *ptr; if (index == IO_SIZE) { mwrite(fd, out_buffer, IO_SIZE); index = 0; } } while (*ptr++ != '\n'); } mwrite(fd, out_buffer, index); /* Flush buffer */ (void) close(fd); /* Close file */ nr_of_files++; /* Increment nr_of_files to merge */ } /* * File_name () returns the nr argument from the argument list, or a uniq * filename if the nr is too high, or the arguments were not merge files. */ char *file_name(nr) register int nr; { if (only_merge) { if (args_offset + nr < args_limit) return argptr[args_offset + nr]; } temp_files[16] = nr / 26 + 'a'; temp_files[17] = nr % 26 + 'a'; return temp_files; } /* * Mread () performs a normal read (), but checks the return value. */ mread(fd, address, bytes) int fd; char *address; register int bytes; { if (read(fd, address, bytes) < 0 && bytes != 0) error(TRUE, "Read error", NIL_PTR); } /* * Mwrite () performs a normal write (), but checks the return value. */ mwrite(fd, address, bytes) int fd; char *address; register int bytes; { if (write(fd, address, bytes) != bytes && bytes != 0) error(TRUE, "Write error", NIL_PTR); } /* * Sort () sorts the input in memory starting at mem_top. */ sort() { register char *ptr = mem_top; register int count = 0; /* Count number of lines in memory */ while (*ptr) { if (*ptr++ == '\n') count++; } /* Set up the line table */ line_table = (char **) msbrk(count * sizeof (char *)+sizeof (char *)); count = 1; ptr = line_table[0] = mem_top; while (*ptr) { if (*ptr++ == '\n') line_table[count++] = ptr; } line_table[count - 1] = NIL_PTR; /* Sort the line table */ sort_table(count - 1); /* Stash output somewhere */ if (in_core) { open_outfile(); print_table(out_fd); } else print_table(ERROR); /* Free line table */ mbrk(line_table); } /* * Sort_table () sorts the line table consisting of nel elements. */ sort_table(nel) register int nel; { char *tmp; register int i; /* Make heap */ for (i = (nel >> 1); i >= 1; i--) incr(i, nel); /* Sort from heap */ for (i = nel; i > 1; i--) { tmp = line_table[0]; line_table[0] = line_table[i - 1]; line_table[i - 1] = tmp; incr(1, i - 1); } } /* * Incr () increments the heap. */ incr(si, ei) register int si, ei; { char *tmp; while (si <= (ei >> 1)) { si <<= 1; if (si + 1 <= ei && compare(line_table[si - 1], line_table[si]) <= 0) si++; if (compare(line_table[(si >> 1) - 1],line_table[si - 1]) >= 0) return; tmp = line_table[(si >> 1) - 1]; line_table[(si >> 1) - 1] = line_table[si - 1]; line_table[si - 1] = tmp; } } /* * Cmp_fields builds new lines out of the lines pointed to by el1 and el2 and * puts it into the line1 and line2 arrays. It then calls the cmp () routine * with the field describing the arguments. */ cmp_fields(el1, el2) register char *el1, *el2; { int i, ret; char line1[LINE_SIZE], line2[LINE_SIZE]; for (i = 0; i < field_cnt; i++) { /* Setup line parts */ build_field(line1, &fields[i + 1], el1); build_field(line2, &fields[i + 1], el2); if ((ret = cmp(line1, line2, &fields[i + 1])) != SAME) break; /* If equal, try next field */ } /* Check for reverse flag */ if (i != field_cnt && fields[i + 1].reverse) return -ret; /* Else return the last return value of cmp () */ return ret; } /* * Build_field builds a new line from the src as described by the field. * The result is put in dest. */ build_field(dest, field, src) char *dest; /* Holds result */ register FIELD *field; /* Field description */ register char *src; /* Source line */ { char *begin = src; /* Remember start location */ char *last; /* Pointer to end location */ int i; /* Skip begin fields */ src = skip_fields(src, field->beg_field); /* Skip begin positions */ for (i = 0; i < field->beg_pos && *src != '\n'; i++) src++; /* Copy whatever is left */ copy(dest, src); /* If end field is assigned truncate (perhaps) the part copied */ if (field->end_field != ERROR) { /* Find last field */ last = skip_fields(begin, field->end_field); /* Skip positions as given by end fields description */ for (i = 0; i < field->end_pos && *last != '\n'; i++) last++; dest[last - src] = '\n'; /* Truncate line */ } } /* * Skip_fields () skips nf fields of the line pointed to by str. */ char *skip_fields(str, nf) register char *str; int nf; { while (nf-- > 0) { if (separator == '\0') { /* Means ' ' or '\t' */ while (*str != ' ' && *str != '\t' && *str != '\n') str++; while (table[*str] & BLANK) str++; } else { while (*str != separator && *str != '\n') str++; str++; } } return str; /* Return pointer to indicated field */ } /* * Compare is called by all sorting routines. It checks if fields assignments * has been made. if so, it calls cmp_fields (). If not, it calls cmp () and * reversed the return value if the (global) reverse flag is set. */ compare(el1, el2) register char *el1, *el2; { int ret; if (field_cnt > GLOBAL) return cmp_fields(el1, el2); ret = cmp(el1, el2, &fields[GLOBAL]); return (fields[GLOBAL].reverse) ? -ret : ret; } /* * Cmp () is the actual compare routine. It compares according to the * description given in the field pointer. */ cmp(el1, el2, field) register char *el1, *el2; FIELD *field; { int c1, c2; if (field->blanks) { /* Skip leading blanks */ while (table[*el1] & BLANK) el1++; while (table[*el2] & BLANK) el2++; } if (field->numeric) /* Compare numeric */ return digits(el1, el2, TRUE); for (; ;) { while (*el1 == *el2) { if (*el1++ == '\n') /* EOLN on both strings */ return SAME; el2++; } if (*el1 == '\n') /* EOLN on string one */ return LOWER; if (*el2 == '\n') return HIGHER; if (field->ascii) {/* Skip chars outside 040 - 0177 */ if ((table[*el1] & ASCII) == 0) { do { el1++; } while ((table[*el1] & ASCII) == 0); continue; } if ((table[*el2] & ASCII) == 0) { do { el2++; } while ((table[*el2] & ASCII) == 0); continue; } } if (field->dictionary) {/* Skip non-dict chars */ if ((table[*el1] & DICT) == 0) { do { el1++; } while ((table[*el1] & DICT) == 0); continue; } if ((table[*el2] & DICT) == 0) { do { el2++; } while ((table[*el2] & DICT) == 0); continue; } } if (field->fold_case) { /* Fold upper case to lower */ if (table[c1 = *el1++] & UPPER) c1 += 'a' - 'A'; if (table[c2 = *el2++] & UPPER) c2 += 'a' - 'A'; if (c1 == c2) continue; return c1 - c2; } return *el1 - *el2; } /* NOTREACHED */ } /* * Digits compares () the two strings that point to a number of digits followed * by an optional decimal point. */ digits(str1, str2, check_sign) register char *str1, *str2; BOOL check_sign; /* True if sign must be checked */ { BOOL negative = FALSE; /* True if negative numbers */ int diff, pow, ret; /* Check for optional minus or plus sign */ if (check_sign) { if (*str1 == '-') { negative = TRUE; str1++; } else if (*str1 == '+') str1++; if (*str2 == '-') { if (negative == FALSE) return HIGHER; str2++; } else if (negative) return LOWER; else if (*str2 == '+') str2++; } /* Keep incrementing as long as digits are available and equal */ while ((table[*str1] & DIGIT) && table[*str2] & DIGIT) { if (*str1 != *str2) break; str1++; str2++; } /* First check for the decimal point. */ if (*str1 == '.' || *str2 == '.') { if (*str1 == '.') { if (*str2 == '.') /* Both. Check decimal part */ ret = digits(str1 + 1, str2 + 1, FALSE); else ret = (table[*str2] & DIGIT) ? LOWER : HIGHER; } else ret = (table[*str1] & DIGIT) ? HIGHER : LOWER; } /* Now either two digits differ, or unknown char is seen (e.g. end of string) */ else if ((table[*str1] & DIGIT) && (table[*str2] & DIGIT)) { diff = *str1 - *str2; /* Basic difference */ pow = 0; /* Check power of numbers */ while (table[*str1++] & DIGIT) pow++; while (table[*str2++] & DIGIT) pow--; ret = (pow == 0) ? diff : pow; } /* Unknown char. Check on which string it occurred */ else { if ((table[*str1] & DIGIT) == 0) ret = (table[*str2] & DIGIT) ? LOWER : SAME; else ret = HIGHER; } /* Reverse sense of comparisons if negative is true. (-1000 < -1) */ return (negative) ? -ret : ret; } /* * Files_merge () merges all files as indicated by nr_of_files. Merging goes * in numbers of files that can be opened at the same time. (OPEN_FILES) */ files_merge(file_cnt) register int file_cnt; /* Nr_of_files to merge */ { register int i; int limit; for (i = 0; i < file_cnt; i += OPEN_FILES) { /* Merge last files and store in output file */ if ((limit = i + OPEN_FILES) >= file_cnt) { open_outfile(); limit = file_cnt; } else { /* Merge OPEN_FILES files and store in temp file */ temp_files[16] = file_cnt / 26 + 'a'; temp_files[17] = file_cnt % 26 + 'a'; if ((out_fd = creat(temp_files, 0644)) < 0) error(TRUE, "Cannot creat ", temp_files); file_cnt++; } merge(i, limit); } /* Cleanup mess */ i = (only_merge) ? args_limit - args_offset : 0; while (i < file_cnt) (void) unlink(file_name(i++)); } /* * Merge () merges the files between start_file and limit_file. */ merge(start_file, limit_file) int start_file, limit_file; { register MERGE *smallest; /* Keeps track of smallest line */ register int i; int file_cnt = limit_file - start_file;/* Nr of files to merge */ /* Calculate size in core available for file_cnt merge structs */ buf_size = MEMORY_SIZE / file_cnt - LINE_SIZE; mbrk(mem_top); /* First reset mem to lowest loc. */ disabled = 0; /* All files not done yet */ /* Set up merge structures. */ for (i = start_file; i < limit_file; i++) { smallest = &merge_f[i - start_file]; if (!strcmp(file_name(i), "-")) /* File is stdin */ smallest->fd = 0; else if ((smallest->fd = open(file_name(i), 0)) < 0) { smallest->fd = ERROR; error(FALSE, "Cannot open ", file_name(i)); disabled++; /* Done this file */ continue; } smallest->buffer = msbrk(buf_size); smallest->line = msbrk(LINE_SIZE); smallest->cnt = smallest->read_chars = 0; (void) read_line(smallest); /* Read first line */ } if (disabled == file_cnt) { /* Couldn't open files */ (void) close(out_fd); return; } /* Find a merg struct to assign smallest. */ for (i = 0; i < file_cnt; i++) { if (merge_f[i].fd != ERROR) { smallest = &merge_f[i]; break; } } /* Loop until all files minus one are done */ while (disabled < file_cnt - 1) { if (uniq) /* Skip all same lines */ smallest = skip_lines(smallest, file_cnt); else { /* Find smallest line */ for (i = 0; i < file_cnt; i++) { if (merge_f[i].fd == ERROR) continue;/* We've had this one */ if (compare(merge_f[i].line,smallest->line) < 0) smallest = &merge_f[i]; } } /* Print line and read next */ smallest = print(smallest, file_cnt); } if (only_merge && uniq) uniq_lines(smallest); /* Print only uniq lines */ else /* Print rest of file */ while (print(smallest, file_cnt) != NIL_MERGE) ; put_line(NIL_PTR); /* Flush output buffer */ } /* * Put_line () prints the line into the out_fd filedescriptor. If line equals * NIL_PTR, the out_fd is flushed and closed. */ put_line(line) register char *line; { static int index = 0; /* Index in out_buffer */ if (line == NIL_PTR) { /* Flush and close */ mwrite(out_fd, out_buffer, index); index = 0; (void) close(out_fd); return; } do { /* Fill out_buffer with line */ out_buffer[index++] = *line; if (index == IO_SIZE) { mwrite(out_fd, out_buffer, IO_SIZE); index = 0; } } while (*line++ != '\n'); } /* * Print () prints the line of the merg structure and tries to read another one. * If this fails, it returns the next merg structure which file_descriptor is * still open. If none could be found, a NIL structure is returned. */ MERGE *print(merg, file_cnt) register MERGE *merg; int file_cnt; /* Nr of files that are being merged */ { register int i; put_line(merg->line); /* Print the line */ if (read_line(merg) == ERROR) {/* Read next line */ for (i = 0; i < file_cnt; i++) { if (merge_f[i].fd != ERROR) { merg = &merge_f[i]; break; } } if (i == file_cnt) /* No more files left */ return NIL_MERGE; } return merg; } /* * Read_line () reads a line from the fd from the merg struct. If the read * failed, disabled is incremented and the file is closed. Readings are * done in buf_size bytes. * Lines longer than LINE_SIZE are silently truncated. */ read_line(merg) register MERGE *merg; { register char *ptr = merg->line - 1; /* Ptr buf that will hold line*/ do { ptr++; if (merg->cnt == merg->read_chars) {/* Read new buffer */ if ((merg->read_chars = read(merg->fd, merg->buffer, buf_size)) <= 0) { (void) close(merg->fd);/* OOPS */ merg->fd = ERROR; disabled++; return ERROR; } merg->cnt = 0; } *ptr = merg->buffer[merg->cnt++];/* Assign next char of line */ if (ptr - merg->line == LINE_SIZE - 1) *ptr = '\n'; /* Truncate very long lines */ } while (*ptr != '\n' && *ptr != '\0'); if (*ptr == '\0') /* Add '\n' to last line */ *ptr = '\n'; *++ptr = '\0'; /* Add '\0' */ return OK; } /* * Skip_lines () skips all same lines in all the files currently being merged. * It returns a pointer to the merge struct containing the smallest line. */ MERGE *skip_lines(smallest, file_cnt) register MERGE *smallest; int file_cnt; { register int i; int ret; if (disabled == file_cnt - 1) /* We've had all */ return smallest; for (i = 0; i < file_cnt; i++) { if (merge_f[i].fd == ERROR || smallest == &merge_f[i]) continue; /* Don't check same file */ while ((ret = compare(merge_f[i].line, smallest->line)) == 0) { if (read_line(&merge_f[i]) == ERROR) break; /* EOF */ } if (ret < 0) /* Line wasn't smallest. Try again */ return skip_lines(&merge_f[i], file_cnt); } return smallest; } /* * Uniq_lines () prints only the uniq lines out of the fd of the merg struct. */ uniq_lines(merg) register MERGE *merg; { char lastline[LINE_SIZE]; /* Buffer to hold last line */ for (; ;) { put_line(merg->line); /* Print this line */ copy(lastline, merg->line); /* and save it */ if (read_line(merg) == ERROR) /* Read the next */ return; /* Keep reading until lines duffer */ while (compare(lastline, merg->line) == SAME) if (read_line(merg) == ERROR) return; } /* NOTREACHED */ } /* * Check_file () checks if a file is sorted in order according to the arguments * given in main (). */ check_file(fd, file) int fd; char *file; { register MERGE *merg; /* 1 file only */ char lastline[LINE_SIZE]; /* Save last line */ register int ret; /* ret status of compare */ if (fd == 0) file = "stdin"; merg = (MERGE *) mem_top; /* Assign MERGE structure */ merg->buffer = mem_top + sizeof(MERGE); merg->line = msbrk(LINE_SIZE); merg->cnt = merg->read_chars = 0; merg->fd = fd; buf_size = MEMORY_SIZE - sizeof(MERGE); if (read_line(merg) == ERROR) /* Read first line */ return; copy (lastline, merg->line); /* and save it */ for (; ;) { if (read_line(merg) == ERROR) /* EOF reached */ break; if ((ret = compare(lastline, merg->line)) > 0) { error(FALSE, "Disorder in file ", file); write(2, merg->line, length(merg->line)); break; } else if (ret < 0) /* Copy if lines not equal */ copy(lastline, merg->line); else if (uniq) { error(FALSE, "Non uniq line in file ", file); write(2, merg->line, length(merg->line)); break; } } mbrk(mem_top); /* Reset mem */ } /* * Length () returns the length of the argument line including the linefeed. */ length(line) register char *line; { register int i = 1; /* Add linefeed */ while (*line++ != '\n') i++; return i; } /* * Copy () copies the src line into the dest line including linefeed. */ copy(dest, src) register char *dest, *src; { while ((*dest++ = *src++) != '\n') ; } /* * Msbrk() does a sbrk() and checks the return value. */ char *msbrk(size) register unsigned size; { extern char *sbrk(); register char *address; if ((address = sbrk(size)) < 0) error(TRUE, "Not enough memory. Use chmem to allocate more", NIL_PTR); return address; } /* * Mbrk() does a brk() and checks the return value. */ char *mbrk(size) register unsigned size; { extern char *brk(); register char *address; if ((address = brk(size)) < 0) error(TRUE, "Cannot reset memory", NIL_PTR); return address; } /* split - split a file Author: Michiel Huisjes */ #include "blocksize.h" int cut_line = 1000; int infile; char out_file[100]; char *suffix; main(argc, argv) int argc; char **argv; { unsigned short i; out_file[0] = 'x'; infile = -1; if (argc > 4) usage(); for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (argv[i][1] >= '0' && argv[i][1] <= '9' && cut_line == 1000) cut_line = atoi(argv[i]); else if (argv[i][1] == '\0' && infile == -1) infile = 0; else usage(); } else if (infile == -1) { if ((infile = open(argv[i], 0)) < 0) { std_err("Cannot open input file.\n"); exit (1); } } else strcpy(out_file, argv[i]); } if (infile == -1) infile = 0; strcat(out_file, "aa"); for (suffix = out_file; *suffix; suffix++) ; suffix--; /* Appendix now points to last `a' of "aa". We have to decrement it by one */ *suffix = 'a' - 1; split(); exit(0); } split() { char buf[BLOCK_SIZE]; register char *index, *base; register int n; int fd; long lines = 0L; fd = newfile(); while ((n = read(infile, buf, BLOCK_SIZE)) > 0) { base = index = buf; while (--n >= 0) { if (*index++ == '\n') if (++lines % cut_line == 0) { if (write(fd,base,(int)(index-base)) != (int)(index-base)) quit(); base = index; close(fd); fd = newfile(); } } if (write(fd, base, (int) (index-base)) != (int) (index-base)) quit(); } } newfile() { int fd; if (++*suffix > 'z') { /* Increment letter */ *suffix = 'a'; /* Reset last letter */ ++*(suffix - 1); /* Previous letter must be incremented*/ /* E.g. was `filename.az' */ /* Now `filename.ba' */ } if ((fd = creat(out_file, 0644)) < 0) { std_err("Cannot create new file.\n"); exit(2); } return fd; } usage () { std_err("Usage: split [-n] [file [name]].\n"); exit(1); } quit() { std_err("split: write error\n"); exit(1); } /* stty - set terminal mode Author: Andy Tanenbaum */ #include "sgtty.h" char *on[] = {"tabs", "cbreak", "raw", "-nl", "echo"}; char *off[]= {"-tabs", "", "", "nl", "-echo"}; int k; struct sgttyb args; struct tchars tch; #define STARTC 021 /* CTRL-Q */ #define STOPC 023 /* CTRL-S */ #define QUITC 034 /* CTRL-\ */ #define EOFC 004 /* CTRL-D */ #define DELC 0177 /* DEL */ main(argc, argv) int argc; char *argv[]; { /* stty with no arguments just reports on current status. */ ioctl(0, TIOCGETP, &args); ioctl(0, TIOCGETC, &tch); if (argc == 1) { report(); exit(0); } /* Process the options specified. */ k = 1; while (k < argc) { option(argv[k], argv[k+1]); k++; } ioctl(0, TIOCSETP, &args); ioctl(0, TIOCSETC, &tch); exit(0); } report() { int mode; mode = args.sg_flags; pr(mode&XTABS, 0); pr(mode&CBREAK, 1); pr(mode&RAW, 2); pr(mode&CRMOD,3); pr(mode&ECHO,4); prints("\nkill = "); prctl(args.sg_kill); prints("\nerase = "); prctl(args.sg_erase); prints("\nint = "); prctl(tch.t_intrc); prints("\nquit = "); prctl(tch.t_quitc); prints("\n"); } pr(f, n) int f,n; { if (f) prints("%s ",on[n]); else prints("%s ",off[n]); } option(opt, next) char *opt, *next; { if (match(opt, "-tabs")) {args.sg_flags &= ~XTABS; return;} if (match(opt, "-raw")) {args.sg_flags &= ~RAW; return;} if (match(opt, "-cbreak")) {args.sg_flags &= ~CBREAK; return;} if (match(opt, "-echo")) {args.sg_flags &= ~ECHO; return;} if (match(opt, "-nl")) {args.sg_flags |= CRMOD; return;} if (match(opt, "tabs")) {args.sg_flags |= XTABS; return;} if (match(opt, "raw")) {args.sg_flags |= RAW; return;} if (match(opt, "cbreak")) {args.sg_flags |= CBREAK; return;} if (match(opt, "echo")) {args.sg_flags |= ECHO; return;} if (match(opt, "nl")) {args.sg_flags &= ~CRMOD; return;} if (match(opt, "kill")) {args.sg_kill = *next; k++; return;} if (match(opt, "erase")) {args.sg_erase = *next; k++; return;} if (match(opt, "int")) {tch.t_intrc = *next; k++; return;} if (match(opt, "quit")) {tch.t_quitc = *next; k++; return;} if (match(opt, "default")) { args.sg_flags = ECHO | CRMOD | XTABS; args.sg_kill = '@'; args.sg_erase = '\b'; tch.t_intrc = DELC; tch.t_quitc = QUITC; tch.t_startc = STARTC; tch.t_stopc = STOPC; tch.t_eofc = EOFC; return; } std_err("unknown mode: "); std_err(opt); std_err("\n"); } int match(s1, s2) char *s1, *s2; { while (1) { if (*s1 == 0 && *s2 == 0) return(1); if (*s1 == 0 || *s2 == 0) return(0); if (*s1 != *s2) return(0); s1++; s2++; } } prctl(c) char c; { if (c < ' ') prints("^%c", 'A' + c - 1); else if (c == 0177) prints("DEL"); else prints("%c", c); } /* su - become super-user Author: Patrick van Kleef */ #include "sgtty.h" #include "stdio.h" #include "pwd.h" main (argc, argv) int argc; char *argv[]; { register char *name; char *crypt (); char *shell = "/bin/sh"; int nr; char password[14]; struct sgttyb args; register struct passwd *pwd; struct passwd *getpwnam (); if (argc > 1) name = argv[1]; else name = "root"; if ((pwd = getpwnam (name)) == 0) { std_err("Unknown id: "); std_err(name); std_err("\n"); exit (1); } if (pwd->pw_passwd[0] != '\0' && getuid()!= 0) { std_err("Password: "); ioctl (0, TIOCGETP, &args); /* get parameters */ args.sg_flags = args.sg_flags & (~ECHO); ioctl (0, TIOCSETP, &args); nr = read (0, password, 14); password[nr - 1] = 0; putc('\n',stderr); args.sg_flags = args.sg_flags | ECHO; ioctl (0, TIOCSETP, &args); if (strcmp (pwd->pw_passwd, crypt (password, pwd->pw_passwd))) { std_err("Sorry\n"); exit (2); } } setgid (pwd->pw_gid); setuid (pwd->pw_uid); if (pwd->pw_shell[0]) shell = pwd->pw_shell; execn (shell); std_err("No shell\n"); exit (3); } /* sum - checksum a file Author: Martin C. Atkins */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. */ #define BUFSIZ (512) int rc = 0; char *defargv[] = { "-", 0 }; main(argc,argv) int argc; char *argv[]; { int fd; if (*++argv == 0) argv = defargv; for (; *argv; argv++) { if (argv[0][0] == '-' && argv[0][1] == '\0') fd = 0; else fd = open(*argv, 0); if (fd == -1) { error("can't open ",*argv); rc = 1; continue; } sum(fd, (argc > 2) ? *argv : (char *)0); if (fd != 0) close(fd); } exit(rc); } error(s,f) char *s,*f; { std_err("sum: "); std_err(s); if (f) std_err(f); std_err("\n"); } sum(fd,fname) int fd; char *fname; { char buf[BUFSIZ]; int i,n; int size = 0; unsigned crc = 0; unsigned tmp; while((n = read(fd,buf,BUFSIZ)) > 0) { for (i = 0; i < n; i++) { crc = (crc>>1) + ((crc&1) ? 0x8000 : 0); tmp = buf[i] & 0377; crc += tmp; crc &= 0xffff; size++; } } if (n < 0) { if (fname) error("read error on ", fname); else error("read error", (char *)0); rc = 1; return; } putd(crc,5,1); putd((size+BUFSIZ-1)/BUFSIZ, 6, 0); if (fname) prints(" %s", fname); prints("\n"); } putd(number, fw, zeros) int number,fw,zeros; { /* Put a decimal number, in a field width, to stdout. */ char buf[10]; int n; unsigned num; num = (unsigned) number; for (n = 0; n < fw; n++) { if (num || n == 0) { buf[fw-n-1] = '0' + num%10; num /= 10; } else buf[fw-n-1] = zeros ? '0' : ' '; } buf[fw] = 0; prints("%s", buf); } /* sync - flush the file system buffers. Author: Andy Tanenbaum */ main() {sync();} /* First prize in shortest useful program contest. */ /* tail - print the end of a file */ #include "stdio.h" #define TRUE 1 #define FALSE 0 #define BLANK ' ' #define TAB '\t' #define NEWL '\n' int lines, chars ; char buff[BUFSIZ]; main(argc, argv) int argc ; char *argv[] ; { char *s ; FILE *input , *fopen(); int count ; setbuf(stdout, buff); argc-- ; argv++ ; lines = TRUE ; chars = FALSE ; count = -10 ; if (argc == 0 ) { tail(stdin, count); done(0) ; } s = *argv ; if (*s == '-' || *s == '+' ) { s++ ; if (*s >= '0' && *s <= '9' ) { count = stoi(*argv); s++ ; while (*s >= '0' && *s <= '9' ) s++ ; } if (*s == 'c' ) { chars = TRUE ; lines = FALSE ; } else if (*s != 'l' && *s != NULL ) { fprintf(stderr, "tail: unknown option %c\n", *s); argc = 0 ; } argc-- ; argv++ ; } if (argc < 0 ) { fprintf(stderr, "Usage: tail [+/-[number][lc]] [files]\n"); done(1) ; } if (argc == 0 ) tail(stdin, count); else if ((input=fopen(*argv,"r")) == NULL ) { fprintf(stderr, "tail: can't open %s\n", *argv) ; done(1) ; } else { tail(input, count); fclose(input); } done(0) ; } /* stoi - convert string to integer */ stoi(s) char *s ; { int n, sign ; while (*s == BLANK || *s == NEWL || *s == TAB ) s++ ; sign = 1 ; if (*s == '+' ) s++ ; else if (*s == '-' ) { sign = -1 ; s++ ; } for(n=0 ; *s >= '0' && *s <= '9' ; s++ ) n = 10 * n + *s - '0' ; return(sign * n); } /* tail - print 'count' lines/chars */ #define INCR(p) if (p >= end) p=cbuf ; else p++ #define BUF_SIZE 4098 char cbuf[ BUF_SIZE ] ; tail(in, goal ) FILE *in ; int goal ; { int c, count ; char *start, *finish, *end ; count = 0 ; if (goal > 0 ) { /* skip */ if (lines ) /* lines */ while ((c=getc(in)) != EOF ) { if (c == NEWL ) count++ ; if (count >= goal ) break ; } else /* chars */ while (getc(in) != EOF ) { count++ ; if (count >= goal ) break ; } if (count >= goal ) while ((c=getc(in)) != EOF ) putc(c, stdout); } else { /* tail */ goal = -goal ; start = finish = cbuf ; end = &cbuf[ BUF_SIZE - 1 ] ; while ((c=getc(in)) != EOF ) { *finish = c ; INCR(finish); if (start == finish ) INCR(start); if (!lines || c == NEWL ) count++ ; if (count > goal ) { count = goal ; if (lines ) while (*start != NEWL ) INCR(start); INCR(start); } } /* end while */ while (start != finish ) { putc(*start, stdout); INCR(start); } } /* end else */ } /* end tail */ done(n) int n; { _cleanup(); /* flush stdio's internal buffers */ exit(n); } /* tar - tape archiver Author: Michiel Huisjes */ /* Usage: tar [cxt][v] tapefile [files] * * Bugs: * This tape archiver should only be used as a program to read or make * simple tape archives. Its basic goal is to read (or build) UNIX V7 tape * archives and extract the named files. It is not wise to use it on * raw magnetic tapes. It doesn't know anything about linked files, * except when the involved fields are filled in. */ #include "stat.h" struct direct { unsigned short d_ino; char d_name[14]; }; typedef char BOOL; #define TRUE 1 #define FALSE 0 #define HEADER_SIZE 512 #define NAME_SIZE 100 #define BLOCK_BOUNDARY 20 typedef union { char hdr_block[HEADER_SIZE]; struct m { char m_name[NAME_SIZE]; char m_mode[8]; char m_uid[8]; char m_gid[8]; char m_size[12]; char m_time[12]; char m_checksum[8]; char m_linked; char m_link[NAME_SIZE]; } member; } HEADER; HEADER header; #define INT_TYPE (sizeof(header.member.m_uid)) #define LONG_TYPE (sizeof(header.member.m_size)) #define MKDIR "/bin/mkdir" #define NIL_HEADER ((HEADER *) 0) #define NIL_PTR ((char *) 0) #define BLOCK_SIZE 512 #define flush() print(NIL_PTR) BOOL show_fl, creat_fl, ext_fl; int tar_fd; char usage[] = "Usage: tar [cxt] tarfile [files]."; char io_buffer[BLOCK_SIZE]; char path[NAME_SIZE]; char pathname[NAME_SIZE]; int total_blocks; long convert(); #define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \ + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE) error(s1, s2) char *s1, *s2; { string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : ""); flush(); exit(1); } main(argc, argv) int argc; register char *argv[]; { register char *ptr; int i; if (argc < 3) error(usage, NIL_PTR); for (ptr = argv[1]; *ptr; ptr++) { switch (*ptr) { case 'c' : creat_fl = TRUE; break; case 'x' : ext_fl = TRUE; break; case 't' : show_fl = TRUE; break; default : error(usage, NIL_PTR); } } if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR); tar_fd = creat_fl ? creat(argv[2], 0644) : open(argv[2], 0); if (tar_fd < 0) error("Cannot open ", argv[2]); if (creat_fl) { for (i = 3; i < argc; i++) { add_file(argv[i]); path[0] = '\0'; } adjust_boundary(); } else tarfile(); flush(); exit(0); } BOOL get_header() { register int check; mread(tar_fd, &header, sizeof(header)); if (header.member.m_name[0] == '\0') return FALSE; check = (int) convert(header.member.m_checksum, INT_TYPE); if (check != checksum()) error("Tar: header checksum error.", NIL_PTR); return TRUE; } tarfile() { register char *ptr; register char *mem_name; while (get_header()) { mem_name = header.member.m_name; if (ext_fl) { if (is_dir(mem_name)) { for (ptr = mem_name; *ptr; ptr++) ; *(ptr - 1) = '\0'; mkdir(mem_name); } else extract(mem_name); } else { string_print(NIL_PTR, "%s ", mem_name); if (header.member.m_linked == '1') string_print(NIL_PTR, "linked to %s\n", header.member.m_link); else { string_print(NIL_PTR, "%d tape blocks\n", block_size()); skip_entry(); } } flush(); } } skip_entry() { register int blocks = block_size(); while (blocks--) (void) read(tar_fd, io_buffer, BLOCK_SIZE); } extract(file) register char *file; { register int fd; if (header.member.m_linked == '1') { if (link(header.member.m_link, file) < 0) string_print(NIL_PTR, "Cannot link %s to %s\n", header.member.m_link, file); else string_print(NIL_PTR, "Linked %s to %s\n", header.member.m_link, file); return; } if ((fd = creat(file, 0644)) < 0) { string_print(NIL_PTR, "Cannot create %s\n", file); return; } copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE)); (void) close(fd); chmod(file, convert(header.member.m_mode, INT_TYPE)); flush(); } copy(file, from, to, bytes) char *file; int from, to; register long bytes; { register int rest; int blocks = (int) ((bytes + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE); string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks); while (blocks--) { (void) read(from, io_buffer, BLOCK_SIZE); rest = (bytes > (long) BLOCK_SIZE) ? BLOCK_SIZE : (int) bytes; mwrite(to, io_buffer, (to == tar_fd) ? BLOCK_SIZE : rest); bytes -= (long) rest; } } long convert(str, type) char str[]; int type; { register long ac = 0L; register int i; for (i = 0; i < type; i++) { if (str[i] >= '0' && str[i] <= '7') { ac <<= 3; ac += (long) (str[i] - '0'); } } return ac; } mkdir(dir_name) char *dir_name; { register int pid, w; if ((pid = fork()) < 0) error("Cannot fork().", NIL_PTR); if (pid == 0) { execl(MKDIR, "mkdir", dir_name, (char *) 0); error("Cannot find mkdir.", NIL_PTR); } do { w = wait((int *) 0); } while (w != -1 && w != pid); } checksum() { register char *ptr = header.member.m_checksum; register int ac = 0; while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' '; ptr = header.hdr_block; while (ptr < &header.hdr_block[BLOCK_SIZE]) ac += *ptr++; return ac; } is_dir(file) register char *file; { while (*file++ != '\0') ; return (*(file - 2) == '/'); } char *path_name(file) register char *file; { string_print(pathname, "%s%s", path, file); return pathname; } add_path(name) register char *name; { register char *path_ptr = path; while (*path_ptr) path_ptr++; if (name == NIL_PTR) { while (*path_ptr-- != '/') ; while (*path_ptr != '/' && path_ptr != path) path_ptr--; if (*path_ptr == '/') path_ptr++; *path_ptr = '\0'; } else { while (*name) { if (path_ptr == &path[NAME_SIZE]) error("Pathname too long", NIL_PTR); *path_ptr++ = *name++; } *path_ptr++ = '/'; *path_ptr = '\0'; } } add_file(file) register char *file; { struct stat st; struct direct dir; register int fd; if (stat(file, &st) < 0) { string_print(NIL_PTR, "Cannot find %s\n", file); return; } if ((fd = open(file, 0)) < 0) { string_print(NIL_PTR, "Cannot open %s\n", file); return; } make_header(path_name(file), &st); mwrite(tar_fd, &header, sizeof(header)); if (st.st_mode & S_IFREG) copy(path_name(file), fd, tar_fd, st.st_size); else if (st.st_mode & S_IFDIR) { if (chdir(file) < 0) string_print(NIL_PTR, "Cannot chdir to %s\n", file); else { add_path(file); mread(fd, &dir, sizeof(dir)); /* "." */ mread(fd, &dir, sizeof(dir)); /* ".." */ while (read(fd, &dir, sizeof(dir)) == sizeof(dir)) if (dir.d_ino) add_file(dir.d_name); chdir(".."); add_path(NIL_PTR); } } else print(" Tar: unknown file type. Not added.\n"); (void) close(fd); } make_header(file, st) char *file; register struct stat *st; { register char *ptr = header.member.m_name; clear_header(); while (*ptr++ = *file++) ; if (st->st_mode & S_IFDIR) { *(ptr - 1) = '/'; st->st_size = 0L; } string_print(header.member.m_mode, "%I ", st->st_mode & 07777); string_print(header.member.m_uid, "%I ", st->st_uid); string_print(header.member.m_gid, "%I ", st->st_gid); string_print(header.member.m_size, "%L ", st->st_size); string_print(header.member.m_time, "%L ", st->st_mtime); header.member.m_linked = ' '; string_print(header.member.m_checksum, "%I", checksum()); } clear_header() { register char *ptr = header.hdr_block; while (ptr < &header.hdr_block[BLOCK_SIZE]) *ptr++ = '\0'; } adjust_boundary() { clear_header(); mwrite(tar_fd, &header, sizeof(header)); while (total_blocks++ < BLOCK_BOUNDARY) mwrite(tar_fd, &header, sizeof(header)); (void) close(tar_fd); } mread(fd, address, bytes) int fd, bytes; char *address; { if (read(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR); } mwrite(fd, address, bytes) int fd, bytes; char *address; { if (write(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR); total_blocks++; } char output[BLOCK_SIZE]; print(str) register char *str; { static int index = 0; if (str == NIL_PTR) { write(1, output, index); index = 0; return; } while (*str) { output[index++] = *str++; if (index == BLOCK_SIZE) { write(1, output, BLOCK_SIZE); index =   0; } } } char *num_out(number) register long number; { static char num_buf[13]; char temp[13]; register int i; for (i = 0; i < 11; i++) { temp[i] = (number & 07) + '0'; number >>= 3; } for (i = 0; i < 11; i++) num_buf[i] = temp[10 - i]; return num_buf; } /* VARARGS */ string_print(buffer, fmt, args) char *buffer; register char *fmt; int args; { register char *buf_ptr; char *scan_ptr; char buf[NAME_SIZE]; int *argptr = &args; BOOL pr_fl, i; if (pr_fl = (buffer == NIL_PTR)) buffer = buf; buf_ptr = buffer; while (*fmt) { if (*fmt == '%') { fmt++; switch (*fmt++) { case 's': scan_ptr = (char *) *argptr; break; case 'I': scan_ptr = num_out((long) *argptr); for (i = 0; i < 5; i++) scan_ptr++; break; case 'L': scan_ptr = num_out(*((long *) argptr)); argptr++; break; case 'd' : scan_ptr = num_out((long) *argptr); while (*scan_ptr == '0') scan_ptr++; scan_ptr--; break; default: scan_ptr = ""; } while (*buf_ptr++ = *scan_ptr++) ; buf_ptr--; argptr++; } else *buf_ptr++ = *fmt++; } *buf_ptr = '\0'; if (pr_fl) print(buffer); } /* tee - pipe fitting Author: Paul Polderman */ #include "blocksize.h" #include "signal.h" #define MAXFD 18 int fd[MAXFD]; main(argc, argv) int argc; char **argv; { char iflag = 0, aflag = 0; char buf[BLOCK_SIZE]; int i, s, n; argv++; --argc; while (argc > 0 && argv[0][0] == '-') { switch (argv[0][1]) { case 'i': /* Interrupt turned off. */ iflag++; break; case 'a': /* Append to outputfile(s), * instead of overwriting them. */ aflag++; break; default: std_err("Usage: tee [-i] [-a] [files].\n"); exit(1); } argv++; --argc; } fd[0] = 1; /* Always output to stdout. */ for (s = 1; s < MAXFD && argc > 0; --argc, argv++) { if ((fd[s] = open(*argv, 2)) < 0 && (fd[s] = creat(*argv, 0666)) < 0) { std_err("Cannot open output file: "); std_err(*argv); std_err("\n"); exit(2); } s++; } if (iflag) signal(SIGINT, SIG_IGN); for (i = 1; i < s; i++) { /* Don't lseek stdout. */ if (aflag) lseek(fd[i], 0L, 2); } while ((n = read(0, buf, BLOCK_SIZE)) > 0) { for (i = 0; i < s; i++) write(fd[i], buf, n); } for (i = 0; i < s; i++) /* Close all fd's */ close(fd[i]); exit(0); } /* time - time a command Authors: Andy Tanenbaum & Michiel Huisjes */ #include "signal.h" #include "../h/const.h" char **args; char *name; struct time_buf { long user, sys; long childu, childs; }; int digit_seen; char a[12] = {" . \n"}; main(argc, argv) int argc; char *argv[]; { struct time_buf pre_buf, post_buf; int status, pid; long start_time, end_time; if (argc == 1) exit(0); args = &argv[1]; name = argv[1]; /* Get real time at start of run. */ (void) time(&start_time); /* Fork off child. */ if ((pid = fork()) < 0) { std_err("Cannot fork\n"); exit(1); } if (pid == 0) execute(); /* Parent is the time program. Disable interrupts and wait. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); do { times(&pre_buf); } while (wait(&status) != pid); (void) time(&end_time); if ((status & 0377) != 0) std_err("Command terminated abnormally.\n"); times(&post_buf); /* Print results. */ print_time("real ", (end_time - start_time) * HZ); print_time("user ", post_buf.childu - pre_buf.childu); print_time("sys ", post_buf.childs - pre_buf.childs); exit(status >> 8); } print_time(mess, t) char *mess; register long t; { /* Print the time 't' in hours: minutes: seconds. 't' is in ticks. */ int hours, minutes, seconds, tenths, i; digit_seen = 0; for (i = 0; i < 8; i++) a[i] = ' '; hours = (int) (t / (3600L * (long) HZ)); t -= (long) hours * 3600L * (long) HZ; minutes = (int) (t / (60L * (long) HZ)); t -= (long) minutes * 60L * (long) HZ; seconds = (int) (t / (long) HZ); t -= (long) seconds * (long) HZ; tenths = (int) (t / ((long) HZ / 10L)); std_err(mess); if (hours) { twin(hours, &a[0]); a[2] = ':'; } if (minutes || digit_seen) { twin(minutes, &a[3]); a[5] = ':'; } if (seconds || digit_seen) twin(seconds, &a[6]); else a[7] = '0'; a[9] = tenths + '0'; std_err(a); } twin(n, p) int n; char *p; { char c1, c2; c1 = (n/10) + '0'; c2 = (n%10) + '0'; if (digit_seen==0 && c1 == '0') c1 = ' '; *p++ = c1; *p++ = c2; if (n > 0) digit_seen = 1; } char *newargs[MAX_ISTACK_BYTES >> 2] = { "/bin/sh" }; /* 256 args */ execute() { register int i; try(""); /* try local directory */ try("/bin/"); try("/usr/bin/"); for (i = 0; newargs[i + 1] = args[i]; i++) ; execv("/bin/sh", newargs); std_err("Cannot execute /bin/sh\n"); exit(-1); } char pathname[200]; try(path) char *path; { register char *p1, *p2; p1 = path; p2 = pathname; while (*p1 != 0) *p2++ = *p1++; p1 = name; while (*p1 != 0) *p2++ = *p1++; *p2 = 0; execv(pathname, args); } #include "stat.h" #include "errno.h" int no_creat = 0; main(argc,argv) int argc; char *argv[]; { char *path; int i =1; if (argc == 1) usage(); while ( i < argc ) { if (argv[i][0] == '-') { if (argv[i][1] == 'f') { i+=1; } else if (argv[i][1] == 'c') { no_creat = 1; i+=1; } else { usage(); } } else { path=argv[i]; i+=1; if (doit(path) > 0) { std_err("touch: cannot touch "); std_err(path); std_err("\n"); } } } exit(0); } doit(name) char *name; { int fd; long *t, tim; struct stat buf; unsigned short tmp; long tvp[2]; extern long time(); if (!access(name,0)) { /* change date if possible */ stat(name, &buf); tmp = (buf.st_mode & S_IFREG); if (tmp != S_IFREG) return(1); tim = time(0L); tvp[0] = tim; tvp[1] = tim; if (!utime(name,tvp)) return(0); else return(1); } else { /* file does not exist */ if (no_creat == 1) return(0); else if ( (fd = creat(name, 0777)) < 0) { return(1); } else { close(fd); return(0); } } } usage() { std_err("Usage: touch [-c] file...\n"); exit(1); } std_err(s) { prints("%s",s); } /* tr - translate characters Author: Michiel Huisjes */ /* Usage: tr [-cds] [string1 [string2]] * c: take complement of string1 * d: delete input characters coded string1 * s: squeeze multiple output characters of string2 into one character */ #define BUFFER_SIZE 1024 #define ASCII 0377 typedef char BOOL; #define TRUE 1 #define FALSE 0 #define NIL_PTR ((char *) 0) BOOL com_fl, del_fl, sq_fl; unsigned char output[BUFFER_SIZE], input[BUFFER_SIZE]; unsigned char vector[ASCII + 1]; BOOL invec[ASCII + 1], outvec[ASCII + 1]; short in_index, out_index; main(argc, argv) int argc; char *argv[]; { register unsigned char *ptr; int index = 1; short i; if (argc > 1 && argv[index][0] == '-') { for (ptr = &argv[index][1]; *ptr; ptr++) { switch (*ptr) { case 'c' : com_fl = TRUE; break; case 'd' : del_fl = TRUE; break; case 's' : sq_fl = TRUE; break; default : write(2, "Usage: tr [-cds] [string1 [string2]].\n", 38); exit(1); } } index++; } for (i = 0; i <= ASCII; i++) { vector[i] = i; invec[i] = outvec[i] = FALSE; } if (argv[index] != NIL_PTR) { expand(argv[index++], input); if (com_fl) complement(input); if (argv[index] != NIL_PTR) expand(argv[index], output); if (argv[index] != NIL_PTR) map(input, output); for (ptr = input; *ptr; ptr++) invec[*ptr] = TRUE; for (ptr = output; *ptr; ptr++) outvec[*ptr] = TRUE; } convert(); } convert() { short read_chars = 0; short c, coded; short last = -1; for (; ;) { if (in_index == read_chars) { if ((read_chars = read(0, input, BUFFER_SIZE)) <= 0) { if (write(1, output, out_index) != out_index) write(2, "Bad write\n", 10); exit(0); } in_index = 0; } c = input[in_index++]; coded = vector[c]; if (del_fl && invec[c]) continue; if (sq_fl && last == coded && outvec[coded]) continue; output[out_index++] = last = coded; if (out_index == BUFFER_SIZE) { if (write(1, output, out_index) != out_index) { write(2, "Bad write\n", 10); exit(1); } out_index = 0; } } /* NOTREACHED */ } map(string1, string2) register unsigned char *string1, *string2; { unsigned char last; while (*string1) { if (*string2 == '\0') vector[*string1] = last; else vector[*string1] = last = *string2++; string1++; } } expand(arg, buffer) register char *arg; register unsigned char *buffer; { int i, ac; while (*arg) { if (*arg == '\\') { arg++; i = ac = 0; if (*arg >= '0' && *arg <= '7') { do { ac = (ac << 3) + *arg++ - '0'; i++; } while (i < 4 && *arg >= '0' && *arg <= '7'); *buffer++ = ac; } else if (*arg != '\0') *buffer++ = *arg; } else if (*arg == '[') { arg++; i = *arg++; if (*arg++ != '-') { *buffer++ = '['; *buffer++ = i; *buffer++ = '-'; continue; } ac = *arg++; while (i <= ac) *buffer++ = i++; arg++; /* Skip ']' */ } else *buffer++ = *arg++; } } complement(buffer) unsigned char *buffer; { register unsigned char *ptr; register short i, index; unsigned char conv[ASCII + 2]; index = 0; for (i = 1; i <= ASCII; i++) { for (ptr = buffer; *ptr; ptr++) if (*ptr == i) break; if (*ptr == '\0') conv[index++] = i & ASCII; } conv[index] = '\0'; strcpy(buffer, conv); } /* umount - unmount a file system Author: Andy Tanenbaum */ #include "errno.h" extern int errno; main(argc, argv) int argc; char *argv[]; { if (argc != 2) usage(); if (umount(argv[1]) < 0) { if (errno == EINVAL) std_err("Device not mounted\n"); else perror("umount"); exit(1); } std_err(argv[1]); std_err(" unmounted\n"); exit(0); } usage() { std_err("Usage: umount special\n"); exit(1); } /* uniq - compact repeated lines Author: John Woods */ /* * uniq [-udc] [-n] [+n] [infile [outfile]] * * Written 02/08/86 by John Woods, placed into public domain. Enjoy. * */ /* If the symbol WRITE_ERROR is defined, uniq will exit(1) if it gets a * write error on the output. This is not (of course) how V7 uniq does it, * so undefine the symbol if you want to lose your output to a full disk */ #define WRITE_ERROR 1 #define isdigit(c) (c >= '0' && c <= '9') #include "stdio.h" FILE *fopen(); char buffer [BUFSIZ]; int uflag = 1; /* default is union of -d and -u outputs */ int dflag = 1; /* flags are mutually exclusive */ int cflag = 0; int fields = 0; int chars = 0; FILE *xfopen(fn, mode) char *fn, *mode; { FILE *p; extern int errno; extern char *sys_errlist[]; if ((p = fopen(fn,mode)) == NULL) { perror("uniq"); fflush(stdout); exit(1); } return (p); } main(argc,argv) char *argv[]; { char *p; int inf = -1, outf; setbuf(stdout, buffer); for (--argc, ++argv; argc > 0 && (**argv == '-' || **argv == '+'); --argc, ++argv) { if (**argv == '+') chars = atoi(*argv + 1); else if (isdigit(argv[0][1])) fields = atoi(*argv + 1); else if (argv[0][1] == '\0') inf = 0; /* - is stdin */ else for (p = *argv+1; *p; p++) { switch(*p) { case 'd': dflag = 1; uflag = 0; break; case 'u': uflag = 1; dflag = 0; break; case 'c': cflag = 1; break; default: usage(); } } } /* input file */ if (argc == 0) inf = 0; else if (inf == -1) { /* if - was not given */ fclose(stdin); xfopen(*argv++, "r"); argc--; } if (argc == 0) outf = 1; else { fclose(stdout); xfopen(*argv++, "w"); argc--; } uniq(); fflush(stdout); exit(0); } char *skip(s) char *s; { int n; /* skip fields */ for (n = fields; n > 0; --n) { /* skip blanks */ while (*s && (*s == ' ' || *s == '\t')) s++; if (!*s) return s; while (*s && (*s != ' ' && *s != '\t')) s++; if (!*s) return s; } /* skip characters */ for (n = chars; n > 0; --n) { if (!*s) return s; s++; } return s; } int equal(s1, s2) char *s1, *s2; { return !strcmp( skip(s1), skip(s2)); } show(line,count) char *line; { if (cflag) printf("%4d %s", count,line); else { if ((uflag && count == 1) || (dflag && count != 1)) printf("%s", line); } } /* * The meat of the whole affair */ char *nowline, *prevline, buf1[1024], buf2[1024]; uniq() { char *p; int seen; /* setup */ prevline = buf1; if (getline(prevline, 1024) < 0) return(0); seen = 1; nowline = buf2; /* get nowline and compare * if not equal, dump prevline and swap pointers * else continue, bumping seen count */ while (getline(nowline, 1024) > 0) { if (!equal(prevline, nowline)) { show(prevline, seen); seen = 1; p = nowline; nowline = prevline; prevline = p; } else seen += 1; } show(prevline, seen); return 0; } usage() { std_err("Usage: uniq [-udc] [+n] [-n] [input [output]]\n"); } int getline(buf,count) char *buf; int count; { char c; int ct= 0; while (ct++ < count) { c = getc(stdin); if (c <= 0) return(-1); *buf++ = c; if (c == '\n') { *buf++ = 0; return(ct); } } return(ct); } /* update - do sync periodically Author: Andy Tanenbaum */ #include "signal.h" main() { int fd, buf[2]; /* Disable SIGTERM */ signal(SIGTERM, SIG_IGN); /* Open some files to hold their inodes in core. */ close(0); close(1); close(2); open("/bin", 0); open("/lib", 0); open("/etc", 0); open("/tmp", 0); /* Flush the cache every 30 seconds. */ while (1) { sync(); sleep(30); } } /* wc - count lines, words and characters Author: David Messer */ #include "stdio.h" #define isdigit(c) (c >= '0' && c <= '9) #define isspace(c) (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r') /* * * Usage: wc [-lwc] [names] * * Flags: * l - count lines. * w - count words. * c - count characters. * * Flags l, w, and c are default. * Words are delimited by any non-alphabetic character. * * Released into the PUBLIC-DOMAIN 02/10/86 * * If you find this program to be of use to you, a donation of * whatever you think it is worth will be cheerfully accepted. * * Written by: David L. Messer * P.O. Box 19130, Mpls, MN, 55119 * Program (heavily) modified by Andy Tanenbaum */ int lflag; /* Count lines */ int wflag; /* Count words */ int cflag; /* Count characters */ long lcount; /* Count of lines */ long wcount; /* Count of words */ long ccount; /* Count of characters */ long ltotal; /* Total count of lines */ long wtotal; /* Total count of words */ long ctotal; /* Total count of characters */ main(argc, argv) int argc; char *argv[]; { int k; char *cp; int tflag, files; int i; /* Get flags. */ files = argc - 1; k = 1; cp = argv[1]; if (argc >1 && *cp++ == '-') { files--; k++; /* points to first file */ while (*cp != 0) { switch (*cp) { case 'l': lflag++; break; case 'w': wflag++; break; case 'c': cflag++; break; default: usage(); } cp++; } } /* If no flags are set, treat as wc -lwc. */ if(!lflag && !wflag && !cflag) { lflag = 1; wflag = 1; cflag = 1; } /* Process files. */ tflag = files >= 2; /* set if # files > 1 */ /* Check to see if input comes from std input. */ if (k >= argc) { count(); if(lflag) printf(" %6D", lcount); if(wflag) printf(" %6D", wcount); if(cflag) printf(" %6D", ccount); printf(" \n"); fflush(stdout); exit(0); } /* There is an explicit list of files. Loop on files. */ while (k < argc) { fclose(stdin); if (fopen(argv[k], "r") == NULL) { std_err("wc: cannot open "); std_err(argv[k]); std_err("\n"); k++; continue; } else { /* Next file has been opened as std input. */ count(); if(lflag) printf(" %6D", lcount); if(wflag) printf(" %6D", wcount); if(cflag) printf(" %6D", ccount); printf(" %s\n", argv[k]); } k++; } if(tflag) { if(lflag) printf(" %6D", ltotal); if(wflag) printf(" %6D", wtotal); if(cflag) printf(" %6D", ctotal); printf(" total\n"); } fflush(stdout); exit(0); } count() { register int c; register int word = 0; lcount = 0; wcount = 0; ccount = 0L; while((c = getc(stdin)) > 0) { ccount++; if(isspace(c)) { if(word) wcount++; word = 0; } else { word = 1; } if (c == '\n' || c == '\f') lcount++; } ltotal += lcount; wtotal += wcount; ctotal += ccount; } usage() { std_err("Usage: wc [-lwc] [name ...]\n"); exit(1); } ?...@...Amakefile# To make 'cp', type: make f=cp # To make 'ls', type: make f=ls # To make 'cat', type: make f=cat # Get the idea? l=/usr/lib i=/usr/include CFLAGS= -I/usr/include -F file: $l/libc.a $f.s @cc -o bin/$f $f.s @chmem =2048 bin/$f >/dev/null @echo "$f done ." BPCIXDC86B...Cmakefile# To make 'cp', type: make f=cp # To make 'ls', type: make f=ls # To make 'cat', type: make f=cat # Get the idea? # It is absolutely essential that no routines are extracted from -lc because # they may contain system calls. Instead, find out which library routines are # needed (e.g., lmul.o, ldiv.o, lrem.o, divsub.o, etc) and extract these # from /lib/libc.a and insert them in the MINIX library. l=../lib i=../include CFLAGS=-O -I../include file: $l/libc.a $f.o @ld -s -o bin/$f $l/crtso.o $f.o $l/libc.a $l/end.o @chmem =2048 bin/$f >/dev/null @echo "$f done ." mined: mined1.o mined2.o $i/mined.h @ld -s -i -o bin/mined $l/crtso.o mined1.o mined2.o $l/libc.a $l/end.o make: make.o @ld -s -i -o bin/make $l/crtso.o make.o $l/libc.a $l/end.o @chmem =20000 bin/make shobj = sh1.o sh2.o sh3.o sh4.o sh5.o sh: $(shobj) $i/sh.h @ld -s -i -o bin/sh $l/crtso.o $(shobj) $l/libc.a $l/end.o @chmem =8000 bin/sh D...Emake.batecho off :begin if "%1"=="" goto eind echo/ echo Compiling %1 for Minix cc1 %1 > %1.lst if errorlevel 1 goto fout cc2 %1 >> %1.lst if errorlevel 1 goto fout cc3 %1 >> %1.lst if errorlevel 1 goto fout cc4 %1 >> %1.lst if errorlevel 1 goto fout link ..\lib\crtso+%1,%1,%1,..\lib\mxc86 >> %1.lst dos2out -d %1 >>%1.lst shift goto begin :fout echo +++error in compilation+++ shift goto begin :eind F...Gblocksize.hHctype.hIerrno.hJgrp.hKlib.hLpwd.hMregexp.hNsetjmp.hOsgtty.hPsignal.hQstat.hRstdio.h#define BLOCK_SIZE 1024 /* file system data block size */ extern char _ctype_[]; #define _U 0001 #define _L 0002 #define _N 0004 #define _S 0010 #define _P 0020 #define _C 0040 #define _X 0100 #define isalpha(c) ((_ctype_+1)[c]&(_U|_L)) #define isupper(c) ((_ctype_+1)[c]&_U) #define islower(c) ((_ctype_+1)[c]&_L) #define isdigit(c) ((_ctype_+1)[c]&_N) #define isxdigit(c) ((_ctype_+1)[c]&(_N|_X)) #define isspace(c) ((_ctype_+1)[c]&_S) #define ispunct(c) ((_ctype_+1)[c]&_P) #define isalnum(c) ((_ctype_+1)[c]&(_U|_L|_N)) #define isprint(c) ((_ctype_+1)[c]&(_P|_U|_L|_N)) #define iscntrl(c) ((_ctype_+1)[c]&_C) #define isascii(c) ((unsigned)(c)<=0177) #define toupper(c) ((c) - 'a' + 'A') #define tolower(c) ((c) - 'A' + 'a') #define OK 0 #define ERROR 1 #define EPERM 1 #define ENOENT 2 #define ESRCH 3 #define EINTR 4 #define EIO 5 #define ENXIO 6 #define E2BIG 7 #define ENOEXEC 8 #define EBADF 9 #define ECHILD 10 #define EAGAIN 11 #define ENOMEM 12 #define EACCES 13 #define EFAULT 14 #define ENOTBLK 15 #define EBUSY 16 #define EEXIST 17 #define EXDEV 18 #define ENODEV 19 #define ENOTDIR 20 #define EISDIR 21 #define EINVAL 22 #define ENFILE 23 #define EMFILE 24 #define ENOTTY 25 #define ETXTBSY 26 #define EFBIG 27 #define ENOSPC 28 #define ESPIPE 29 #define EROFS 30 #define EMLINK 31 #define EPIPE 32 #define EDOM 33 #define ERANGE 34 #define E_LOCKED 101 #define E_BAD_CALL 102 #define E_LONG_STRING 103 struct group { char *name; char *passwd; int gid; }; #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "../h/callnr.h" extern message M; #define MM 0 #define FS 1 extern int callm1(), callm3(), callx(), len(); extern int errno; extern int begsig(); /* interrupts all vector here */ struct passwd { char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; char *pw_gecos; char *pw_dir; char *pw_shell; }; /* * Definitions etc. for regexp(3) routines. * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #define void int #define CHARBITS 0377 #define strchr index #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Internal use only. */ char reganch; /* Internal use only. */ char *regmust; /* Internal use only. */ int regmlen; /* Internal use only. */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); extern int regexec(); extern void regsub(); extern void regerror(); #define _JBLEN 3 typedef int jmp_buf[_JBLEN]; /* Data structures for IOCTL. */ struct sgttyb { char sg_ispeed; /* input speed (not used) */ char sg_ospeed; /* output speed (not used) */ char sg_erase; /* erase character */ char sg_kill; /* kill character */ int sg_flags; /* mode flags */ }; struct tchars { char t_intrc; /* SIGINT char */ char t_quitc; /* SIGQUIT char */ char t_startc; /* start output (initially CTRL-Q) */ char t_stopc; /* stop output (initially CTRL-S) */ char t_eofc; /* EOF (initially CTRL-D) */ char t_brkc; /* input delimiter (like nl) */ }; /* Fields in t_flags. */ #define XTABS 0006000 /* do tab expansion */ #define RAW 0000040 /* enable raw mode */ #define CRMOD 0000020 /* map lf to cr + lf */ #define ECHO 0000010 /* echo input */ #define CBREAK 0000002 /* enable cbreak mode */ #define COOKED 0000000 /* neither CBREAK nor RAW */ #define TIOCGETP (('t'<<8) | 8) #define TIOCSETP (('t'<<8) | 9) #define TIOCGETC (('t'<<8) | 18) #define TIOCSETC (('t'<<8) | 17) #define NR_SIGS 16 /* number of signals used */ #define NSIG 16 /* number of signals used */ #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt (DEL) */ #define SIGQUIT 3 /* quit (ASCII FS) */ #define SIGILL 4 /* illegal instruction (not reset when caught)*/ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define STACK_FAULT 16 /* used by kernel to signal stack fault */ int (*signal())(); #define SIG_DFL (int (*)())0 #define SIG_IGN (int (*)())1 struct stat { short int st_dev; unsigned short st_ino; unsigned short st_mode; short int st_nlink; short int st_uid; short int st_gid; short int st_rdev; long st_size; long st_atime; long st_mtime; long st_ctime; }; /* Some common definitions. */ #define S_IFMT 0170000 /* type of file */ #define S_IFDIR 0040000 /* directory */ #define S_IFCHR 0020000 /* character special */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_ISUID 04000 /* set user id on execution */ #define S_ISGID 02000 /* set group id on execution */ #define S_ISVTX 01000 /* save swapped text even after use */ #define S_IREAD 00400 /* read permission, owner */ #define S_IWRITE 00200 /* write permission, owner */ #define S_IEXEC 00100 /* execute/search permission, owner */ #define BUFSIZ 1024 #define NFILES 20 #define NULL 0 #define EOF (-1) #define CMASK 0377 #define READMODE 1 #define WRITEMODE 2 #define UNBUFF 4 #define _EOF 8 #define _ERR 16 #define IOMYBUF 32 #define PERPRINTF 64 #define STRINGS 128 #ifndef FILE extern struct _io_buf { int _fd; int _count; int _flags; char *_buf; char *_ptr; } *_io_table[NFILES]; #endif /* FILE */ #define FILE struct _io_buf #define stdin (_io_table[0]) #define stdout (_io_table[1]) #define stderr (_io_table[2]) #define getchar() getc(stdin) #define putchar(c) putc(c,stdout) #define fgetc(f) getc(f) #define fputc(c,f) putc(c,f) #define feof(p) (((p)->_flags & _EOF) != 0) #define ferror(p) (((p)->_flags & _ERR) != 0) #define fileno(p) ((p)->_fd) #define rewind(f) fseek(f, 0L, 0) #define testflag(p,x) ((p)->_flags & (x)) /* If you want a stream to be flushed after each printf use: * * perprintf(stream); * * If you want to stop with this kind of buffering use: * * noperprintf(stream); */ #define noperprintf(p) ((p)->_flags &= ~PERPRINTF) #define perprintf(p) ((p)->_flags |= PERPRINTF) if (retries) { sectnum++; } else { dexit ("mx_write",sectnum,err); } } } } dexit (s,sectnum,err) int sectnum, err; char *s; { printf ("Error: %s, sector: %d, code: %d, meaning: %s\n", s, sectnum, err, derrtab[err] ); exit (2); } #endif /*================================================================ * get_block & put_block for UNIX *===============================================================*/ #ifdef UNIX special (string) char *string; { fd = creat(string, 0777); close(fd); fd = open(string, 2); if (fd < 0) pexit("Can't open special file"); } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Read a block. */ int k; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } lseek(fd, (long) n*BLOCK_SIZE, 0); k = read(fd, buf, BLOCK_SIZE); if (k != BLOCK_SIZE) { pexit("get_block couldn't read"); } } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Write a block. */ read_and_set(n); if (lseek(fd, (long)n*BLOCK_SIZE, 0) < 0L) { pexit("put_block couldn't seek"); } if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit("put_block couldn't write"); } } /* dummy routines to keep source file clean from #ifdefs */ flush() { return; } cache_init() { return; } #endif C86 MINIX PCIX ar.c basename.c bin cat.c cc.c chmem.c chmod.c chown.c clr.c cmp.c comm.c cp.c date.c dd.c df.c dosread.c echo.c getlf.c grep.c gres.c head.c kill.c libpack.c libupack.c ln.c login.c lpr.c ls.c mkdir.c mkfs.c mknod.c mount.c mv.c od.c passwd.c pr.c pwd.c rev.c rm.c rmdir.c roff.c run shar.c size.c sleep.c sort.c split.c stty.c su.c sum.c sync.c tail.c tar.c tee.c time.c touch.c tr.c umount.c uniq.c update.c wc.c E2’d--75511