147082Smckusick /*- 2*66502Sbostic * Copyright (c) 1980, 1991, 1993, 1994 361484Sbostic * The Regents of the University of California. All rights reserved. 447082Smckusick * 547082Smckusick * %sccs.include.redist.c% 622037Sdist */ 722037Sdist 822037Sdist #ifndef lint 961484Sbostic static char copyright[] = 10*66502Sbostic "@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 1161484Sbostic The Regents of the University of California. All rights reserved.\n"; 1246586Storek #endif /* not lint */ 1322037Sdist 1447082Smckusick #ifndef lint 15*66502Sbostic static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 03/28/94"; 1647082Smckusick #endif /* not lint */ 1747082Smckusick 1857725Smckusick #include <sys/param.h> 1957725Smckusick #include <sys/time.h> 2050496Smckusick #ifdef sunos 2157725Smckusick #include <sys/vnode.h> 2257725Smckusick 2357725Smckusick #include <ufs/inode.h> 2454042Smckusick #include <ufs/fs.h> 2550496Smckusick #else 2654042Smckusick #include <ufs/ffs/fs.h> 2757725Smckusick #include <ufs/ufs/dinode.h> 2854042Smckusick #endif 2957725Smckusick 3046795Sbostic #include <protocols/dumprestore.h> 3157725Smckusick 3259926Storek #include <ctype.h> 3357725Smckusick #include <errno.h> 3446795Sbostic #include <fcntl.h> 3546795Sbostic #include <fstab.h> 3657725Smckusick #include <signal.h> 3746795Sbostic #include <stdio.h> 3846795Sbostic #ifdef __STDC__ 3946795Sbostic #include <stdlib.h> 4046795Sbostic #include <string.h> 4157725Smckusick #include <unistd.h> 4246795Sbostic #endif 4357725Smckusick 441423Sroot #include "dump.h" 4537266Sbostic #include "pathnames.h" 461423Sroot 4759926Storek #ifndef SBOFF 4859926Storek #define SBOFF (SBLOCK * DEV_BSIZE) 4959926Storek #endif 5059926Storek 511423Sroot int notify = 0; /* notify operator flag */ 521423Sroot int blockswritten = 0; /* number of blocks written on current tape */ 531423Sroot int tapeno = 0; /* current tape number */ 5410910Ssam int density = 0; /* density in bytes/0.1" */ 5510910Ssam int ntrec = NTREC; /* # tape blocks in each tape record */ 5610910Ssam int cartridge = 0; /* Assume non-cartridge tape */ 5730560Smckusick long dev_bsize = 1; /* recalculated below */ 5846614Smckusick long blocksperfile; /* output blocks per file */ 5950495Smckusick char *host = NULL; /* remote host (if any) */ 601423Sroot 6159926Storek static long numarg __P((int, char *, long, long, int *, char ***)); 6259926Storek static __dead void missingarg __P((int, char *)); 6359926Storek 6457725Smckusick int 651423Sroot main(argc, argv) 6646794Smckusick int argc; 6746795Sbostic char **argv; 681423Sroot { 6946794Smckusick register ino_t ino; 7047058Smckusick register int dirty; 7146794Smckusick register struct dinode *dp; 7246794Smckusick register struct fstab *dt; 7346794Smckusick register char *map; 7446794Smckusick register char *cp; 7559926Storek int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; 7646794Smckusick ino_t maxino; 771423Sroot 7850495Smckusick spcl.c_date = 0; 7959926Storek (void)time((time_t *)&spcl.c_date); 801423Sroot 8110910Ssam tsize = 0; /* Default later, based on 'c' option for cart tapes */ 8237946Sbostic tape = _PATH_DEFTAPE; 8346794Smckusick dumpdates = _PATH_DUMPDATES; 8437266Sbostic temp = _PATH_DTMP; 8546586Storek if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) 8646586Storek quit("TP_BSIZE must be a multiple of DEV_BSIZE\n"); 8746794Smckusick level = '0'; 88*66502Sbostic if (argc == 1) { 89*66502Sbostic (void) fprintf(stderr, "Must specify a key.\n"); 90*66502Sbostic Exit(X_ABORT); 91*66502Sbostic } 9246794Smckusick argv++; 9346794Smckusick argc -= 2; 9446794Smckusick for (cp = *argv++; *cp; cp++) { 9546794Smckusick switch (*cp) { 9646794Smckusick case '-': 9759926Storek break; 981423Sroot 9946794Smckusick case 'w': 10046794Smckusick lastdump('w'); /* tell us only what has to be done */ 10157725Smckusick exit(0); 10246794Smckusick 10346794Smckusick case 'W': /* what to do */ 10446794Smckusick lastdump('W'); /* tell us state of what is done */ 10557725Smckusick exit(0); /* do nothing else */ 10646794Smckusick 10746794Smckusick case 'f': /* output file */ 10846794Smckusick if (argc < 1) 10959926Storek missingarg('f', "output file"); 11046794Smckusick tape = *argv++; 1111423Sroot argc--; 11259926Storek break; 1131423Sroot 11446794Smckusick case 'd': /* density, in bits per inch */ 11559926Storek density = numarg('d', "density", 11659926Storek 10L, 327670L, &argc, &argv) / 10; 11718494Smckusick if (density >= 625 && !bflag) 11818494Smckusick ntrec = HIGHDENSITYTREC; 11959926Storek break; 1201423Sroot 12146794Smckusick case 's': /* tape size, feet */ 12259926Storek tsize = numarg('s', "size", 12359926Storek 1L, 0L, &argc, &argv) * 12 * 10; 12459926Storek break; 1251423Sroot 12654042Smckusick case 'T': /* time of last dump */ 12754042Smckusick if (argc < 1) 12859926Storek missingarg('T', "time of last dump"); 12954042Smckusick spcl.c_ddate = unctime(*argv); 13054042Smckusick if (spcl.c_ddate < 0) { 13159926Storek (void)fprintf(stderr, "bad time \"%s\"\n", 13254042Smckusick *argv); 13359926Storek exit(X_ABORT); 13454042Smckusick } 13559926Storek Tflag = 1; 13654042Smckusick lastlevel = '?'; 13754042Smckusick argc--; 13854042Smckusick argv++; 13959926Storek break; 14054042Smckusick 14146794Smckusick case 'b': /* blocks per tape write */ 14259926Storek ntrec = numarg('b', "number of blocks per write", 14359926Storek 1L, 1000L, &argc, &argv); 14459926Storek break; 14510910Ssam 14646794Smckusick case 'B': /* blocks per output file */ 14759926Storek blocksperfile = numarg('B', "number of blocks per file", 14859926Storek 1L, 0L, &argc, &argv); 14959926Storek break; 15046614Smckusick 15146794Smckusick case 'c': /* Tape is cart. not 9-track */ 15259926Storek cartridge = 1; 15359926Storek break; 15410910Ssam 15559926Storek /* dump level */ 15659926Storek case '0': case '1': case '2': case '3': case '4': 15759926Storek case '5': case '6': case '7': case '8': case '9': 15846794Smckusick level = *cp; 15959926Storek break; 1601423Sroot 16146794Smckusick case 'u': /* update /etc/dumpdates */ 16259926Storek uflag = 1; 16359926Storek break; 1641423Sroot 16546794Smckusick case 'n': /* notify operators */ 16659926Storek notify = 1; 16759926Storek break; 1681423Sroot 16959926Storek case 'h': 17059926Storek honorlevel = numarg('h', "honor level", 17159926Storek 0L, 10L, &argc, &argv); 17259926Storek break; 17359926Storek 17446794Smckusick default: 17559926Storek (void)fprintf(stderr, "bad key '%c'\n", *cp); 17659926Storek exit(X_ABORT); 17746794Smckusick } 1781423Sroot } 17946794Smckusick if (argc < 1) { 18059926Storek (void)fprintf(stderr, "Must specify disk or filesystem\n"); 18159926Storek exit(X_ABORT); 1821423Sroot } 18359926Storek disk = *argv++; 18459926Storek argc--; 18546794Smckusick if (argc >= 1) { 18659926Storek (void)fprintf(stderr, "Unknown arguments to dump:"); 18746794Smckusick while (argc--) 18859926Storek (void)fprintf(stderr, " %s", *argv++); 18959926Storek (void)fprintf(stderr, "\n"); 19059926Storek exit(X_ABORT); 19146794Smckusick } 19254042Smckusick if (Tflag && uflag) { 19359926Storek (void)fprintf(stderr, 19454042Smckusick "You cannot use the T and u flags together.\n"); 19559926Storek exit(X_ABORT); 19654042Smckusick } 19712331Smckusick if (strcmp(tape, "-") == 0) { 19812331Smckusick pipeout++; 19912331Smckusick tape = "standard output"; 20012331Smckusick } 20110910Ssam 20246614Smckusick if (blocksperfile) 20346614Smckusick blocksperfile = blocksperfile / ntrec * ntrec; /* round down */ 20446614Smckusick else { 20546614Smckusick /* 20646614Smckusick * Determine how to default tape size and density 20746614Smckusick * 20846614Smckusick * density tape size 20946614Smckusick * 9-track 1600 bpi (160 bytes/.1") 2300 ft. 21046614Smckusick * 9-track 6250 bpi (625 bytes/.1") 2300 ft. 21146614Smckusick * cartridge 8000 bpi (100 bytes/.1") 1700 ft. 21246614Smckusick * (450*4 - slop) 21346614Smckusick */ 21446614Smckusick if (density == 0) 21546614Smckusick density = cartridge ? 100 : 160; 21646614Smckusick if (tsize == 0) 21746614Smckusick tsize = cartridge ? 1700L*120L : 2300L*120L; 21846614Smckusick } 21910910Ssam 22050495Smckusick if (index(tape, ':')) { 22150495Smckusick host = tape; 22250495Smckusick tape = index(host, ':'); 22359926Storek *tape++ = '\0'; 2246886Ssam #ifdef RDUMP 22550495Smckusick if (rmthost(host) == 0) 22657725Smckusick exit(X_ABORT); 22750495Smckusick #else 22859926Storek (void)fprintf(stderr, "remote dump not enabled\n"); 22957725Smckusick exit(X_ABORT); 23050495Smckusick #endif 2316886Ssam } 23259926Storek (void)setuid(getuid()); /* rmthost() is the only reason to be setuid */ 23350495Smckusick 23446614Smckusick if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 23555288Sbostic signal(SIGHUP, sig); 23646614Smckusick if (signal(SIGTRAP, SIG_IGN) != SIG_IGN) 23755288Sbostic signal(SIGTRAP, sig); 23846614Smckusick if (signal(SIGFPE, SIG_IGN) != SIG_IGN) 23955288Sbostic signal(SIGFPE, sig); 24046614Smckusick if (signal(SIGBUS, SIG_IGN) != SIG_IGN) 24155288Sbostic signal(SIGBUS, sig); 24246614Smckusick if (signal(SIGSEGV, SIG_IGN) != SIG_IGN) 24355288Sbostic signal(SIGSEGV, sig); 24446614Smckusick if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 24555288Sbostic signal(SIGTERM, sig); 2461423Sroot if (signal(SIGINT, interrupt) == SIG_IGN) 2471423Sroot signal(SIGINT, SIG_IGN); 2481423Sroot 2491423Sroot set_operators(); /* /etc/group snarfed */ 2501423Sroot getfstab(); /* /etc/fstab snarfed */ 2511423Sroot /* 2521423Sroot * disk can be either the full special file name, 2531423Sroot * the suffix of the special file name, 2541423Sroot * the special name missing the leading '/', 2551423Sroot * the file system name with or without the leading '/'. 2561423Sroot */ 2571423Sroot dt = fstabsearch(disk); 25859926Storek if (dt != NULL) { 2591423Sroot disk = rawname(dt->fs_spec); 26059926Storek (void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN); 26159926Storek (void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN); 26229900Smckusick } else { 26359926Storek (void)strncpy(spcl.c_dev, disk, NAMELEN); 26459926Storek (void)strncpy(spcl.c_filesys, "an unlisted file system", 26554042Smckusick NAMELEN); 26629900Smckusick } 26759926Storek (void)strcpy(spcl.c_label, "none"); 26859926Storek (void)gethostname(spcl.c_host, NAMELEN); 26946794Smckusick spcl.c_level = level - '0'; 27029900Smckusick spcl.c_type = TS_TAPE; 27154042Smckusick if (!Tflag) 27254042Smckusick getdumptime(); /* /etc/dumpdates snarfed */ 2731423Sroot 27446794Smckusick msg("Date of this level %c dump: %s", level, 27546794Smckusick spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date)); 27646794Smckusick msg("Date of last level %c dump: %s", lastlevel, 27746794Smckusick spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate)); 2781423Sroot msg("Dumping %s ", disk); 27959926Storek if (dt != NULL) 2801423Sroot msgtail("(%s) ", dt->fs_file); 28150495Smckusick if (host) 28250495Smckusick msgtail("to %s on host %s\n", tape, host); 28350495Smckusick else 28450495Smckusick msgtail("to %s\n", tape); 2851423Sroot 28646794Smckusick if ((diskfd = open(disk, O_RDONLY)) < 0) { 2871423Sroot msg("Cannot open %s\n", disk); 28859926Storek exit(X_ABORT); 2891423Sroot } 29046794Smckusick sync(); 29154042Smckusick sblock = (struct fs *)sblock_buf; 29254042Smckusick bread(SBOFF, (char *) sblock, SBSIZE); 29346586Storek if (sblock->fs_magic != FS_MAGIC) 29446586Storek quit("bad sblock magic number\n"); 29530560Smckusick dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1); 29646586Storek dev_bshift = ffs(dev_bsize) - 1; 29746586Storek if (dev_bsize != (1 << dev_bshift)) 29846586Storek quit("dev_bsize (%d) is not a power of 2", dev_bsize); 29946586Storek tp_bshift = ffs(TP_BSIZE) - 1; 30046586Storek if (TP_BSIZE != (1 << tp_bshift)) 30146586Storek quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE); 30257725Smckusick #ifdef FS_44INODEFMT 30354165Smckusick if (sblock->fs_inodefmt >= FS_44INODEFMT) 30454165Smckusick spcl.c_flags |= DR_NEWINODEFMT; 30557725Smckusick #endif 30659926Storek maxino = sblock->fs_ipg * sblock->fs_ncg; 30759926Storek mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE); 30854042Smckusick usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 30954042Smckusick dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char)); 31054042Smckusick dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 31146794Smckusick tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 3121423Sroot 31359926Storek nonodump = spcl.c_level < honorlevel; 31459926Storek 3151423Sroot msg("mapping (Pass I) [regular files]\n"); 31646794Smckusick anydirskipped = mapfiles(maxino, &tapesize); 3171423Sroot 31846794Smckusick msg("mapping (Pass II) [directories]\n"); 31946794Smckusick while (anydirskipped) { 32046794Smckusick anydirskipped = mapdirs(maxino, &tapesize); 32146794Smckusick } 3221423Sroot 32359926Storek if (pipeout) { 32446794Smckusick tapesize += 10; /* 10 trailer blocks */ 32559926Storek msg("estimated %ld tape blocks.\n", tapesize); 32659926Storek } else { 32759926Storek double fetapes; 32859926Storek 32946614Smckusick if (blocksperfile) 33059926Storek fetapes = (double) tapesize / blocksperfile; 33146614Smckusick else if (cartridge) { 33246614Smckusick /* Estimate number of tapes, assuming streaming stops at 33346614Smckusick the end of each block written, and not in mid-block. 33446614Smckusick Assume no erroneous blocks; this can be compensated 33546614Smckusick for with an artificially low tape size. */ 33646614Smckusick fetapes = 33746794Smckusick ( tapesize /* blocks */ 33846614Smckusick * TP_BSIZE /* bytes/block */ 33946614Smckusick * (1.0/density) /* 0.1" / byte */ 34046614Smckusick + 34146794Smckusick tapesize /* blocks */ 34246614Smckusick * (1.0/ntrec) /* streaming-stops per block */ 34346614Smckusick * 15.48 /* 0.1" / streaming-stop */ 34446614Smckusick ) * (1.0 / tsize ); /* tape / 0.1" */ 34546614Smckusick } else { 34646614Smckusick /* Estimate number of tapes, for old fashioned 9-track 34746614Smckusick tape */ 34846614Smckusick int tenthsperirg = (density == 625) ? 3 : 7; 34946614Smckusick fetapes = 35046794Smckusick ( tapesize /* blocks */ 35146614Smckusick * TP_BSIZE /* bytes / block */ 35246614Smckusick * (1.0/density) /* 0.1" / byte */ 35346614Smckusick + 35446794Smckusick tapesize /* blocks */ 35546614Smckusick * (1.0/ntrec) /* IRG's / block */ 35646614Smckusick * tenthsperirg /* 0.1" / IRG */ 35746614Smckusick ) * (1.0 / tsize ); /* tape / 0.1" */ 35846614Smckusick } 35946614Smckusick etapes = fetapes; /* truncating assignment */ 36046614Smckusick etapes++; 36146794Smckusick /* count the dumped inodes map on each additional tape */ 36246794Smckusick tapesize += (etapes - 1) * 36346794Smckusick (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 36446794Smckusick tapesize += etapes + 10; /* headers + 10 trailer blks */ 36546614Smckusick msg("estimated %ld tape blocks on %3.2f tape(s).\n", 36646794Smckusick tapesize, fetapes); 36759926Storek } 3681423Sroot 36954042Smckusick /* 37059926Storek * Allocate tape buffer. 37154042Smckusick */ 37254042Smckusick if (!alloctape()) 37354042Smckusick quit("can't allocate tape buffers - try a smaller blocking factor.\n"); 37410910Ssam 37550495Smckusick startnewtape(1); 37659926Storek (void)time((time_t *)&(tstart_writing)); 37759926Storek dumpmap(usedinomap, TS_CLRI, maxino - 1); 3781423Sroot 3791423Sroot msg("dumping (Pass III) [directories]\n"); 38059926Storek dirty = 0; /* XXX just to get gcc to shut up */ 38159926Storek for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 38259926Storek if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 38347058Smckusick dirty = *map++; 38446794Smckusick else 38547058Smckusick dirty >>= 1; 38647058Smckusick if ((dirty & 1) == 0) 38746794Smckusick continue; 38846794Smckusick /* 38946794Smckusick * Skip directory inodes deleted and maybe reallocated 39046794Smckusick */ 39146794Smckusick dp = getino(ino); 39246794Smckusick if ((dp->di_mode & IFMT) != IFDIR) 39346794Smckusick continue; 39459926Storek (void)dumpino(dp, ino); 39546794Smckusick } 3961423Sroot 3971423Sroot msg("dumping (Pass IV) [regular files]\n"); 39859926Storek for (map = dumpinomap, ino = 1; ino < maxino; ino++) { 39957725Smckusick int mode; 40057725Smckusick 40159926Storek if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 40247058Smckusick dirty = *map++; 40346794Smckusick else 40447058Smckusick dirty >>= 1; 40547058Smckusick if ((dirty & 1) == 0) 40646794Smckusick continue; 40746794Smckusick /* 40846794Smckusick * Skip inodes deleted and reallocated as directories. 40946794Smckusick */ 41046794Smckusick dp = getino(ino); 41157725Smckusick mode = dp->di_mode & IFMT; 41257725Smckusick if (mode == IFDIR) 41346794Smckusick continue; 41459926Storek (void)dumpino(dp, ino); 41546794Smckusick } 4161423Sroot 4171423Sroot spcl.c_type = TS_END; 41846794Smckusick for (i = 0; i < ntrec; i++) 41959926Storek writeheader(maxino - 1); 42046614Smckusick if (pipeout) 42146614Smckusick msg("DUMP: %ld tape blocks\n",spcl.c_tapea); 42246614Smckusick else 42346614Smckusick msg("DUMP: %ld tape blocks on %d volumes(s)\n", 42446614Smckusick spcl.c_tapea, spcl.c_volume); 42546794Smckusick putdumptime(); 42646239Storek trewind(); 4271423Sroot broadcast("DUMP IS DONE!\7\7\n"); 42850495Smckusick msg("DUMP IS DONE\n"); 4291423Sroot Exit(X_FINOK); 43046586Storek /* NOTREACHED */ 4311423Sroot } 4321423Sroot 43359926Storek /* 43459926Storek * Pick up a numeric argument. It must be nonnegative and in the given 43559926Storek * range (except that a vmax of 0 means unlimited). 43659926Storek */ 43759926Storek static long 43859926Storek numarg(letter, meaning, vmin, vmax, pargc, pargv) 43959926Storek int letter; 44059926Storek char *meaning; 44159926Storek long vmin, vmax; 44259926Storek int *pargc; 44359926Storek char ***pargv; 44459926Storek { 44559926Storek register char *p; 44659926Storek long val; 44759926Storek char *str; 44859926Storek 44959926Storek if (--*pargc < 0) 45059926Storek missingarg(letter, meaning); 45159926Storek str = *(*pargv)++; 45259926Storek for (p = str; *p; p++) 45359926Storek if (!isdigit(*p)) 45459926Storek goto bad; 45559926Storek val = atol(str); 45659926Storek if (val < vmin || (vmax && val > vmax)) 45759926Storek goto bad; 45859926Storek return (val); 45959926Storek 46059926Storek bad: 46159926Storek (void)fprintf(stderr, "bad '%c' (%s) value \"%s\"\n", 46259926Storek letter, meaning, str); 46359926Storek exit(X_ABORT); 46459926Storek } 46559926Storek 46659926Storek static __dead void 46759926Storek missingarg(letter, meaning) 46859926Storek int letter; 46959926Storek char *meaning; 47059926Storek { 47159926Storek 47259926Storek (void)fprintf(stderr, "The '%c' flag (%s) requires an argument\n", 47359926Storek letter, meaning); 47459926Storek exit(X_ABORT); 47559926Storek } 47659926Storek 47746586Storek void 47855288Sbostic sig(signo) 47955288Sbostic int signo; 4801423Sroot { 48155288Sbostic switch(signo) { 48255288Sbostic case SIGALRM: 48355288Sbostic case SIGBUS: 48455288Sbostic case SIGFPE: 48555288Sbostic case SIGHUP: 48655288Sbostic case SIGTERM: 48755288Sbostic case SIGTRAP: 48855288Sbostic if (pipeout) 48955288Sbostic quit("Signal on pipe: cannot recover\n"); 49055288Sbostic msg("Rewriting attempted as response to unknown signal.\n"); 49159926Storek (void)fflush(stderr); 49259926Storek (void)fflush(stdout); 49355288Sbostic close_rewind(); 49457725Smckusick exit(X_REWRITE); 49555288Sbostic /* NOTREACHED */ 49655288Sbostic case SIGSEGV: 49755288Sbostic msg("SIGSEGV: ABORTING!\n"); 49859926Storek (void)signal(SIGSEGV, SIG_DFL); 49959926Storek (void)kill(0, SIGSEGV); 50055288Sbostic /* NOTREACHED */ 50155288Sbostic } 5021423Sroot } 5031423Sroot 50446586Storek char * 50546586Storek rawname(cp) 5061423Sroot char *cp; 5071423Sroot { 50865540Smckusick static char rawbuf[MAXPATHLEN]; 5091423Sroot char *dp = rindex(cp, '/'); 5101423Sroot 51159926Storek if (dp == NULL) 51259926Storek return (NULL); 51359926Storek *dp = '\0'; 51459926Storek (void)strcpy(rawbuf, cp); 5151423Sroot *dp = '/'; 51659926Storek (void)strcat(rawbuf, "/r"); 51759926Storek (void)strcat(rawbuf, dp + 1); 5181423Sroot return (rawbuf); 5191423Sroot } 52050496Smckusick 52150496Smckusick #ifdef sunos 52259926Storek const char * 52350496Smckusick strerror(errnum) 52450496Smckusick int errnum; 52550496Smckusick { 52650496Smckusick extern int sys_nerr; 52759926Storek extern const char *const sys_errlist[]; 52850496Smckusick 52959926Storek if (errnum < sys_nerr) 53059926Storek return (sys_errlist[errnum]); 53159926Storek else 53259926Storek return ("bogus errno in strerror"); 53350496Smckusick } 53450496Smckusick #endif 535