File: rmtioctl.c

package info (click to toggle)
xfsdump 3.2.0-2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,012 kB
  • sloc: ansic: 45,797; sh: 3,449; makefile: 512
file content (427 lines) | stat: -rw-r--r-- 13,963 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
 * Copyright (c) 2000-2001 Silicon Graphics, Inc.; provided copyright in
 * certain portions may be held by third parties as indicated herein.
 * All Rights Reserved.
 *
 * The code in this source file represents an aggregation of work from
 * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon
 * Graphics engineers over the period 1985-2000.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/param.h>
#include <assert.h>

#include "config.h"
#include "rmtlib.h"
#include "swap.h"


/*
 * uses old_mtget IRIX structure since we don't bother
 * sending the "V" version command.
 */
struct  irix_mtget   {
        short   mt_type;          /* type of magtape device */
        unsigned short  mt_dsreg; /* ``drive status'' register */
        short   mt_erreg;         /* ``error'' register */
        short   mt_resid;         /* residual count */
        int     mt_fileno;        /* file number of current position */
        int     mt_blkno;         /* block number of current position */
};

struct linux32_mtget
{
    int32_t mt_type;           /* Type of magtape device.  */
    int32_t mt_resid;          /* Residual count: */
    /* The following registers are device dependent.  */
    int32_t mt_dsreg;          /* Status register.  */
    int32_t mt_gstat;          /* Generic (device independent) status.  */
    int32_t mt_erreg;          /* Error register.  */
    /* The next two fields are not always used.  */
    int32_t mt_fileno;        /* Number of current file on tape.  */
    int32_t mt_blkno;         /* Current block number.  */
};

struct linux64_mtget
{
    int64_t mt_type;           /* Type of magtape device.  */
    int64_t mt_resid;          /* Residual count. */
    /* The following registers are device dependent.  */
    int64_t mt_dsreg;          /* Status register.  */
    int64_t mt_gstat;          /* Generic (device independent) status.  */
    int64_t mt_erreg;          /* Error register.  */
    /* The next two fields are not always used.  */
    int32_t mt_fileno;        /* Number of current file on tape.  */
    int32_t mt_blkno;         /* Current block number.  */
};


/* IRIX tape device status values */
#define IRIX_MT_EOT          0x01    /* tape is at end of media */
#define IRIX_MT_BOT          0x02    /* tape is at beginning of media */
#define IRIX_MT_WPROT        0x04    /* tape is write-protected */
#define IRIX_MT_EW           0x08    /* hit early warning marker     */
#define IRIX_MT_ONL          0x40    /* drive is online */
#define IRIX_MT_EOD          0x4000  /* tape is at end of data */
#define IRIX_MT_FMK          0x8000  /* tape is at file mark */

/* IRIX mt operations (mt_op values for MTIOCTOP) */
#define IRIX_MTWEOF  0       /* write an end-of-file record */
#define IRIX_MTFSF   1       /* forward space file */
#define IRIX_MTBSF   2       /* backward space file */
#define IRIX_MTFSR   3       /* forward space record */
#define IRIX_MTBSR   4       /* backward space record */
#define IRIX_MTREW   5       /* rewind */
#define IRIX_MTOFFL  6       /* rewind and put the drive offline */
#define IRIX_MTERASE 12      /* erase tape from current position to EOT */
#define IRIX_MTUNLOAD 13     /* unload tape from drive */

/* std (common) mt op codes */
#define STD_MTWEOF  0       /* write an end-of-file record */
#define STD_MTFSF   1       /* forward space file */
#define STD_MTBSF   2       /* backward space file */
#define STD_MTFSR   3       /* forward space record */
#define STD_MTBSR   4       /* backward space record */
#define STD_MTREW   5       /* rewind */
#define STD_MTOFFL  6       /* rewind and put the drive offline */

#define MT_MAX 40 /* encompass potential range of mt_op values */
static int mtop_irixmap[MT_MAX] = {-1};
static int mtop_stdmap[MT_MAX] = {-1};

static void
init_mtop_map(void)
{
    /* set all other values to sentinel (-1) */

    /* only map the ones which xfsdump/restore are interested in */
    mtop_irixmap[MTWEOF]    = IRIX_MTWEOF;
    mtop_irixmap[MTFSF]     = IRIX_MTFSF;
    mtop_irixmap[MTBSF]     = IRIX_MTBSF;
    mtop_irixmap[MTFSR]     = IRIX_MTFSR;
    mtop_irixmap[MTBSR]     = IRIX_MTBSR;
    mtop_irixmap[MTREW]     = IRIX_MTREW;
    mtop_irixmap[MTOFFL]    = IRIX_MTOFFL;
    mtop_irixmap[MTERASE]   = IRIX_MTERASE;
    mtop_irixmap[MTUNLOAD]  = IRIX_MTUNLOAD;

    mtop_stdmap[MTWEOF]    = STD_MTWEOF;
    mtop_stdmap[MTFSF]     = STD_MTFSF;
    mtop_stdmap[MTBSF]     = STD_MTBSF;
    mtop_stdmap[MTFSR]     = STD_MTFSR;
    mtop_stdmap[MTBSR]     = STD_MTBSR;
    mtop_stdmap[MTREW]     = STD_MTREW;
    mtop_stdmap[MTOFFL]    = STD_MTOFFL;
    mtop_stdmap[MTUNLOAD]  = STD_MTOFFL;
}


static int _rmt_ioctl(int, unsigned int, void *);

/*
 *	Do ioctl on file.  Looks just like ioctl(2) to caller.
 */

int
rmtioctl(int fildes, unsigned int request, void *arg)
{
	if (isrmt (fildes)) {
		return (_rmt_ioctl (fildes - REM_BIAS, request, arg));
	}
	else {
		return (ioctl (fildes, request, arg));
	}
}


/*
 *	_rmt_ioctl --- perform raw tape operations remotely
 */

/*
 * WARNING: MTIOCGET code is highly dependent on the format
 *          of mtget on different platforms
 *          We only support Linux 32/ia64 and IRIX 32/64 for this case.
 *          We use the result of uname(1) (in rmtopen()) and
 *          the size of the mtget structure to determine which
 *          architecture it is.
 */

static int
_rmt_ioctl(int fildes, unsigned int op, void *arg)
{
	char buffer[BUFMAGIC];
	int rc, cnt, ssize;
	char *p = NULL, *irixget = NULL, *linux32get = NULL, *linux64get = NULL;
	struct irix_mtget irix_mtget;
	struct linux32_mtget linux32_mtget;
	struct linux64_mtget linux64_mtget;
	int islinux32 = 1; /* is remote machine Linux 32 bit */
	static int onetrip = 0;

	if (!onetrip) {
		onetrip = 1;
		init_mtop_map();
	}

/*
 *	MTIOCTOP is the easy one. nothing is transfered in binary
 */

	if (op == MTIOCTOP) {
		int mt_op = ((struct mtop *) arg)->mt_op;
		int mt_count = ((struct mtop *) arg)->mt_count;

		if (RMTHOST(fildes) == UNAME_UNDEFINED) {
			_rmt_msg(RMTWARN,
		_("rmtioctl: remote host type not supported for MTIOCTOP\n"));
			setoserror(EPROTONOSUPPORT);
			return(-1);
		}

		/* map the linux op code to the irix op code */
		if (RMTHOST(fildes) == UNAME_IRIX) {
			mt_op = mtop_irixmap[mt_op];
			if (mt_op == -1) {
			    setoserror(EINVAL);
			    return(-1);
			}
		}
		else if (RMTHOST(fildes) != UNAME_LINUX) {
		/* map the linux op code to the standard/fallback op code */
			mt_op = mtop_stdmap[mt_op];
			if (mt_op == -1) {
			    setoserror(EINVAL);
			    return(-1);
			}
		}

		sprintf(buffer, "I%d\n%d\n", mt_op, mt_count);
		if (_rmt_command(fildes, buffer) == -1) {
			return(-1);
		}
		return(_rmt_status(fildes));
	}
        else if (op == MTIOCGET) {

		/*
		 *  Grab the status and read it directly into the structure.
		 *  Since the data is binary data, and the other machine might
		 *  be IRIX or Linux of a different byte-order,
		 *  we have to be careful in converting the data.
		 *
		 *  NOTE: the original /etc/rmt did NOT support a newline after
		 *  the S command, and Sun still does not.  Neither does the
		 *  current bsd source, all the way through the tahoe release.
		 *  So do NOT add the \n to this!  The sgi rmt command will
		 *  work either way.  Olson, 4/91
		 */
		if (_rmt_command(fildes, "S") == -1 ||
		    (rc = _rmt_status(fildes)) == -1)
			return(-1);


		/* If undefined then try and define it by looking
		 * and the size of the get structure.
		 * If we know our rmt host, then verify that the
		 * structure is the correct size for the supported ones
		 */
 		switch (RMTHOST(fildes)) {
		    case UNAME_UNDEFINED:
			_rmt_msg(RMTWARN,
		_("rmtioctl: remote host type not supported for MTIOCGET\n"));
			setoserror(EPROTONOSUPPORT);
			return(-1);
		    case UNAME_IRIX:
			if (sizeof(struct irix_mtget) != rc) {
			    _rmt_msg(RMTWARN,
				_("rmtioctl: IRIX mtget structure of wrong size"
				  " - got %d, wanted %d\n"),
				rc, sizeof(struct irix_mtget));
			    setoserror(EPROTONOSUPPORT);
			    return(-1);
			}
			break;
		    case UNAME_LINUX:
			if (sizeof(struct linux32_mtget) == rc) {
			    islinux32 = 1;
			}
			else if (sizeof(struct linux64_mtget) == rc) {
			    islinux32 = 0;
			}
			else {
			    _rmt_msg(RMTWARN,
			_("rmtioctl: Linux mtget structure of wrong size "
			  "- got %d, wanted %d or %d\n"),
				rc, sizeof(struct linux32_mtget),
				sizeof(struct linux64_mtget));
			    setoserror(EPROTONOSUPPORT);
			    return(-1);
			}
			break;
		    default:
			setoserror(EPROTONOSUPPORT);
			return(-1);
		}


		assert(RMTHOST(fildes)==UNAME_LINUX || RMTHOST(fildes)==UNAME_IRIX);


		if (RMTHOST(fildes) == UNAME_IRIX) {
		    p = irixget = (char *)&irix_mtget;
		}
		else if (islinux32) {
		    p = linux32get = (char *)&linux32_mtget;
		}
		else {
		    p = linux64get = (char *)&linux64_mtget;
		}


		/* read in all the data */
		ssize = rc;
		for (; ssize > 0; ssize -= cnt, p += cnt) {
			cnt = read(READ(fildes), p, ssize);
			if (cnt <= 0) {
				_rmt_abort(fildes);
				setoserror(EIO);
				return(-1);
			}
		}


		/*
		 * May need to byteswap
		 */
		if (RMTHOST(fildes) == UNAME_IRIX) {
			struct irix_mtget *irixp = (struct irix_mtget *)irixget;

			if (irixp->mt_type > 0xff) {
			    /* assume that mt_type should fit in 1 byte */

			    irixp->mt_type   = INT_SWAP(irixp->mt_type, irixp->mt_type);
			    irixp->mt_dsreg  = INT_SWAP(irixp->mt_dsreg, irixp->mt_dsreg);
			    irixp->mt_erreg  = INT_SWAP(irixp->mt_erreg, irixp->mt_erreg);
			    irixp->mt_resid  = INT_SWAP(irixp->mt_resid, irixp->mt_resid);
			    irixp->mt_fileno = INT_SWAP(irixp->mt_fileno, irixp->mt_fileno);
			    irixp->mt_blkno  = INT_SWAP(irixp->mt_blkno, irixp->mt_blkno);
			}
		}
		else if (islinux32) {
			struct linux32_mtget *linuxp = (struct linux32_mtget *)linux32get;

			if (linuxp->mt_type > 0xffff) {
			    /* assume that mt_type should fit in 2 bytes */

			    linuxp->mt_type   = INT_SWAP(linuxp->mt_type, linuxp->mt_type);
			    linuxp->mt_dsreg  = INT_SWAP(linuxp->mt_dsreg, linuxp->mt_dsreg);
			    linuxp->mt_erreg  = INT_SWAP(linuxp->mt_erreg, linuxp->mt_erreg);
			    linuxp->mt_resid  = INT_SWAP(linuxp->mt_resid, linuxp->mt_resid);
			    linuxp->mt_fileno = INT_SWAP(linuxp->mt_fileno, linuxp->mt_fileno);
			    linuxp->mt_blkno  = INT_SWAP(linuxp->mt_blkno, linuxp->mt_blkno);
			    linuxp->mt_gstat  = INT_SWAP(linuxp->mt_gstat, linuxp->mt_gstat);

			}
		}
		else {
			struct linux64_mtget *linuxp = (struct linux64_mtget *)linux64get;

			if (linuxp->mt_type > 0xffff) {
			    /* assume that mt_type should fit in 2 bytes */

			    linuxp->mt_type   = INT_SWAP(linuxp->mt_type, linuxp->mt_type);
			    linuxp->mt_dsreg  = INT_SWAP(linuxp->mt_dsreg, linuxp->mt_dsreg);
			    linuxp->mt_erreg  = INT_SWAP(linuxp->mt_erreg, linuxp->mt_erreg);
			    linuxp->mt_resid  = INT_SWAP(linuxp->mt_resid, linuxp->mt_resid);
			    linuxp->mt_fileno = INT_SWAP(linuxp->mt_fileno, linuxp->mt_fileno);
			    linuxp->mt_blkno  = INT_SWAP(linuxp->mt_blkno, linuxp->mt_blkno);
			    linuxp->mt_gstat  = INT_SWAP(linuxp->mt_gstat, linuxp->mt_gstat);

			}
		}

		/*
		 * now mtget has the correct (byte-swapped if needed) data,
                 * so we just need to copy over the fields which are possibly
                 * of different length and different semantics.
		 */
		if (RMTHOST(fildes) == UNAME_IRIX) {
			struct mtget *dstp = (struct mtget *)arg;
			struct irix_mtget *srcp = (struct irix_mtget *)irixget;
			short status = srcp->mt_dsreg;

			dstp->mt_type = srcp->mt_type;
			dstp->mt_erreg = srcp->mt_erreg;
			dstp->mt_resid = srcp->mt_resid;
			dstp->mt_fileno = srcp->mt_fileno;
			dstp->mt_blkno = srcp->mt_blkno;
			dstp->mt_dsreg = srcp->mt_dsreg; /* different semantics */

			/* need to do tape status conversions */
			dstp->mt_gstat = 0;
			if (status & IRIX_MT_EOT)
			    dstp->mt_gstat |= GMT_EOT(0xffffffff);
			if (status & IRIX_MT_BOT)
			    dstp->mt_gstat |= GMT_BOT(0xffffffff);
			if (status & IRIX_MT_WPROT)
			    dstp->mt_gstat |= GMT_WR_PROT(0xffffffff);
			if (status & IRIX_MT_ONL)
			    dstp->mt_gstat |= GMT_ONLINE(0xffffffff);
			if (status & IRIX_MT_EOD)
			    dstp->mt_gstat |= GMT_EOD(0xffffffff);
			if (status & IRIX_MT_FMK)
			    dstp->mt_gstat |= GMT_EOF(0xffffffff);
			if (status & IRIX_MT_EW)
			    ;/* No GMT_ to map it to */
		}
		else if (islinux32) {
			struct mtget *dstp = (struct mtget *)arg;
			struct linux32_mtget *srcp = (struct linux32_mtget *)linux32get;

			dstp->mt_type = srcp->mt_type;
			dstp->mt_erreg = srcp->mt_erreg;
			dstp->mt_resid = srcp->mt_resid;
			dstp->mt_fileno = srcp->mt_fileno;
			dstp->mt_blkno = srcp->mt_blkno;
			dstp->mt_dsreg = srcp->mt_dsreg;
			dstp->mt_gstat = srcp->mt_gstat;
		}
		else {
			struct mtget *dstp = (struct mtget *)arg;
			struct linux64_mtget *srcp = (struct linux64_mtget *)linux64get;

			dstp->mt_type = srcp->mt_type;
			dstp->mt_erreg = srcp->mt_erreg;
			dstp->mt_resid = srcp->mt_resid;
			dstp->mt_fileno = srcp->mt_fileno;
			dstp->mt_blkno = srcp->mt_blkno;
			dstp->mt_dsreg = srcp->mt_dsreg;
			dstp->mt_gstat = srcp->mt_gstat;
		}
		return(0);

	}
        else {
	    setoserror(EINVAL);
	    return(-1);
	}
}