X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=rmt%2Frmt.c;h=fc8ebce49eec2c95bb89cb7f978ae0f87ac4a077;hp=efe8ea88394e3ac3e9dfb601bf403117dddeaa61;hb=88ac410d747e12ed2c1edd1ed0fdab994de71cf9;hpb=109e9e1d1a904627eeae4d519a0f694795b2892c diff --git a/rmt/rmt.c b/rmt/rmt.c index efe8ea8..fc8ebce 100644 --- a/rmt/rmt.c +++ b/rmt/rmt.c @@ -2,8 +2,8 @@ * Ported to Linux's Second Extended File System as part of the * dump and restore backup suit * Remy Card , 1994-1997 - * Stelian Pop , 1999-2000 - * Stelian Pop - Alcôve , 2000 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 2000-2002 */ /* @@ -41,12 +41,14 @@ #ifndef lint static const char rcsid[] = - "$Id: rmt.c,v 1.11 2000/12/04 15:43:17 stelian Exp $"; + "$Id: rmt.c,v 1.20 2002/05/21 15:48:46 stelian Exp $"; #endif /* not linux */ /* * rmt */ +#include +#include #include #include #include @@ -60,32 +62,70 @@ static const char rcsid[] = #include #include -int tape = -1; +static int tape = -1; -char *record; -int maxrecsize = -1; +static char *record; +static int maxrecsize = -1; #define SSIZE 64 -char device[SSIZE]; -char count[SSIZE], filemode[SSIZE], pos[SSIZE], op[SSIZE]; +static char device[SSIZE]; +static char count[SSIZE], filemode[SSIZE], pos[SSIZE], op[SSIZE]; -char resp[BUFSIZ]; +static char resp[BUFSIZ]; -FILE *debug; +static FILE *debug; #define DEBUG(f) if (debug) fprintf(debug, f) #define DEBUG1(f,a) if (debug) fprintf(debug, f, a) #define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2) +/* + * Support for Sun's extended RMT protocol + * code originally written by Jörg Schilling + * and relicensed by his permission from GPL to BSD for use in dump. + * + * rmt_version is 0 for regular clients (Linux included) + * rmt_version is 1 for extended clients (Sun especially). In this case + * we support some extended commands (see below) and we remap + * the ioctl commands to the UNIX "standard", as per: + * ftp://ftp.fokus.gmd.de/pub/unix/star/README.mtio + * + * In order to use rmt version 1, a client must send "I-1\n0\n" + * before issuing the other I commands. + */ +static int rmt_version = 0; +#define RMTI_VERSION -1 +#define RMT_VERSION 1 + +/* Extended 'i' commands */ +#define RMTI_CACHE 0 +#define RMTI_NOCACHE 1 +#define RMTI_RETEN 2 +#define RMTI_ERASE 3 +#define RMTI_EOM 4 +#define RMTI_NBSF 5 + +/* Extended 's' comands */ +#define MTS_TYPE 'T' +#define MTS_DSREG 'D' +#define MTS_ERREG 'E' +#define MTS_RESID 'R' +#define MTS_FILENO 'F' +#define MTS_BLKNO 'B' +#define MTS_FLAGS 'f' +#define MTS_BF 'b' + char *checkbuf __P((char *, int)); void error __P((int)); void getstring __P((char *)); +int getopenflags __P((char *)); int main(int argc, char *argv[]) { int rval = 0; char c; - int n, i, cc; + int n, i, cc, oflags; + unsigned long block = 0; argc--, argv++; if (argc > 0) { @@ -107,29 +147,43 @@ top: getstring(device); getstring(filemode); DEBUG2("rmtd: O %s %s\n", device, filemode); + /* + * Translate extended GNU syntax into its numeric platform equivalent + */ + oflags = getopenflags(filemode); +#ifdef O_TEXT + /* + * Default to O_BINARY the client may not know that we need it. + */ + if ((oflags & O_TEXT) == 0) + oflags |= O_BINARY; +#endif + DEBUG2("rmtd: O %s %d\n", device, oflags); /* * XXX the rmt protocol does not provide a means to * specify the permission bits; allow rw for everyone, * as modified by the users umask */ - tape = open(device, atoi(filemode), 0666); + tape = OPEN(device, oflags, 0666); if (tape < 0) goto ioerror; + block = 0; goto respond; case 'C': - DEBUG("rmtd: C\n"); + DEBUG1("rmtd: C (%lu blocks)\n", block); getstring(device); /* discard */ if (close(tape) < 0) goto ioerror; tape = -1; + block = 0; goto respond; case 'L': getstring(count); getstring(pos); DEBUG2("rmtd: L %s %s\n", count, pos); - rval = lseek(tape, (off_t)atol(count), atoi(pos)); + rval = LSEEK(tape, (off_t)atol(count), atoi(pos)); if (rval < 0) goto ioerror; goto respond; @@ -137,7 +191,7 @@ top: case 'W': getstring(count); n = atoi(count); - DEBUG1("rmtd: W %s\n", count); + DEBUG2("rmtd: W %s (block = %lu)\n", count, block); record = checkbuf(record, n); for (i = 0; i < n; i += cc) { cc = read(0, &record[i], n - i); @@ -149,11 +203,12 @@ top: rval = write(tape, record, n); if (rval < 0) goto ioerror; + block += n >> 10; goto respond; case 'R': getstring(count); - DEBUG1("rmtd: R %s\n", count); + DEBUG2("rmtd: R %s (block %lu)\n", count, block); n = atoi(count); record = checkbuf(record, n); rval = read(tape, record, n); @@ -162,21 +217,130 @@ top: (void)sprintf(resp, "A%d\n", rval); (void)write(1, resp, strlen(resp)); (void)write(1, record, rval); + block += n >> 10; goto top; case 'I': getstring(op); getstring(count); DEBUG2("rmtd: I %s %s\n", op, count); - { struct mtop mtop; - mtop.mt_op = atoi(op); - mtop.mt_count = atoi(count); - if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0) - goto ioerror; - rval = mtop.mt_count; + if (atoi(op) == RMTI_VERSION) { + rval = RMT_VERSION; + rmt_version = 1; + } + else { + struct mtop mtop; + mtop.mt_op = -1; + if (rmt_version) { + /* rmt version 1, assume UNIX client */ + switch (atoi(op)) { +#ifdef MTWEOF + case 0: + mtop.mt_op = MTWEOF; + break; +#endif +#ifdef MTFSF + case 1: + mtop.mt_op = MTFSF; + break; +#endif +#ifdef MTBSF + case 2: + mtop.mt_op = MTBSF; + break; +#endif +#ifdef MTFSR + case 3: + mtop.mt_op = MTFSR; + break; +#endif +#ifdef MTBSR + case 4: + mtop.mt_op = MTBSR; + break; +#endif +#ifdef MTREW + case 5: + mtop.mt_op = MTREW; + break; +#endif +#ifdef MTOFFL + case 6: + mtop.mt_op = MTOFFL; + break; +#endif +#ifdef MTNOP + case 7: + mtop.mt_op = MTNOP; + break; +#endif + } + if (mtop.mt_op == -1) { + errno = EINVAL; + goto ioerror; + } + } + else { + /* rmt version 0, assume linux client */ + mtop.mt_op = atoi(op); + } + mtop.mt_count = atoi(count); + if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0) + goto ioerror; + rval = mtop.mt_count; } goto respond; + case 'i': + { struct mtop mtop; + + getstring (op); + getstring (count); + DEBUG2 ("rmtd: i %s %s\n", op, count); + switch (atoi(op)) { +#ifdef MTCACHE + case RMTI_CACHE: + mtop.mt_op = MTCACHE; + break; +#endif +#ifdef MTNOCACHE + case RMTI_NOCACHE: + mtop.mt_op = MTNOCACHE; + break; +#endif +#ifdef MTRETEN + case RMTI_RETEN: + mtop.mt_op = MTRETEN; + break; +#endif +#ifdef MTERASE + case RMTI_ERASE: + mtop.mt_op = MTERASE; + break; +#endif +#ifdef MTEOM + case RMTI_EOM: + mtop.mt_op = MTEOM; + break; +#endif +#ifdef MTNBSF + case RMTI_NBSF: + mtop.mt_op = MTNBSF; + break; +#endif + default: + errno = EINVAL; + goto ioerror; + } + mtop.mt_count = atoi (count); + if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0) + goto ioerror; + + rval = mtop.mt_count; + + goto respond; + } + case 'S': /* status */ DEBUG("rmtd: S\n"); { struct mtget mtget; @@ -189,6 +353,49 @@ top: goto top; } + case 's': + { char s; + struct mtget mtget; + + if (read (0, &s, 1) != 1) + goto top; + + if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0) + goto ioerror; + + switch (s) { + case MTS_TYPE: + rval = mtget.mt_type; + break; + case MTS_DSREG: + rval = mtget.mt_dsreg; + break; + case MTS_ERREG: + rval = mtget.mt_erreg; + break; + case MTS_RESID: + rval = mtget.mt_resid; + break; + case MTS_FILENO: + rval = mtget.mt_fileno; + break; + case MTS_BLKNO: + rval = mtget.mt_blkno; + break; + case MTS_FLAGS: + rval = mtget.mt_gstat; + break; + case MTS_BF: + rval = 0; + break; + default: + errno = EINVAL; + goto ioerror; + } + + goto respond; + } + case 'V': /* version */ getstring(op); DEBUG1("rmtd: V %s\n", op); @@ -251,3 +458,96 @@ error(int num) (void)snprintf(resp, sizeof(resp), "E%d\n%s\n", num, strerror(num)); (void)write(1, resp, strlen(resp)); } + +struct openflags { + char *name; + int value; +} openflags[] = { + { "O_RDONLY", O_RDONLY }, + { "O_WRONLY", O_WRONLY }, + { "O_RDWR", O_RDWR }, +#ifdef O_CREAT + { "O_CREAT", O_CREAT }, +#endif +#ifdef O_EXCL + { "O_EXCL", O_EXCL }, +#endif +#ifdef O_NOCTTY + { "O_NOCTTY", O_NOCTTY }, +#endif +#ifdef O_TRUNC + { "O_TRUNC", O_TRUNC }, +#endif +#ifdef O_APPEND + { "O_APPEND", O_APPEND }, +#endif +#ifdef O_NONBLOCK + { "O_NONBLOCK", O_NONBLOCK }, +#endif +#ifdef O_NDELAY + { "O_NDELAY", O_NDELAY }, +#endif +#ifdef O_SYNC + { "O_SYNC", O_SYNC }, +#endif +#ifdef O_FSYNC + { "O_FSYNC", O_FSYNC }, +#endif +#ifdef O_ASYNC + { "O_ASYNC", O_ASYNC }, +#endif +#ifdef O_TEXT + { "O_TEXT", O_TEXT }, +#endif +#ifdef O_DSYNC + { "O_DSYNC", O_DSYNC }, +#endif +#ifdef O_RSYNC + { "O_RSYNC", O_RSYNC }, +#endif +#ifdef O_PRIV + { "O_PRIV", O_PRIV }, +#endif +#ifdef O_LARGEFILE + { "O_LARGEFILE",O_LARGEFILE }, +#endif + { NULL, 0 } +}; + +/* Parts of this stolen again from Jörg Schilling's star package... */ +int +getopenflags(char *filemode) +{ + char *p = filemode; + struct openflags *op; + int result = 0; + + do { + /* skip space */ + while (*p != '\0' && *p == ' ') + p++; + /* get O_XXXX constant */ + if (p[0] != 'O' || p[1] != '_') { + /* numeric syntax detected */ + result = atoi(filemode); + result &= O_RDONLY | O_WRONLY | O_RDWR; + return result; + } + + /* translate O_XXXX constant */ + for (op = openflags; op->name; op++) { + int slen = strlen(op->name); + if ((strncmp(op->name, p, slen) == 0) && + (p[slen] == '|' || p[slen] == ' ' || + p[slen] == '\0')) { + result |= op->value; + break; + } + } + + /* goto next constant */ + p = strchr(p, '|'); + } while (p && *p++ == '|'); + + return result; +}