nick@nswitgould.OZ (Nick Andrew) (06/20/88)
I spent a little more time tonight working on Minix 1.3, and found a few more things I'd like to be in the official release. This article includes some shar scripts interleaved with comments ... don't just cut and run! -1- LS still has a problem with 14-character long names. You thought that one was fixed in 1.2. Yes, mostly. The remaining bug happens when a 14 character filename is listed, AND the ascii value of the first character of the inode integer in the next directory slot is a slash '/'. In other words, LS's print routine is prepared to print either a pathname of indeterminate length (with slashes), or a single filename of up to 14 characters long. Unfortunately if the first byte of the next directory slot is a '/', the print loop gets confused and prints junk. -2- Andy distributed the 1.2 and 1.3 diffs with some "ls -l" listings of the resulting directories. The only way to check that diffs have been applied properly (apart from verifying the code by eye) is to match the lengths of the files against Andy's listing. This is not very reliable. Using context diffs and Patch would make things more reliable ... but its not done yet, and anyway, I compiled the posted Patch (patchlevel 4) and couldn't coerce it to patch a darn thing. So anyhow I am taking the liberty of reposting a program called VITALS, which calculates CRC, SUM, and other info about given files. Checking the CRCs of resultant 1.3 files against the CRC of Andy's masters is a helluvalot more reliable than comparing the lengths. Of course it isn't too good if people have made _any_ local changes to the file .... but then how do you know the diff file has been applied properly anyway? Must check it by hand regardless. Vitals comes with source and a manual page, and I'm not the author (as the source plainly tells). Shar follows... echo x - vitals.c gres '^X' '' > vitals.c << '/' Xstatic char *HPUX_ID = "@(#)27.1 85/02/04"; X/* HPUX_ID: @(#)vitals.c 27.1 85/02/04 */ X/* X * Compute vital statistics of data: crc, sum, line, word, and character X * counts. See the manual entry for details. X * X * Compile with -DTABLE to produce an alternate program, which prints a X * CRC table for use in this program. X * X * The CRC code was lifted from a USENET posting: X * X * hpfcla:net.sources / hcrvax!sft / 8:17 pm Nov 15, 1984 X * X * The following program is a command to calculate the CRC of files. X * It is useful for the same purposes as sum(1). It calculates the X * true CRC16 (unlike CP/M utilities that say they calculate CRCs X * but really just hash). Crc detects more errors than old sum(1); X * for example, it detects exchanges of characters. It is also X * (now) in the public domain. X * X * CRC16 polynomial: x**0 + x**2 + x**15 + x**16 (0xA001) X * (CCITT polynomial: x**0 + x**5 + x**12 + x**16 (0x8408)) X * Initial condition: 0 X * X * D. Hugh Redelmeier, 1983 April 15; latest change: 1984 April 2. X */ X X X#include <stdio.h> X Xchar *USAGE = "usage: %s [-rslwcb] [files...]\n"; X X#define proc /* null; easy to grep for procs */ X#define chNull ('\0') X#define chNewline ('\n') X#define sbNull ((char *) NULL) X#define fileNull ((FILE *) NULL) X#define false 0 X#define true 1 X Xchar *myname; /* how command invoked */ Xint rflag = false; /* -r (crc) option */ Xint sflag = false; /* -s (sum) option */ Xint lflag = false; /* -l (lines) option */ Xint wflag = false; /* -w (words) option */ Xint cflag = false; /* -c (chars) option */ Xint bflag = false; /* -b (basenames) opt */ X Xint retval = 0; /* return value */ Xchar *defaultargs[] = {"-", sbNull}; /* read stdin by default */ X X#define PrintErr(part1,part2) \ X fprintf (stderr, "%s: %s %s\n", myname, part1, part2); X X X/************************************************************************ X * M A I N X * X * Initialize, check arguments, open files, and call another routine to X * do each file. X */ X Xproc main (argc, argv) Xregister int argc; Xregister char **argv; X{ Xextern int optind; /* for getopt() */ X int optchar; /* from getopt() */ Xregister FILE *filep; /* file to read */ X X#ifdef TABLE /* just print table */ X PrintTable(); X#else X X/* X * CHECK ARGUMENTS: X */ X X myname = *argv; X X while ((optchar = getopt (argc, argv, "rslwcb")) != EOF) X switch (optchar) X { X case 'r': rflag = true; break; X case 's': sflag = true; break; X case 'l': lflag = true; break; X case 'w': wflag = true; break; X case 'c': cflag = true; break; X case 'b': bflag = true; break; X default: fprintf (stderr, USAGE, myname); exit (1); X } X X if (! (rflag || sflag || lflag || wflag || cflag)) X rflag = sflag = lflag = wflag = cflag = true; X X argc -= optind; X argv += optind; X X if (argc < 1) /* use default arguments */ X argv = defaultargs; X X/* X * OPEN AND DO EACH INPUT FILE: X * X * Be careful to keep stdin open for filenames of "-". X * Argc is not altered; if < 1, it means no file args were given. X */ X X for ( ; *argv != sbNull; argv++) /* each argument */ X { X if (strcmp (*argv, "-") == 0) /* read stdin */ X filep = stdin; X X else if ((filep = fopen (*argv, "r")) == fileNull) X { X PrintErr ("can't open", *argv); X retval = 1; X continue; X } X X DoFile (filep, (argc < 1), *argv); X X if (filep != stdin) /* keep stdin open for reuse */ X fclose (filep); X } X exit (retval); X X#endif /* not TABLE */ X X} /* main */ X X X#ifdef TABLE X X/************************************************************************ X * P R I N T T A B L E X * X * Print table needed for CRC computation, as a C array declaration. X * The output can then be included in this program. It would be easy X * to just build the table in memory each time the program is run, but X * what the heck -- this way is a little more complicated, but already X * done, and shaves off a bit of startup time. X * X * Assumes unsigned and short are at least 16 bits. X */ X Xproc PrintTable() X{ Xregister unsigned index = 0; /* place in table */ Xregister unsigned entry; /* table entry */ Xregister int count; /* for changing entry */ X X printf ("unsigned short CRCtable [256] = {"); X X while (true) X { X if ((index % 8) == 0) /* time for new line */ X putchar (chNewline); X X for (entry = index, count = 8; (count--) > 0; ) X { X if (entry & 1) /* low bit set */ X entry = (entry >> 1) ^ 0xA001; X else X entry >>= 1; X } X X printf ("\t0x%4.4x", entry); X X if (++index == 256) X break; X X putchar (','); X } X X printf ("\n};\n"); X X} /* PrintTable */ X X X#else /* not TABLE */ X X X/************************************************************************ X * CRC TABLE AND BYTE SUM STRUCTS X * X * CRCtable[], output from PrintTable(), is used for CRC calculation. X * Structures are used for circular mod-2**16 byte sums. They assume X * that two shorts == one long! X */ X Xunsigned short CRCtable [256] = { X 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, X 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, X 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, X 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, X 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, X 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, X 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, X 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, X 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, X 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, X 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, X 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, X 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, X 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, X 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, X 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, X 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, X 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, X 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, X 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, X 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, X 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, X 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, X 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, X 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, X 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, X 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, X 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, X 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, X 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, X 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, X 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 X}; X Xstruct shorts { /* as used, order is irrelevant */ X unsigned short high, low; X}; X Xtypedef union { /* to map one long to two shorts */ X unsigned long sum; X struct shorts shorts; X} convert; X X X/************************************************************************ X * D O F I L E X * X * Read one file, calculate values, and print an output line. X * Sets retval if necessary. ch is int, not char, to be sure X * it can distinguish 0xff and EOF. As a result, all normal X * values of ch should be positive, 0..255. X */ X Xproc DoFile (filep, nullname, filename) Xregister FILE *filep; /* file to read */ X int nullname; /* ignore filename? */ X char *filename; /* name of filep */ X{ Xregister int ch; /* current char */ Xregister unsigned crc = 0; /* crc sum */ Xregister long sum = 0L; /* byte sum */ Xregister long lines = 0L; /* line count */ Xregister long words = 0L; /* word count */ Xregister long chars = 0L; /* char count */ X X convert conv; /* for 16-sum */ Xregister int notword = true; /* not in word? */ X X/* X * READ FILE AND COMPUTE SUMS: X * X * CRCtable[] values have 16 bits, so the masking is necessary before each X * repeated index into the array. sum is allowed to increment to more than X * 16 bits; overflow is handled later. Line and char counts are accumulated X * regardless whether they are needed; it's faster not to check. Words are X * counted in the same strange way as wc(1), ignoring special chars. X */ X X while ((ch = getc (filep)) != EOF) X { X if (rflag) X crc = (crc >> 8) ^ (CRCtable [(crc ^ ch) & 0xff]); X X if (sflag) X sum += ch; X X if (ch == chNewline) X lines++; X X chars++; X X if (wflag) X { X if ((' ' < ch) && (ch < '\177')) /* word char */ X { X if (notword) /* start of word */ X { X words++; X notword = false; X } X } X else if ((ch == ' ') || (ch == '\t') || (ch == chNewline)) X { X notword = true; X } X } X } /* while */ X X/* X * REPORT ERROR OR PRINT TOTALS: X */ X X if (ferror (filep)) X { X PrintErr ("read failed from", nullname ? "stdin" : filename); X retval = 1; X } X else X { X conv.sum = sum; /* for adding back overflow */ X X if (rflag) printf (" %4.4x", crc); X if (sflag) printf (" %5u", conv.shorts.high + conv.shorts.low); X if (lflag) printf (" %6ld", lines); X if (wflag) printf (" %6ld", words); X if (cflag) printf (" %6ld", chars); X X if (! nullname) /* have name to print */ X { X if (bflag) /* basename only */ X { X char *cp = filename; X X while (*cp != chNull) /* till end of name */ X if (*cp++ == '/') /* directory level */ X filename = cp; /* set past '/' */ X } X printf (" %s", filename); X } X putchar (chNewline); X X } /* else */ X X} /* DoFile */ X X#endif /* not TABLE */ / echo x - vitals.man gres '^X' '' > vitals.man << '/' X.\" $Header: vitals.1,v 1.1 87/08/10 12:07:47 $ X.TH VITALS 1 "" X.ad b X.SH NAME Xvitals \- crc, sum, line, word, and character counts X.SH SYNOPSIS X.B vitals X[ X.B \-rslwcb X] [ X.I file ... X] X.SH DESCRIPTION X.I Vitals Xchecks data integrity by Xcomputing vital statistics related to the data in the given Xfile(s) or standard input (by default). XThe statistics include a four-digit hex CRC, a 16-bit byte sum (similar to X.IR sum (1) Xwithout the block count) Xand line, word, and character counts (similar to X.IR wc (1)). XOne line is printed for each input file or standard input, consisting of Xfive statistics fields Xfollowed by the file name, if known. XIf a file is specified as "\fB\-\fR", the program reads standard Xinput at that Xpoint and shows "\fB\-\fR" as the file name. X.SS Options X.TP 15 X.B \-r XCompute only the CRC: a true 16-bit cyclic redundancy count Xthat can Xdetect, among other things, exchanged characters. X.TP X.B \-s XCompute only the byte sum: the modulo-2\(**\(**16, unsigned, circular sum Xof all the bytes, each taken as an X.B int X(therefore normally in the range 0-255). X.TP X.B \-l XCompute only the line count: the number of newline characters in the input. X.TP X.B \-w XCompute only the word count: the number of Xcharacter sequences Xdelimited by blanks, tabs, or newlines. XAs in X.IR wc (1), Xnon-printable characters are totally ignored when looking for words. X.TP X.B \-c XCompute only the character count. X.TP X.B \-b XPrint only file basenames, not full path names. X.PP XThese options can be used in any combination. XThe default is X.BR \-rslwc , Xthat is, all but X.BR \-b . X.PP X.I Vitals Xis more efficient than separate commands tied together Xwith a shell script because the input data is read only once. XUnlike X.IR wc (1), Xthis program does not compute totals, since it is intended for fast data Xvalidation, not size counting. X.SH DIAGNOSTICS XIf any file open or read fails, the program writes a message to standard Xerror when the problem is encountered, and continues with the next file. XIt ultimately returns non-zero if any error occurs, else zero. X.SH AUTHOR X.I Vitals Xwas developed by Hewlett-Packard. X.SH "SEE ALSO" Xsum(1), wc(1). X / -3- Getopt is in fairly wide use. This is Henry Spencer's redistributable version, working on Minix. echo x - /usr/Newlib/getopt.c gres '^X' '' > /usr/Newlib/getopt.c << '/' X X/* X * getopt - get option letter from argv X * X * Copyright (c) Henry Spencer. X * Written by Henry Spencer. X * X * This software is not subject to any license of the American Telephone X * and Telegraph Company or of the Regents of the University of California. X * X * Permission is granted to anyone to use this software for any purpose on X * any computer system, and to alter it and redistribute it freely, subject X * to the following restrictions: X * X * 1. The author is not responsible for the consequences of use of this X * software, no matter how awful, even if they arise from flaws in it. X * X * 2. The origin of this software must not be misrepresented, either by X * explicit claim or by omission. Since few users ever read sources, X * credits must appear in the documentation. X * X * 3. Altered versions must be plainly marked as such, and must not be X * misrepresented as being the original software. Since few users X * ever read sources, credits must appear in the documentation. X * X * 4. This notice may not be removed or altered. X */ X X/* X * changed index() calls to strchr() - darwin, oct 87. X */ X X#include <stdio.h> X Xchar *optarg; /* Global argument pointer. */ Xint optind = 0; /* Global argv index. */ X Xstatic char *scan = NULL; /* Private scan pointer. */ X Xextern char *strchr(); X Xint Xgetopt(argc, argv, optstring) Xint argc; Xchar *argv[]; Xchar *optstring; X{ X register char c; X register char *place; X X optarg = NULL; X X if (scan == NULL || *scan == '\0') { X if (optind == 0) X optind++; X X if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') X return(EOF); X if (strcmp(argv[optind], "--")==0) { X optind++; X return(EOF); X } X X scan = argv[optind]+1; X optind++; X } X X c = *scan++; X place = strchr(optstring, c); X X if (place == NULL || c == ':') { X fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); X return('?'); X } X X place++; X if (*place == ':') { X if (*scan != '\0') { X optarg = scan; X scan = NULL; X } else if (optind < argc) { X optarg = argv[optind]; X optind++; X } else { X fprintf(stderr, "%s: -%c argument missing\n", argv[0], c); X return('?'); X } X } X X return(c); X} / -4- I was porting some program which used environment strings a while back, and the Minix 1.2 getenv.c was causing an infinite loop. I therefore rewrote the routine, and it appears to work fine, but I don't have an exact definition of the function of getenv() so I cannot be positive there is no error in the following ... echo x - /usr/Newlib/getenv.c gres '^X' '' > /usr/Newlib/getenv.c << '/' X#define NULL (char *) 0 Xchar *getenv(name) Xregister char *name; X{ X extern char **environ; X register char **v = environ, *p, *q; X X while ((p = *v++) != NULL) { X q = name; X while ((*p == *q) && *q) { X ++p; ++q; X } X X if (*q != 0) X continue; X if (*p == '=') return(p+1); X if (*p == 0) return(p); X } X return(0); X} / -5- Andy's posting of sys/types.h seemed to lack a couple of defined types. This is the version I had to hack together in order to port some software - it too is incomplete but an amalgam of the two may be best. echo x - /usr/include/sys/types.h gres '^X' '' > /usr/include/sys/types.h << '/' X/* this is a poor hack of sys/types.h by nick for time_t & others */ X X#define major(x) ( (int) (x >> 8) & 0377) X#define minor(x) ( (int) (x >> 0) & 0377) X Xtypedef long size_t; Xtypedef long time_t; Xtypedef short dev_t; /* should be unsigned short? */ Xtypedef unsigned short ino_t; X Xtypedef short int uid_t; Xtypedef char gid_t; / -6- This is a diff to 1.2 cc.c to move the preprocessor, library and the like into /usr/lib. Why? Not everybody can mount a filesystem just for /lib (partition table limitation and in-core-superblock table size limit), or waste the memory to put it on ramdisk. My hard disk has 4 Minix partitions, /usr is the most important one in terms of compatibility with Unix. echo x - cc.c.diff gres '^X' '' > cc.c.diff << '/' X14a15,16 X> X> Change pathnames for hard disk system (Mar 5, 1988) Nick Andrew X30c32 X< !!!!_SEE_BELOW_!!! X--- X> X44,48c46,51 X< X< #ifdef MEM640K X< /* MINIX paths for 640K PC (not 512K AT) */ X< char *PP = "/lib/cpp"; X< char *CEM = "/lib/cem"; X--- X> /* #define HARDDISK */ X> X> #ifdef HARDDISK X> /* MINIX paths for hard disk system (640 or 512k) */ X> char *PP = "/usr/lib/cpp"; X> char *CEM = "/usr/lib/cem"; X56,59c59,62 X< #ifdef MEM512K X< /* MINIX paths for 512K AT (not 640K PC) */ X< char *PP = "/usr/lib/cpp"; X< char *CEM = "/usr/lib/cem"; X--- X> #ifdef MEM640K X> /* MINIX paths for 640K PC (not 512K AT) */ X> char *PP = "/lib/cpp"; X> char *CEM = "/lib/cem"; X66a70,81 X> X> #ifdef MEM512K X> /* MINIX paths for 512K AT (not 640K PC) */ X> char *PP = "/usr/lib/cpp"; X> char *CEM = "/usr/lib/cem"; X> char *OPT = "/usr/lib/opt"; X> char *CG = "/usr/lib/cg"; X> char *ASLD = "/usr/bin/asld"; X> char *SHELL = "/bin/sh"; X> char *LIBDIR = "/usr/lib"; X> #endif X> / I hope the above shars prove useful ... Nick.