]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/mtops.c
1b3dcb51b796b19d82e6fb89bb411bfc2741ff6f
[bacula/bacula] / bacula / patches / testing / mtops.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * mtops.c - Emulate the Linux st (scsi tape) driver on file.
30  *
31  * Version $Id$
32  *
33  */
34
35 #include <stdarg.h>
36 #include <stddef.h>
37
38 #include "bacula.h"                   /* pull in global headers */
39 #include "stored.h"                   /* pull in Storage Deamon headers */
40
41 #include "sys/mtio.h"
42
43 //
44 // SCSI bus status codes.
45 //
46
47 #define SCSISTAT_GOOD                  0x00
48 #define SCSISTAT_CHECK_CONDITION       0x02
49 #define SCSISTAT_CONDITION_MET         0x04
50 #define SCSISTAT_BUSY                  0x08
51 #define SCSISTAT_INTERMEDIATE          0x10
52 #define SCSISTAT_INTERMEDIATE_COND_MET 0x14
53 #define SCSISTAT_RESERVATION_CONFLICT  0x18
54 #define SCSISTAT_COMMAND_TERMINATED    0x22
55 #define SCSISTAT_QUEUE_FULL            0x28
56
57 static int tape_get(int fd, struct mtget *mt_get);
58 static int tape_op(int fd, struct mtop *mt_com);
59 static int tape_pos(int fd, struct mtpos *mt_pos);
60
61 int
62 fake_tape_open(const char *file, int flags, int mode)
63 {
64    int fd;
65    fd = open(file, flags, mode);
66    return fd;
67 }
68
69 int
70 fake_tape_read(int fd, void *buffer, unsigned int count)
71 {
72    int ret;
73    if (buffer == NULL) {
74       errno = EINVAL;
75       return -1;
76    }
77    ret = read(fd, buffer, count);
78    return ret;
79 }
80
81 int
82 fake_tape_write(int fd, const void *buffer, unsigned int count)
83 {
84    int ret;
85    if (buffer == NULL) {
86       errno = EINVAL;
87       return -1;
88    }
89    ret = write(fd, buffer, count);
90    return ret;
91 }
92
93 int
94 fake_tape_close(int fd)
95 {
96    close(fd);
97    return 0;
98 }
99
100 int
101 fake_tape_ioctl(int fd, unsigned long int request, ...)
102 {
103    va_list argp;
104    int result;
105
106    va_start(argp, request);
107
108    switch (request) {
109    case MTIOCTOP:
110       result = tape_op(fd, va_arg(argp, mtop *));
111       break;
112
113    case MTIOCGET:
114       result = tape_get(fd, va_arg(argp, mtget *));
115       break;
116
117    case MTIOCPOS:
118       result = tape_pos(fd, va_arg(argp, mtpos *));
119       break;
120
121    default:
122       errno = ENOTTY;
123       result = -1;
124       break;
125    }
126
127    va_end(argp);
128
129    return result;
130 }
131
132 static int tape_op(int fd, struct mtop *mt_com)
133 {
134    int result;
135
136    switch (mt_com->mt_op)
137    {
138    case MTRESET:
139    case MTNOP:
140    case MTSETDRVBUFFER:
141       break;
142
143    default:
144    case MTRAS1:
145    case MTRAS2:
146    case MTRAS3:
147    case MTSETDENSITY:
148       errno = ENOTTY;
149       result = (DWORD)-1;
150       break;
151
152    case MTFSF:
153       for (index = 0; index < mt_com->mt_count; index++) {
154          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
155          if (result == NO_ERROR) {
156             pHandleInfo->ulFile++;
157             pHandleInfo->bEOF = true;
158             pHandleInfo->bEOT = false;
159          }
160       }
161       break;
162
163    case MTBSF:
164       for (index = 0; index < mt_com->mt_count; index++) {
165          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
166          if (result == NO_ERROR) {
167             pHandleInfo->ulFile--;
168             pHandleInfo->bBlockValid = false;
169             pHandleInfo->bEOD = false;
170             pHandleInfo->bEOF = false;
171             pHandleInfo->bEOT = false;
172          }
173       }
174       break;
175
176    case MTFSR:
177       result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE);
178       if (result == NO_ERROR) {
179          pHandleInfo->bEOD = false;
180          pHandleInfo->bEOF = false;
181          pHandleInfo->bEOT = false;
182       } else if (result == ERROR_FILEMARK_DETECTED) {
183          pHandleInfo->bEOF = true;
184       }
185       break;
186
187    case MTBSR:
188       result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE);
189       if (result == NO_ERROR) {
190          pHandleInfo->bEOD = false;
191          pHandleInfo->bEOF = false;
192          pHandleInfo->bEOT = false;
193       } else if (result == ERROR_FILEMARK_DETECTED) {
194          pHandleInfo->ulFile--;
195          pHandleInfo->bBlockValid = false;
196          pHandleInfo->bEOD = false;
197          pHandleInfo->bEOF = false;
198          pHandleInfo->bEOT = false;
199       }
200       break;
201
202    case MTWEOF:
203       result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE);
204       if (result == NO_ERROR) {
205          pHandleInfo->bEOF = true;
206          pHandleInfo->bEOT = false;
207          pHandleInfo->ulFile += mt_com->mt_count;
208          pHandleInfo->bBlockValid = true;
209          pHandleInfo->ullFileStart = 0;
210       }
211       break;
212
213    case MTREW:
214       if (lseek(fd, (boffset_t)0, SEEK_SET) < 0) {
215          berrno be;
216          dev_errno = errno;
217          Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
218             print_name(), be.bstrerror());
219          result = -1 ;
220       } else {
221          result = NO_ERROR;
222       }
223       break;
224
225    case MTOFFL:
226       result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
227       if (result == NO_ERROR) {
228          pHandleInfo->bEOD = false;
229          pHandleInfo->bEOF = false;
230          pHandleInfo->bEOT = false;
231          pHandleInfo->ulFile = 0;
232          pHandleInfo->ullFileStart = 0;
233       }
234       break;
235
236    case MTRETEN:
237       result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE);
238       if (result == NO_ERROR) {
239          pHandleInfo->bEOD = false;
240          pHandleInfo->bEOF = false;
241          pHandleInfo->bEOT = false;
242          pHandleInfo->ulFile = 0;
243          pHandleInfo->bBlockValid = true;
244          pHandleInfo->ullFileStart = 0;
245       }
246       break;
247
248    case MTBSFM:
249       for (index = 0; index < mt_com->mt_count; index++) {
250          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
251          if (result == NO_ERROR) {
252             result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
253             pHandleInfo->bEOD = false;
254             pHandleInfo->bEOF = false;
255             pHandleInfo->bEOT = false;
256          }
257       }
258       break;
259
260    case MTFSFM:
261       for (index = 0; index < mt_com->mt_count; index++) {
262          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE);
263          if (result == NO_ERROR) {
264             result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
265             pHandleInfo->bEOD = false;
266             pHandleInfo->bEOF = false;
267             pHandleInfo->bEOT = false;
268          }
269       }
270       break;
271
272    case MTEOM:
273       for ( ; ; ) {
274          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
275          if (result != NO_ERROR) {
276             pHandleInfo->bEOF = false;
277
278             if (result == ERROR_END_OF_MEDIA) {
279                pHandleInfo->bEOD = true;
280                pHandleInfo->bEOT = true;
281                return 0;
282             }
283             if (result == ERROR_NO_DATA_DETECTED) {
284                pHandleInfo->bEOD = true;
285                pHandleInfo->bEOT = false;
286                return 0;
287             }
288             break;
289          } else {
290             pHandleInfo->bEOF = true;
291             pHandleInfo->ulFile++;
292          }
293       }
294       break;
295
296    case MTERASE:
297       result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE);
298       if (result == NO_ERROR) {
299          pHandleInfo->bEOD = true;
300          pHandleInfo->bEOF = false;
301          pHandleInfo->bEOT = false;
302          pHandleInfo->ulFile = 0;
303          pHandleInfo->bBlockValid = true;
304          pHandleInfo->ullFileStart = 0;
305       }
306       break;
307
308    case MTSETBLK:
309       {
310          TAPE_SET_MEDIA_PARAMETERS  SetMediaParameters;
311
312          SetMediaParameters.BlockSize = mt_com->mt_count;
313          result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
314       }
315       break;
316
317    case MTSEEK:
318       {
319          TAPE_POSITION_INFO   TapePositionInfo;
320
321          result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
322
323          memset(&TapePositionInfo, 0, sizeof(TapePositionInfo));
324          DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
325          if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) {
326             pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
327          } else {
328             pHandleInfo->ulFile = ~0U;
329          }
330       }
331       break;
332
333    case MTTELL:
334       {
335          DWORD partition;
336          DWORD offset;
337          DWORD offsetHi;
338
339          result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
340          if (result == NO_ERROR) {
341             return offset;
342          }
343       }
344       break;
345
346    case MTFSS:
347       result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
348       break;
349
350    case MTBSS:
351       result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
352       break;
353
354    case MTWSM:
355       result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
356       break;
357
358    case MTLOCK:
359       result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
360       break;
361
362    case MTUNLOCK:
363       result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
364       break;
365
366    case MTLOAD:
367       result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
368       break;
369
370    case MTUNLOAD:
371       result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
372       break;
373
374    case MTCOMPRESSION:
375       {
376          TAPE_GET_DRIVE_PARAMETERS  GetDriveParameters;
377          TAPE_SET_DRIVE_PARAMETERS  SetDriveParameters;
378          DWORD                      size;
379
380          size = sizeof(GetDriveParameters);
381
382          result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
383
384          if (result == NO_ERROR)
385          {
386             SetDriveParameters.ECC = GetDriveParameters.ECC;
387             SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count;
388             SetDriveParameters.DataPadding = GetDriveParameters.DataPadding;
389             SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks;
390             SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize;
391
392             result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
393          }
394       }
395       break;
396
397    case MTSETPART:
398       result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
399       break;
400
401    case MTMKPART:
402       if (mt_com->mt_count == 0)
403       {
404          result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
405       }
406       else
407       {
408          result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
409       }
410       break;
411    }
412
413    if ((result == NO_ERROR && pHandleInfo->bEOF) || 
414        (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
415
416       TAPE_POSITION_INFO TapePositionInfo;
417
418       if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
419          pHandleInfo->bBlockValid = true;
420          pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
421       }
422    }
423
424    switch (result) {
425    case NO_ERROR:
426    case (DWORD)-1:   /* Error has already been translated into errno */
427       break;
428
429    default:
430    case ERROR_FILEMARK_DETECTED:
431       errno = EIO;
432       break;
433
434    case ERROR_END_OF_MEDIA:
435       pHandleInfo->bEOT = true;
436       errno = EIO;
437       break;
438
439    case ERROR_NO_DATA_DETECTED:
440       pHandleInfo->bEOD = true;
441       errno = EIO;
442       break;
443
444    case ERROR_NO_MEDIA_IN_DRIVE:
445       pHandleInfo->bEOF = false;
446       pHandleInfo->bEOT = false;
447       pHandleInfo->bEOD = false;
448       errno = ENOMEDIUM;
449       break;
450
451    case ERROR_INVALID_HANDLE:
452    case ERROR_ACCESS_DENIED:
453    case ERROR_LOCK_VIOLATION:
454       errno = EBADF;
455       break;
456    }
457
458    return result == NO_ERROR ? 0 : -1;
459 }
460
461 static int tape_get(int fd, struct mtget *mt_get)
462 {
463    TAPE_POSITION_INFO pos_info;
464    BOOL result;
465
466    if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
467        TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
468       errno = EBADF;
469       return -1;
470    }
471
472    PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
473
474    if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
475       return -1;
476    }
477
478    DWORD density = 0;
479    DWORD blocksize = 0;
480
481    result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
482
483    if (result != NO_ERROR) {
484       TAPE_GET_DRIVE_PARAMETERS drive_params;
485       DWORD size;
486
487       size = sizeof(drive_params);
488
489       result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
490
491       if (result == NO_ERROR) {
492          blocksize = drive_params.DefaultBlockSize;
493       }
494    }
495
496    mt_get->mt_type = MT_ISSCSI2;
497
498    // Partition #
499    mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
500
501    // Density / Block Size
502    mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
503                       ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
504
505    mt_get->mt_gstat = 0x00010000;  /* Immediate report mode.*/
506
507    if (pHandleInfo->bEOF) {
508       mt_get->mt_gstat |= 0x80000000;     // GMT_EOF
509    }
510
511    if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
512       mt_get->mt_gstat |= 0x40000000;     // GMT_BOT
513    }
514
515    if (pHandleInfo->bEOT) {
516       mt_get->mt_gstat |= 0x20000000;     // GMT_EOT
517    }
518
519    if (pHandleInfo->bEOD) {
520       mt_get->mt_gstat |= 0x08000000;     // GMT_EOD
521    }
522
523    TAPE_GET_MEDIA_PARAMETERS  media_params;
524    DWORD size = sizeof(media_params);
525    
526    result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
527
528    if (result == NO_ERROR && media_params.WriteProtected) {
529       mt_get->mt_gstat |= 0x04000000;     // GMT_WR_PROT
530    }
531
532    result = GetTapeStatus(pHandleInfo->OSHandle);
533
534    if (result != NO_ERROR) {
535       if (result == ERROR_NO_MEDIA_IN_DRIVE) {
536          mt_get->mt_gstat |= 0x00040000;  // GMT_DR_OPEN
537       }
538    } else {
539       mt_get->mt_gstat |= 0x01000000;     // GMT_ONLINE
540    }
541
542    // Recovered Error Count
543    mt_get->mt_erreg = 0;
544
545    // File Number
546    mt_get->mt_fileno = (__daddr_t)pHandleInfo->ulFile;
547
548    // Block Number
549    mt_get->mt_blkno = (__daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);
550
551    return 0;
552 }