Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site seismo.UUCP Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP Path: seismo!harvard!talcott!panda!genrad!sources-request From: sources-request@genrad.UUCP Newsgroups: mod.sources Subject: mdump - multiple dump per tape utility Message-ID: <1007@genrad.UUCP> Date: 8 Aug 85 12:25:57 GMT Sender: john@genrad.UUCP Lines: 1524 Approved: john@genrad.UUCP Mod.sources: Volume 2, Issue 36 Submitted by: ihnp4!uiucdcs!uiucuxc!paul (Paul Pomes) Mdump and st were written to ease the pain of UNIX backups for our operations staff. It's compressed the clock time needed to run a daily set of backups by almost two thirds. The time savings are due to eliminating most of the tape mounts and waiting for tape rewinds. Listings are generated automatically though they can be suppressed. It's been in use here for about two months in its present form. VAX backups are done on local drives, the Pyramid 90x goes over an Ethernet to the VAX drives. Most of the error recovery code was added because mt commands over the network would sometimes mysteriously disappear. I've thought about alarm() timeouts but haven't come up with a reasonable implementation that wouldn't blow long rewinds out of the water by accident. There's also the fact that it's working reasonably well and six other projects are on the fire. Anyway I think this will be extremely useful for some sites, handy at others, and pretty window dressing at the rest. Paul Pomes UUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul ARPANET: paul%uiucuxc@uiuc.arpa CSNET: paul%uiucuxc@uiuc.csnet ICBM: 40 07 N / 88 13 W US Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # README # Makefile # dumptab.5 # dumptab.c # dumptab.h # etc.dumptab # getdtent.3 # mdump.8 # mdump.c # st.8 # st.c sed 's/^X//' << 'SHAR_EOF' > README XMdump and st together provide a coherent method for organizing multiple Xinstances of dump(8) onto a single magnetic tape volume. X XSeveral assumptions have been made: 1) filesystems are backed up on a Xdaily basis capturing changes made in the last 24 hours or since the Xlast weekly. Weekly tapes capture all changes made since the last Xlevel 0 dump. X XTo install, edit the #defines's in mdump.c to properly reflect the Xdesired commands. The dump command issued via a system() call is Xbuilt in the wrt_dmp() procedure. X XCopy dumptab.h to /usr/include. X XEdit etc.dumptab to reflect the order desired in dumping filesystems Xand the day-of-week for the weekly dump. I recommend putting the Xsmaller filesystems first on the tape. Should the tape volume overflow, Xa smaller number of individual tapes will be needed to dump the Xremaining filesystems. X XCopy etc.dumptab to /etc/dumptab. X XRun "make", then "make install". X X Paul Pomes X XUUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul XARPANET: paul%uiucuxc@uiuc.arpa XCSNET: paul%uiucuxc@uiuc.csnet XICBM: 40 07 N / 88 13 W XUS Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > Makefile X# Makefile for mdump, a utility for putting multiple dump files onto a X# single tape volume. X# X# Written by Paul Pomes, University of Illinois, Computing Services Office X# Copyright 1985 by Paul Pomes and University of Illinois Board of Trustees X# X# This program may be freely reproduced and distributed provided the X# copyright above is included in all copies. It may not be included X# in any software product or distribution sold for profit without the X# permission of the author. X# X# UUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul X# ARPANET: paul%uiucuxc@uiuc.arpa X# CSNET: paul%uiucuxc@uiuc.csnet X# US Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 X# X# $Header: Makefile,v 1.1 85/07/02 13:47:16 root Exp $ X XCFLAGS= -O XLDFLAGS= X Xall: mdump st X Xmdump: mdump.o dumptab.o X cc mdump.o dumptab.o -o mdump ${LDFLAGS} X Xst: st.o dumptab.o X cc st.o dumptab.o -o st X Xclean: X rm -f *.o mdump st make.log lint.out a.out X Xlint: X lint -habcx mdump.c dumptab.c X lint -habcx st.c dumptab.c X Xinstall: mdump st X install -s mdump /etc X install -s st /etc X cp mdump.8 /usr/man/manl/mdump.l X cp dumptab.5 /usr/man/manl/dumptab.l X cp getdtent.3 /usr/man/manl/getdtent.l X cp st.8 /usr/man/manl/st.l X Xdumptab.o: dumptab.c dumptab.h X cc ${CFLAGS} -c dumptab.c X Xmdump.o: mdump.c dumptab.h X cc ${CFLAGS} -c mdump.c X Xst.o: st.c dumptab.h X cc ${CFLAGS} -c st.c SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > dumptab.5 X.TH DUMPTAB 5 "UofI CSO" X.SH NAME Xdumptab \- multiple dump per tape description file X.SH DESCRIPTION X.I Dumptab Xcontains for each filesystem the Xfollowing information: X.HP 10 Xname (filesystem name, contains no upper case) X.br X.ns X.HP 10 Xtape file position (1 to n) X.br X.ns X.HP 10 Xday of weekly backup (Sunday = 0) X.br X.ns Xdescriptive comment X.PP XThis is an ASCII file. Each field within each filesystem's entry Xis separated from the next by a colon. XEach filesystem is separated from the next by a new-line. X.PP X.I Dumptab Xis used by X.IR mdump (8) Xand X.IR st (8) Xto define the order and backup schedule of filesystems. X.SH FILES X/etc/dumptab X.SH "SEE ALSO" Xgetdtent(3), mdump(8), st(8) X.SH BUGS XIt's not clear this is the best approach, however it was the fastest to Ximplement. SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > dumptab.c X/* X * dumptab -- read the dumptab file X * X * Dumptab provides a set of routines similar in spirit to getpwent(3). X * getdtent() returns a pointer to a dumptab entry, getdtnam(name) returns X * a dumptab entry pointer for the named filesystem, getdtpos(position) X * returns a dumptab entry pointer for the filesystem at the indicated X * tape position, setdtent opens the dumptab file, and enddtent closes it. X * X * Written by Paul Pomes, University of Illinois, Computing Services Office X * Copyright 1985 by Paul Pomes and University of Illinois Board of Trustees X * X * This program may be freely reproduced and distributed provided the X * copyright above is included in all copies. It may not be included X * in any software product or distribution sold for profit without the X * permission of the author. X * X * UUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul X * ARPANET: paul%uiucuxc@uiuc.arpa X * CSNET: paul%uiucuxc@uiuc.csnet X * US Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 X * X * $Log: dumptab.c,v $ X * Revision 1.1 85/07/02 13:47:31 root X * Initial revision X * X */ X X#ifndef lint Xstatic char RcsId[] = "$Header: dumptab.c,v 1.1 85/07/02 13:47:31 root Exp $"; X#endif X X#include X#include X Xstatic char *DUMPTAB = "/etc/dumptab"; Xstatic FILE *dtf = NULL; Xstatic char line[BUFSIZ+1]; Xstatic struct dumptab dumptab; X Xsetdtent() X{ X if (dtf == NULL) X dtf = fopen(DUMPTAB, "r"); X else X rewind(dtf); X} X Xenddtent() X{ X if (dtf != NULL) { X (void) fclose(dtf); X dtf = NULL; X } X} X Xstatic char * Xdtskip(p) Xregister char *p; X{ X while (*p && *p != ':' && *p != '\n') X p++; X if (*p) X *p++ = 0; X return(p); X} X Xstruct dumptab * Xgetdtent() X{ X register char *p; X X if (dtf == NULL) { X if ((dtf = fopen( DUMPTAB, "r" )) == NULL) X return(0); X } X p = fgets(line, BUFSIZ, dtf); X if (p == NULL) X return(0); X dumptab.dt_name = p; X p = dtskip(p); X dumptab.dt_position = atoi(p); X p = dtskip(p); X dumptab.dt_weekly = atoi(p); X p = dtskip(p); X dumptab.dt_comment = p; X while (*p && *p != '\n') X p++; X *p = '\0'; X return(&dumptab); X} X Xstruct dumptab * Xgetdtpos(num) Xregister num; X{ X register struct dumptab *p; X X setdtent(); X while ((p = getdtent()) && p->dt_position != num) X ; X enddtent(); X return(p); X} X Xsetdtfile(file) Xchar *file; X{ X DUMPTAB = file; X} X Xstruct dumptab * Xgetdtnam(name) Xchar *name; X{ X register struct dumptab *p; X X setdtent(); X while ((p = getdtent()) && strcmp(name, p->dt_name)) X ; X enddtent(); X return(p); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > dumptab.h X/* $Header: dumptab.h,v 1.1 85/07/02 13:48:41 root Exp $ */ X Xstruct dumptab { X char *dt_name; X int dt_position; /* 1 to n */ X int dt_weekly; /* Sunday = 0, Saturday = 6 */ X char *dt_comment; /* other information */ X}; X Xstruct dumptab *getdtent(), *getdtnam(), *getdtpos(); SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > etc.dumptab X/etc/dumptab:0:0:This file must be at position 0 as tape catalogue X/:1:2:The root filesystem, weekly dumped on Tuesday X/mnt:2:2: X/pub:3:5: X/cerlsys:4:1: X/cerl:5:3: X/acct:6:4:acct weekly dumped on Thursday, uses a new tape every month X/misc:7:4: X/srl:8:4: X/usr/spool:9:2: X/usr/src:10:3: X/irm:11:5: SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > getdtent.3 X.TH GETTDENT 3 "UofI CSO" X.SH NAME Xgetdtent, getdtnam, setdtent, enddtent \- get dumptab file entry X.SH SYNOPSIS X.nf X.B #include X.PP X.B struct passwd *getdtent() X.PP X.B struct passwd *getdtnam(name) X.B char *name; X.PP X.B struct passwd *getdtpos(position) X.B int position; X.PP X.B int setdtent() X.PP X.B int enddtent() X.fi X.SH DESCRIPTION X.IR Getdtent , X.IR getdtnam , Xand X.I getdtpos Xeach return a pointer to an object with the following structure Xcontaining the broken-out fields of a line in the dumptab file. X.RS X.PP X.nf X.so /usr/include/dumptab.h X.ft R X.ad X.fi X.RE X.PP X.I Getdtent Xreads the next line (opening the file if necessary); X.I setdtent Xrewinds the file; X.I enddtent Xcloses it. X.PP X.I Getdtnam Xsearches from the beginning until a matching X.I name Xis found (or until EOF is encountered). X.PP X.I Getdtpos Xsearches from the beginning until a matching X.I position X(file number on a tape volume) is found (or until EOF is encountered). X.SH FILES X/etc/dumptab X.SH "SEE ALSO" Xdumptab(5) X.SH DIAGNOSTICS XNull pointer X(0) returned on EOF or error. X.SH BUGS XAll information is contained in a static area so it must be copied if it is Xto be saved. SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > mdump.8 X.TH MDUMP 8 "UofI CSO" X.SH NAME Xmdump \- multiple dump per tape utility X.SH SYNOPSIS X.B mdump X[ X.B \-w X] [ X.B \-d X] [ X.B \-l X] [ X.B \-e X] [ X\fB\-t \fIday-of-week\fR X] [ X\fB\-f \fI[host:]/dev/rmtx\fR X] X.SH DESCRIPTION X.I Mdump Xsimplifies the backup procedure for systems with multiple filesystems Xby putting all daily and/or weekly backups onto a single tape. X.PP XThe order and selection of filesystems to be dumped is determined by X.I /etc/dumptab Xand by the options X.B \-w Xand X.BR \-d . X.B \-w Xselects filesystems scheduled for weekly backup today while X.B \-d Xselects filesystems scheduled for daily backup. XSpecifying both switches causes daily and weekly backups to be selected. XA null file is inserted on the tape for non-selected filesystems Xto preserve file ordering. XThe X.IR st (8) Xcommand (set tape) will position the backup tape to the correct tape Xfile for restores. X.PP XThe backup device is selected with the X.B \-f Xoption. XRemote backup over the network is accomplished by specifying the device Xname in the same manner as X.IR rdump (8), Xe.g., uiucuxc:/dev/rmt0. X.PP XAfter X.I mdump Xhas finished writing the dump files, Xa listing of each dump will be created and sent to the \s-1IBM\s0 printers Xunless the X.B \-l Xoption is given to suppress the listings. X.PP XIn the case of positioning errors during the listing phase of X.IR mdump , Xhanging rsh commands are the usual cause, X.B \-e Xwill execute the listing phase of X.I mdump Xonly. XAt least one of the flags X.B \-d Xand/or X.B \-w Xmust be specified in addition to the X.B \-e Xflag. X.PP XTo run X.I mdump Xas though it were a different day of the week, e.g., Xcreate or list a Monday tape on Wednesday, the X\fB\-t \fIday-of-week\fR Xflag is supplied where X.I day-of-week Xis one of mon, tue, wed, etc. X.SH NOTES XIn the case where X.I mdump Xfound no files to dump, Xthe subsequent listing phase will complain that Xit "Cannot find file dump list". X.I Mdump Xwill print a message saying that the list command exitted abnormally Xand ask whether to continue. XEntering 'y' directs X.I mdump Xto continue listing the other filesystems. XAny other response causes an exit. X.SH FILES X/etc/dumptab, /etc/dump X.SH "SEE ALSO" Xdumptab(5), dump(8), rdump(8), st(8) X.SH BUGS XIt's not clear this is the best approach, however it was the fastest to Ximplement. X.PP XNo provision is made for tape overflow. This is an incentive to use 6250 Xbpi drives. X.PP XAny tape error means restarting X.I mdump Xfrom the beginning. SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > mdump.c X/* X * mdump -- put daily/weekly backups onto a single tape X * X * Mdump simplifies the tedious process of daily and weekly backups by X * putting all daily backups onto a single tape. Weekly backups are X * performed the same way. The /etc/dumptab file defines the file X * position on the tape each filesystem is written at and the day of X * the week the weekly backup is done. Filesystems that are scheduled X * for a weekly backup are marked with an empty file on the daily tape X * so that file numbering remains constant. X * X * usage: mdump [-d] [-w] [-l] [-e] [-t day] [-f [host:]/dev/rmtx] [-db] X * X * -d write a daily backup tape X * X * -w write a weekly backup tape X * X * -l suppress generation of the listing file X * X * -e run listing code after an error exit X * X * -t day run mdump for day (sun - sat) instead of today X * X * -f [host:]/dev/rmtx tape device name. If the host: prefix X * is used, the backup tape will be written over the network to X * the tape drive on the named host. X * X * -db Write debug information to stderr X * X * Written by Paul Pomes, University of Illinois, Computing Services Office. X * Copyright 1985 by Paul Pomes and University of Illinois Board of Trustees X * X * This program may be freely reproduced and distributed provided the X * copyright notice above is included in all copies. It may not be X * included in any software product or distribution sold for profit X * without the permission of the author. X * X * UUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul X * ARPANET: paul%uiucuxc@uiuc.arpa X * CSNET: paul%uiucuxc@uiuc.csnet X * ICBM: 40 07 N / 88 13 W X * US Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 X * X * $Log: mdump.c,v $ X * Revision 1.7 85/08/07 16:30:08 paul X * Added bare-bones System 5 defines (index -> strchr, etc). Large hacks X * needed to do the same for the mag tape ioctls. Another day, far away. X * X * Revision 1.6 85/08/07 16:03:57 root X * Added n switch to dump command so that operators are notified. X * Extremely effective annoyance feature. -pbp X * X * Revision 1.5 85/07/11 14:44:07 paul X * Added recovery question for restore listings of filesystems with no files. X * pbp X * X * Revision 1.4 85/07/09 21:18:09 root X * *** empty log message *** X * X * Revision 1.3 85/07/05 17:13:39 root X * Added -t day-of-week flag for enhanced error recovery. -pbp X * X * Revision 1.2 85/07/03 23:23:04 root X * Added -e flag to force listings after "rsh mt" errors. -pbp X * X * Revision 1.1 85/07/02 13:47:46 root X * Initial revision X */ X X#ifndef lint Xstatic char RcsId[] = "$Header: mdump.c,v 1.7 85/08/07 16:30:08 paul Exp $"; X#endif X X#include X#ifdef SYS5 X#include X#define index strchr X#define rindex strrchr X#else X#include X#endif X#include X#include X#include X#include X#include X#include X#include X X#define equal(s1, s2) (strcmp(s1, s2) == 0) X X/* default output devices */ X#define DEF_DEV "/dev/rmt0" X#define DEF_NRDEV "/dev/nrmt0" X X/* dumptab file. must be the same as referenced by getdtent() functions */ X#define DUMPTAB "/etc/dumptab" X X/* temp file for listings */ X#define DLIST "/tmp/mdumpXXXXXX" X X/* maximum number of filesystems */ X#define MAX_FS 30 X X/* size of shorter strings, e.g., host[] */ X#define SSTR_SIZE 12 X X/* size of longer strings, e.g., command[] */ X#define LSTR_SIZE 160 X X/* command for generating and formatting listings. X * arguments in order are: host, ':' (if host defined, ' ' otherwise), X * nrdevice, myname, dt->dt_name, list_file. don't delete the leading X * blank as a remote restore replaces that with an 'r'. X */ X#define LST_CMD " restore tf %s%c%s | sort +1 | pr -3 -w132 -f -h \"%s Dump Listing of %s\" >> %s" X X/* listing file print command. arguments are myname and list_file */ X#define PRT_CMD "ibmprint -f -h \"%s Dlist\" %s" /* vax */ X/* #define PRT_CMD "lpr -r -s -J %s_Dlist %s" /* pyramid */ X X/* command to copy the /etc/dumptab file to the tape device. arguments X * to DD_CMD are DUMPTAB and nrdevice. for the remote command an rcp and X * rsh command are used. arguments to RDD_CMD are DUMPTAB, host, host, X * nrdevice. X */ X#define DD_CMD "dd if=%s of=%s bs=512" X#define RDD_CMD "rcp %s %s:/tmp/xyzzy.mdump; rsh %s \"dd if=/tmp/xyzzy.mdump of=%s bs=512; rm /tmp/xyzzy.mdump\"" X X/* copy of argv[0] for error messages */ Xchar *self; X X/* resident host name */ Xchar myname[SSTR_SIZE]; X X/* debug messages printed if set */ Xint debug; X X/* run listing code only */ Xint elist; X X/* state table of tape files. if dump_state[0] is set, then there's a dump X * file there. If zero, there's a tape mark on the tape instead. If -1 X * then EOT has been reached or some other dump(8) error. Typical usage X * would be dump_state[dt->dt_position]. X */ Xint dump_state[MAX_FS]; X X/* mag tape stuff */ Xstruct mt_cmds { X char *c_name; X int c_code; X int c_ronly; X} com[] = { X { "eof", MTWEOF, 0 }, X { "fsf", MTFSF, 1 }, X { "bsf", MTBSF, 1 }, X { "rew", MTREW, 1 }, X { 0 } X}; X Xextern time_t time(); X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X /* a useful counter */ X int i; X X /* weekly or daily backups (can be both) */ X int weekly, daily; X X /* create a compact listing if set */ X int dlist; X X /* run mdump for day argument instead of today of set */ X char newday[4]; X X /* listing file */ X char *list_file = DLIST; X X /* backup device */ X char *device, *nrdevice; X X /* host machine */ X char host[SSTR_SIZE]; X X /* time stuff */ X struct tm *tm; X time_t clock; X X /* dumptab info */ X struct dumptab *dt; X X /* library routines */ X char *malloc(), *mktemp(); X X /* routine to set new tm->tm_wday value for -t argument */ X struct tm *setday(); X X /* squirrel a copy of *argv[0] away for use in error messages */ X self = malloc((unsigned) (strlen(*argv) + 1)); X (void) strcpy(self, *argv); X X dlist = 1; X weekly = daily = 0; X newday[0] = host[0] = '\0'; X device = DEF_DEV; X nrdevice = DEF_NRDEV; X (void) gethostname(myname, SSTR_SIZE-1); X /* X * parse arguments X */ X i = 1; X while (i < argc && *argv[i] == '-') { X if (equal(argv[i]+1, "db")) { X /* db - set debug level */ X debug++; X i++; X fprintf(stderr, "%s: debug option enabled\n", self); X } X else if (equal(argv[i]+1, "d")) { X /* d - daily backups */ X daily++; X i++; X } X else if (equal(argv[i]+1, "w")) { X /* w - weekly backups */ X weekly++; X i++; X } X else if (equal(argv[i]+1, "l")) { X /* l - suppress listings of files */ X dlist = 0; X i++; X } X else if (equal(argv[i]+1, "e")) { X /* e - run listing code only */ X printf("Listings only - nothing will be written to tape\n"); X elist++; X i++; X } X else if (equal(argv[i]+1, "t")) { X /* t - read new dump day-of-week from next argument */ X i++; X (void) strncpy(newday, argv[i], 3); X i++; X } X else if (equal(argv[i]+1, "f")) X { X /* X * f - read backup device from next argument X * turn /dev/rmt names into /dev/nrmt X */ X char temp[40], *p1, *p2; X X i++; X p2 = (char *) NULL; X if ((p1 = index(argv[i], ':')) != 0) { X (void) strncpy(host, argv[i], p1-argv[i]+1); X *(index(host, ':')) = '\0'; X p1++; X } X if (p1 == 0) X p1 = argv[i]; X device = malloc((unsigned) (strlen(p1) + 1)); X (void) strcpy(device, p1); X if ((p2 = rindex(argv[i], '/')) == 0) { X fprintf(stderr, "%s: Output device must be a tape drive, e.g., /dev/rmt1, uxc:/dev/rmt2\n", self); X exit(1); X } X p2++; X (void) strncpy(temp, p1, p2-p1); X *(temp + (p2-p1)) = '\0'; X nrdevice = malloc((unsigned) (strlen(argv[i])+2)); X if (*p2 == 'n') X (void) sprintf(nrdevice, "%s%s", temp, p2); X else X (void) sprintf(nrdevice, "%sn%s", temp, p2); X if (debug) X fprintf(stderr, "host %s, device %s, nrdevice %s\n", host, device, nrdevice); X i++; X } X else X { X /* command line errors */ X fprintf(stderr, "%s: %s - bad flag\n", self, argv[i]+1); X fprintf(stderr, "Usage: %s [-d] [-w] [-e] [-l] [-f [host:]/dev/rmtx] [-db]\n", self); X exit(1); X } X } X if (! (weekly || daily)) { X fprintf(stderr, "%s: No action specified.\n\tInvoke %s with at least one of the following: -w, -d\n", self, self); X exit(1); X } X clock = time((time_t *) 0); X if (*newday) X tm = setday(newday); X else X tm = localtime(&clock); X mtio(host, device, "rew"); X wrt_dtinfo(host, nrdevice); X setdtent(); X for (i = 1; (dt = getdtpos(i)); i++) { X if (dt->dt_weekly == tm->tm_wday) { X if (weekly) { X if (wrt_dmp(host, nrdevice, dt, 'w')) X break; X } X else X wrt_dummy(host, nrdevice, dt); X } X else { X if (daily) { X if (wrt_dmp(host, nrdevice, dt, 'd')) X break; X } X else X wrt_dummy(host, nrdevice, dt); X } X } X /* write the last EOF to form EOT and rewind the tape X * by using the rewind-on-close device. X */ X if (! elist) { X printf("Really rewinding tape\n"); X mtio(host, device, "eof"); X } X if (dlist) { X char command[LSTR_SIZE]; X X (void) mktemp(list_file); X mtio(host, device, "rew"); X X /* skip over the zero'th file of /etc/dumptab */ X mtio(host, nrdevice, "fsf"); X setdtent(); X for (i = 1; (dt = getdtpos(i)); i++) X if (list_tape(host, nrdevice, dt, list_file)) X break; X (void) sprintf(command, PRT_CMD, myname, list_file); X if (debug) X fprintf(stderr, "print command: %s\n", command); X if (i = (system(command) >> 8)) X fprintf(stderr, "%s: %s exitted abnormally (%d).\n", self, command, i); X printf("Last rewind of tape\n"); X mtio(host, device, "rew"); X } X exit(0); X} X X/* X * mtio -- perform a local/remote tape operation X * X * for local tapes (host[0] == '\0') use the ioctl calls. X * remote tapes use an rsh command. X * X * parameters: X * host (IN) -- name of remote host, if host[0] != '\0' X * dev (IN) -- tape drive name X * cp (IN) -- tape opcode X * returns: X * none X * side effects: X * none X * deficiencies: X * any error causes an error exit from the program X */ Xmtio(host, dev, cp) Xchar *host, *dev, *cp; X{ X struct mt_cmds *comp; X X /* tape file descriptor */ X int mtfd; X X /* return code from system() call */ X int status; X X /* from sys/mtio.h */ X struct mtop mt_com; X X /* buffer for rsh command */ X char command[LSTR_SIZE]; X X if (*host == '\0') { X for (comp = com; comp->c_name != NULL; comp++) X if (strncmp(cp, comp->c_name, strlen(cp)) == 0) X break; X if (comp->c_name == NULL) { X fprintf(stderr, "%s: mtio: don't grok \"%s\"\n", self, cp); X exit(1); X } X if ((mtfd = open(dev, comp->c_ronly ? 0 : 2)) < 0) { X fprintf(stderr, "%s: mtio: open of ", self); X perror(dev); X exit(1); X } X mt_com.mt_op = comp->c_code; X mt_com.mt_count = 1; X if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) { X fprintf(stderr, "%s: mtio: %s %s %d ", self, dev, X comp->c_name, mt_com.mt_count); X perror("failed"); X exit(1); X } X (void) close(mtfd); X } X else { X (void) strcpy(command, "rsh "); X (void) strcat(command, host); X (void) strcat(command, " mt -t "); X (void) strcat(command, dev); X (void) strcat(command, " "); X (void) strcat(command, cp); X if (debug) X fprintf(stderr, "tape command %s\n", command); X if (status = (system(command) >> 8)) { X fprintf(stderr, "%s: %s exitted abnormally (%d). Restart %s\n", self, command, status, self); X exit(1); X } X } X} X X/* X * wrt_dmp -- write a filesystem dump on the dump tape X * X * for local tapes (host[0] == '\0') use dump X * remote tapes use rdump X * X * parameters: X * host (IN) -- name of remote host, if host[0] != '\0' X * dev (IN) -- tape drive name X * dt (IN) -- dumptab pointer X * type (IN) -- weekly or daily dump X * returns: X * 0 if dump command successful, 1 if not X * side effects: X * alters dump_state table X * deficiencies: X * any error causes an error exit from the program X */ Xwrt_dmp(host, dev, dt, type) Xchar *host, *dev, type; Xstruct dumptab *dt; X{ X char command[LSTR_SIZE]; X int status; X X if (elist) { X dump_state[dt->dt_position] = 1; X return(0); X } X (void) strcpy(command, " dump nu"); X switch (type) { X case 'd': X (void) strcat(command, "5"); X break; X case 'w': X (void) strcat(command, "4"); X break; X default: X fprintf(stderr, "%s: unknown dump type %c\n", self, type); X exit(1); X } X (void) strcat(command, "f "); X if (*host != '\0') { X command[0] = 'r'; X (void) strcat(command, host); X (void) strcat(command, ":"); X } X (void) strcat(command, dev); X (void) strcat(command, " "); X (void) strcat(command, dt->dt_name); X if (debug) X fprintf(stderr, "dump command %s\n", command); X printf("Dumping %s\n", dt->dt_name); X X /* dump(8) exits with 1 if all is well */ X if ((status = (system(command) >> 8)) != 1) { X fprintf(stderr, "%s: %s exitted abnormally (%d).\n", self, command, status); X fprintf(stderr, "\tTape will rewind and create listings of the successful dumps.\n"); X dump_state[dt->dt_position] = -1; X mtio(host, dev, "bsf"); X return(1); X } X dump_state[dt->dt_position] = 1; X return(0); X} X X/* X * list_tape -- generate a "restore tf" listing for the current tape file X * X * list_tape creates a command line to be executed by system() and X * re-directs the output to a listing file. X * X * parameters: X * host (IN) -- name of remote host, if host[0] != '\0' X * dev (IN) -- tape drive name X * dt (IN) -- dumptab pointer X * lfile (IN) -- name of listing file X * returns: X * 0 for normal results, 1 if at end of tape X * side effects: X * none X * deficiencies: X * any error causes an error exit from the program X */ Xlist_tape(host, dev, dt, lfile) Xchar *host, *dev, *lfile; Xstruct dumptab *dt; X{ X FILE *fp; X int status; X char command[LSTR_SIZE]; X X if (dump_state[dt->dt_position] == 0) { X /* no file here so write a message on the dump listing */ X if ((fp = fopen(lfile, "a")) == NULL) { X fprintf(stderr, "%s: list_tape ", self); X perror(lfile); X exit(1); X } X fprintf(fp, "\n\n\tNo dump file for %s on this tape.\n\f", X dt->dt_name); X (void) fclose(fp); X /* advance the tape by one tape mark */ X printf("Skipping dummy file for %s\n", dt->dt_name); X mtio(host, dev, "fsf"); X return(0); X } X else if (dump_state[dt->dt_position] == 1) { X /* build the appropriate restore tf command and execute it */ X (void) sprintf(command, LST_CMD, host, (*host ? ':' : ' '), X dev, myname, dt->dt_name, lfile); X if (*host != '\0') X command[0] = 'r'; X if (debug) X fprintf(stderr, "list command %s\n", command); X printf("Listing %s\n", dt->dt_name); X if (status = (system(command) >> 8)) { X char c,d; X X fprintf(stderr, "%s: %s exitted abnormally (%d). Continue? [yn] ", self, command, status); X while ((d = getc(stdin)) != '\n') X c = d; X if (c != 'y') X exit(1); X } X /* advance the tape to end of file */ X mtio(host, dev, "fsf"); X return(0); X } X return(1); X} X X/* X * wrt_dtinfo -- write /etc/dumptab onto the tape X * X * writing a copy of /etc/dumptab onto the tape as file #0 provides X * a catalogue of the tape files and insulates backup volumes from X * changes in /etc/dumptab. Elsewhere on the tape it acts as a X * place holder for a non-selected dump, e.g., daily on a weekly-only X * tape. X * X * parameters: X * host (IN) -- name of remote host X * dev (IN) -- tape drive name X * returns: X * none X * side effects: X * none X * deficiencies: X * any error causes an error exit from the program X */ Xwrt_dtinfo(host, dev) Xchar *host, *dev; X{ X char command[LSTR_SIZE]; X int status; X X if (elist) X return; X if (*host) X (void) sprintf(command, RDD_CMD, DUMPTAB, host, host, dev); X else X (void) sprintf(command, DD_CMD, DUMPTAB, dev); X printf("Copying %s to tape\n", DUMPTAB); X if (status = (system(command) >> 8)) { X fprintf(stderr, "%s: %s exitted abnormally (%d). Restart %s\n", self, command, status, self); X exit(1); X } X} X X/* X * wrt_dummy -- write a dummy file onto the tape X * X * write a dummy file onto the tape to take the place of a non- X * scheduled backup. this preserves tape order. X * X * parameters: X * host (IN) -- name of remote host X * dev (IN) -- tape drive name X * dt (IN) -- dumptab pointer X * returns: X * none X * side effects: X * alters dump_state table X * deficiencies: X * any error causes an error exit from the program X */ Xwrt_dummy(host, dev, dt) Xchar *host, *dev; Xstruct dumptab *dt; X{ X char command[LSTR_SIZE]; X int status; X X if (elist) X return; X if (*host) X (void) sprintf(command, RDD_CMD, DUMPTAB, host, host, dev); X else X (void) sprintf(command, DD_CMD, DUMPTAB, dev); X printf("Writing place holder file for %s to tape\n", dt->dt_name); X if (status = (system(command) >> 8)) { X fprintf(stderr, "%s: %s exitted abnormally (%d). Restart %s\n", self, command, status, self); X exit(1); X } X} X X/* X * setday -- set tm..tm_wday to value consistent with argument X * X * tm.tm_wday has a legal range of 0 (for Sunday) to 6 (for Saturday). X * day is a three character string ("sun", "mon", etc) used to determine X * the value of tm.tm_wday. X * X * parameters: X * day (IN/OUT) -- day of week string X * returns: X * pointer to static tm struct X * side effects: X * changes day string to all lower case X * deficiencies: X * any error causes an error exit from the program X */ Xstruct tm * Xsetday(day) Xchar *day; X{ X static struct tm mtm; X char *p; X X for (p = day; *p; p++) X if (isupper(*p)) X *p += ('a' - 'A'); X if (equal(day, "sun")) X mtm.tm_wday = 0; X else if (equal(day, "mon")) X mtm.tm_wday = 1; X else if (equal(day, "tue")) X mtm.tm_wday = 2; X else if (equal(day, "wed")) X mtm.tm_wday = 3; X else if (equal(day, "thu")) X mtm.tm_wday = 4; X else if (equal(day, "fri")) X mtm.tm_wday = 5; X else if (equal(day, "sat")) X mtm.tm_wday = 6; X else { X fprintf(stderr, "%s: setday: illegal day of week (%s)\n", self, day); X fprintf(stderr, "\tLegal values are sun, mon, tue, etc.\n"); X exit(1); X } X return(&mtm); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > st.8 X.TH ST 8 "UofI CSO" X.SH NAME Xst \- set mdump tapes to correct file for restores X.SH SYNOPSIS X.B st X[ X\fB\-f \fI[host:]/dev/rmtx\fR X] X.I filesystem X.SH DESCRIPTION X.I St Xpositions tapes created by X.IR mdump (8) Xto the tape file corresponding to X.IR filesystem . XFrom there ordinary commands like X.IR restore (8) Xcan be used to retrieve files, etc. X.PP XThe tape device is selected with the X.B \-f Xoption. XRemote tape reads over the network is accomplished by specifying the device Xname in the same manner as X.IR rdump (8), Xe.g., uiucuxc:/dev/rmt0. X.PP XThe order of filesystems on X.I mdump Xtapes is determined by a copy of X.I /etc/dumptab Xwritten as the first tape file. X.SH FILES X/etc/dumptab X.SH "SEE ALSO" Xdumptab(5), dump(8), mdump(8), rdump(8) X.SH BUGS XIt's not clear this is the best approach, however it was the fastest to Ximplement. SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > st.c X/* X * st -- set tape position on a multi-file dump volume to that of X * the specified filesystem X * X * usage: st [-f [host:]/dev/rmtx] [-db] filesystem X * X * -f [host:]/dev/rmtx tape device name. If the host: prefix X * is used, the backup tape will be addressed over the network to X * the tape drive on the named host. X * X * -db Write debug information to stderr X * X * Written by Paul Pomes, University of Illinois, Computing Services Office X * Copyright 1985 by Paul Pomes and University of Illinois Board of Trustees X * X * This program may be freely reproduced and distributed provided the X * copyright notice above is included in all copies. It may not be X * included in any software product or distribution sold for profit X * without the permission of the author. X * X * UUCP: {ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!paul X * ARPANET: paul%uiucuxc@uiuc.arpa X * CSNET: paul%uiucuxc@uiuc.csnet X * ICBM: 40 07 N / 88 13 W X * US Mail: Univ of Illinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801 X * X * $Log: st.c,v $ X * Revision 1.2 85/07/11 13:27:51 paul X * Updated author information. -pbp X * X * Revision 1.1 85/07/02 13:48:08 root X * Initial revision X * X */ X X#ifndef lint Xstatic char RcsId[] = "$Header: st.c,v 1.2 85/07/11 13:27:51 paul Exp $"; X#endif X X#include X#include X#include X#include X#include X#include X#include X X#define equal(s1, s2) (strcmp(s1, s2) == 0) X X/* default tape devices */ X#define DEF_DEV "/dev/rmt0" X#define DEF_NRDEV "/dev/nrmt0" X X/* size of shorter strings, e.g., host[] */ X#define SSTR_SIZE 12 X X/* size of longer strings, e.g., command[] */ X#define LSTR_SIZE 160 X X/* commands to read the /etc/dumptab file in tape file #0. X * argument to DD_CMD is nrdevice; arguments to RDD_CMD are host, nrdevice, X * and host again. X */ X#define DD_CMD "dd if=%s of=/tmp/xyzzy.mdump bs=512" X#define RDD_CMD "rsh %s dd if=%s of=/tmp/xyzzy.mdump bs=512; rcp %s:/tmp/xyzzy.mdump /tmp/xyzzy.mdump" X X/* copy of argv[0] for error messages */ Xchar *self; X X/* debug messages printed if set */ Xint debug; X X/* mag tape stuff */ Xstruct mt_cmds { X char *c_name; X int c_code; X int c_ronly; X} com[] = { X { "eof", MTWEOF, 0 }, X { "fsf", MTFSF, 1 }, X { "rew", MTREW, 1 }, X { "status", MTNOP, 1 }, X { 0 } X}; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X /* a useful counter */ X int i; X X /* tape device */ X char *device, *nrdevice; X X /* filesystem to position to */ X char *filesys; X X /* host machine */ X char host[SSTR_SIZE]; X X /* dumptab info */ X struct dumptab *dt; X X /* library routines */ X char *malloc(); X X /* squirrel a copy of *argv[0] away for use in error messages */ X self = malloc((unsigned) (strlen(*argv) + 1)); X (void) strcpy(self, *argv); X X host[0] = '\0'; X device = DEF_DEV; X nrdevice = DEF_NRDEV; X /* X * parse arguments X */ X i = 1; X while (i < argc && *argv[i] == '-') { X if (equal(argv[i]+1, "db")) { X /* db - set debug level */ X debug++; X i++; X fprintf(stderr, "%s: debug option enabled\n", self); X } X else if (equal(argv[i]+1, "f")) X { X /* X * f - read tape device from next argument X * turn /dev/rmt names into /dev/nrmt X */ X char temp[40], *p1, *p2; X X i++; X p2 = (char *) NULL; X if ((p1 = index(argv[i], ':')) != 0) { X (void) strncpy(host, argv[i], p1-argv[i]+1); X *(index(host, ':')) = '\0'; X p1++; X } X if (p1 == 0) X p1 = argv[i]; X device = malloc((unsigned) (strlen(p1) + 1)); X (void) strcpy(device, p1); X if ((p2 = rindex(argv[i], '/')) == 0) { X fprintf(stderr, "%s: Device must be a tape drive, e.g., /dev/rmt1, uxc:/dev/rmt2\n", self); X exit(1); X } X p2++; X (void) strncpy(temp, p1, p2-p1); X *(temp + (p2-p1)) = '\0'; X nrdevice = malloc((unsigned) (strlen(argv[i])+2)); X if (*p2 == 'n') X (void) sprintf(nrdevice, "%s%s", temp, p2); X else X (void) sprintf(nrdevice, "%sn%s", temp, p2); X if (debug) X fprintf(stderr, "host %s, device %s, nrdevice %s\n", host, device, nrdevice); X i++; X } X else X { X /* command line errors */ X fprintf(stderr, "%s: %s - bad flag\n", self, argv[i]+1); X Usage: X fprintf(stderr, "Usage: %s [-f [host:]/dev/rmtx] [-db] filesystem\n", self); X exit(1); X } X } X /* last argument is filesystem name */ X if (argv[i] == NULL) { X fprintf(stderr, "%s: No filesystem specified\n", self); X goto Usage; X } X else { X filesys = malloc((unsigned) (strlen(argv[i]) + 1)); X (void) strcpy(filesys, argv[i]); X if (debug) X fprintf(stderr, "filesys %s\n", filesys); X } X read_dtinfo(host, device); X setdtfile("/tmp/xyzzy.mdump"); X setdtent(); X if (dt = getdtnam(filesys)) { X printf("Skipping %d tape files...", dt->dt_position); X (void) fflush(stdout); X for (i = 0; i < dt->dt_position; i++) { X mtio(host, nrdevice, "fsf"); X printf("%d ", i+1); X (void) fflush(stdout); X } X printf("done.\n"); X (void) unlink("/tmp/xyzzy.mdump"); X exit(0); X } X fprintf(stderr, "%s: %s not in tape file #0 (and thus not on tape)\n", X self, filesys); X fprintf(stderr, "\tCopy of tape file #0 in /tmp/xyzzy.mdump\n"); X exit(1); X} X X/* X * mtio -- perform a local/remote tape operation X * X * for local tapes (host[0] == '\0') use the ioctl calls. X * remote tapes use an rsh command. X * X * parameters: X * host (IN) -- name of remote host X * dev (IN) -- tape drive name X * cp (IN) -- tape opcode X * returns: X * none X * side effects: X * none X * deficiencies: X * any error causes an error exit from the program X */ Xmtio(host, dev, cp) Xchar *host, *dev, *cp; X{ X struct mt_cmds *comp; X X /* tape file descriptor */ X int mtfd; X X /* return code from system() call */ X int status; X X /* from sys/mtio.h */ X struct mtop mt_com; X X /* buffer for rsh command */ X char command[LSTR_SIZE]; X X if (*host == '\0') { X for (comp = com; comp->c_name != NULL; comp++) X if (strncmp(cp, comp->c_name, strlen(cp)) == 0) X break; X if (comp->c_name == NULL) { X fprintf(stderr, "%s: mtio: don't grok \"%s\"\n", self, cp); X exit(1); X } X if ((mtfd = open(dev, comp->c_ronly ? 0 : 2)) < 0) { X fprintf(stderr, "%s: mtio: open of ", self); X perror(dev); X exit(1); X } X mt_com.mt_op = comp->c_code; X mt_com.mt_count = 1; X if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) { X fprintf(stderr, "%s: mtio: %s %s %d ", self, dev, X comp->c_name, mt_com.mt_count); X perror("failed"); X exit(1); X } X (void) close(mtfd); X } X else { X (void) strcpy(command, "rsh "); X (void) strcat(command, host); X (void) strcat(command, " mt -t "); X (void) strcat(command, dev); X (void) strcat(command, " "); X (void) strcat(command, cp); X if (debug) X fprintf(stderr, "tape command %s\n", command); X if (status = (system(command) >> 8)) { X fprintf(stderr, "%s: %s exitted abnormally (%d). Restart %s\n", self, command, status, self); X exit(1); X } X } X} X X/* X * read_dtinfo -- copy the dumptab file contained within tape file #0 X * X * the /etc/dumptab file used to create the backup tape volume X * is contained within the first tape file. this routine copies X * it to the magic name of /tmp/xyzzy.mdump on the current host. X * X * parameters: X * host (IN) -- name of remote host X * dev (IN) -- tape drive name X * returns: X * none X * side effects: X * none X * deficiencies: X * any error causes an error exit from the program X */ Xread_dtinfo(host, dev) Xchar *host, *dev; X{ X char command[LSTR_SIZE]; X int status; X X mtio(host, dev, "rew"); X if (*host) X (void) sprintf(command, RDD_CMD, host, dev, host); X else X (void) sprintf(command, DD_CMD, dev); X printf("Reading /etc/dumptab info from first tape file.\n"); X if (status = (system(command) >> 8)) { X fprintf(stderr, "%s: %s exitted abnormally (%d). Restart %s\n", self, command, status, self); X exit(1); X } X} SHAR_EOF exit 0