1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   os.c  -- Operating System dependent dev.c routines
22  *
23  *     written by, Kern Sibbald, MM
24  *     separated from dev.c February 2014
25  *
26  *     Note, this is the device dependent code, and may have
27  *           to be modified for each system.
28  */
29 
30 
31 #include "bacula.h"
32 #include "stored.h"
33 
34 /* Returns file position on tape or -1 */
get_os_tape_file()35 int32_t DEVICE::get_os_tape_file()
36 {
37    struct mtget mt_stat;
38 
39    if (has_cap(CAP_MTIOCGET) &&
40        d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) == 0) {
41       return mt_stat.mt_fileno;
42    }
43    return -1;
44 }
45 
46 
set_os_device_parameters(DCR * dcr)47 void set_os_device_parameters(DCR *dcr)
48 {
49    DEVICE *dev = dcr->dev;
50 
51    if (strcmp(dev->dev_name, "/dev/null") == 0) {
52       return;                            /* no use trying to set /dev/null */
53    }
54 
55 #if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32)
56    struct mtop mt_com;
57 
58    Dmsg0(100, "In set_os_device_parameters\n");
59 #if defined(MTSETBLK)
60    if (dev->min_block_size == dev->max_block_size &&
61        dev->min_block_size == 0) {    /* variable block mode */
62       mt_com.mt_op = MTSETBLK;
63       mt_com.mt_count = 0;
64       Dmsg0(100, "Set block size to zero\n");
65       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
66          dev->clrerror(MTSETBLK);
67       }
68    }
69 #endif
70 #if defined(MTSETDRVBUFFER)
71    if (getuid() == 0) {          /* Only root can do this */
72       mt_com.mt_op = MTSETDRVBUFFER;
73       mt_com.mt_count = MT_ST_CLEARBOOLEANS;
74       if (!dev->has_cap(CAP_TWOEOF)) {
75          mt_com.mt_count |= MT_ST_TWO_FM;
76       }
77       if (dev->has_cap(CAP_EOM)) {
78          mt_com.mt_count |= MT_ST_FAST_MTEOM;
79       }
80       Dmsg0(100, "MTSETDRVBUFFER\n");
81       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
82          dev->clrerror(MTSETDRVBUFFER);
83       }
84    }
85 #endif
86    return;
87 #endif
88 
89 #ifdef HAVE_NETBSD_OS
90    struct mtop mt_com;
91    if (dev->min_block_size == dev->max_block_size &&
92        dev->min_block_size == 0) {    /* variable block mode */
93       mt_com.mt_op = MTSETBSIZ;
94       mt_com.mt_count = 0;
95       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
96          dev->clrerror(MTSETBSIZ);
97       }
98       /* Get notified at logical end of tape */
99       mt_com.mt_op = MTEWARN;
100       mt_com.mt_count = 1;
101       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
102          dev->clrerror(MTEWARN);
103       }
104    }
105    return;
106 #endif
107 
108 #if HAVE_FREEBSD_OS || HAVE_OPENBSD_OS
109    struct mtop mt_com;
110    if (dev->min_block_size == dev->max_block_size &&
111        dev->min_block_size == 0) {    /* variable block mode */
112       mt_com.mt_op = MTSETBSIZ;
113       mt_com.mt_count = 0;
114       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
115          dev->clrerror(MTSETBSIZ);
116       }
117    }
118 #if defined(MTIOCSETEOTMODEL)
119    if (dev->is_fifo()) {
120       return;   /* do not do tape stuff */
121    }
122    uint32_t neof;
123    if (dev->has_cap(CAP_TWOEOF)) {
124       neof = 2;
125    } else {
126       neof = 1;
127    }
128    if (dev->d_ioctl(dev->fd(), MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) {
129       berrno be;
130       dev->dev_errno = errno;         /* save errno */
131       Mmsg2(dev->errmsg, _("Unable to set eotmodel on device %s: ERR=%s\n"),
132             dev->print_name(), be.bstrerror(dev->dev_errno));
133       Jmsg(dcr->jcr, M_FATAL, 0, dev->errmsg);
134    }
135 #endif
136    return;
137 #endif
138 
139 #ifdef HAVE_SUN_OS
140    struct mtop mt_com;
141    if (dev->min_block_size == dev->max_block_size &&
142        dev->min_block_size == 0) {    /* variable block mode */
143       mt_com.mt_op = MTSRSZ;
144       mt_com.mt_count = 0;
145       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
146          dev->clrerror(MTSRSZ);
147       }
148    }
149    return;
150 #endif
151 }
152 
dev_get_os_pos(DEVICE * dev,struct mtget * mt_stat)153 bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
154 {
155    Dmsg0(100, "dev_get_os_pos\n");
156    return dev->has_cap(CAP_MTIOCGET) &&
157           dev->d_ioctl(dev->fd(), MTIOCGET, (char *)mt_stat) == 0 &&
158           mt_stat->mt_fileno >= 0;
159 }
160 
161 /*
162  * Return the status of the device.  This was meant
163  * to be a generic routine. Unfortunately, it doesn't
164  * seem possible (at least I do not know how to do it
165  * currently), which means that for the moment, this
166  * routine has very little value.
167  *
168  *   Returns: status
169  */
status_dev(DEVICE * dev)170 uint32_t status_dev(DEVICE *dev)
171 {
172    struct mtget mt_stat;
173    uint32_t stat = 0;
174 
175    if (dev->state & (ST_EOT | ST_WEOT)) {
176       stat |= BMT_EOD;
177       Pmsg0(-20, " EOD");
178    }
179    if (dev->state & ST_EOF) {
180       stat |= BMT_EOF;
181       Pmsg0(-20, " EOF");
182    }
183    if (dev->is_tape()) {
184       stat |= BMT_TAPE;
185       Pmsg0(-20,_(" Bacula status:"));
186       Pmsg2(-20,_(" file=%d block=%d\n"), dev->file, dev->block_num);
187       if (dev->d_ioctl(dev->fd(), MTIOCGET, (char *)&mt_stat) < 0) {
188          berrno be;
189          dev->dev_errno = errno;
190          Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
191             dev->print_name(), be.bstrerror());
192          return 0;
193       }
194       Pmsg0(-20, _(" Device status:"));
195 
196 #if defined(HAVE_LINUX_OS)
197       if (GMT_EOF(mt_stat.mt_gstat)) {
198          stat |= BMT_EOF;
199          Pmsg0(-20, " EOF");
200       }
201       if (GMT_BOT(mt_stat.mt_gstat)) {
202          stat |= BMT_BOT;
203          Pmsg0(-20, " BOT");
204       }
205       if (GMT_EOT(mt_stat.mt_gstat)) {
206          stat |= BMT_EOT;
207          Pmsg0(-20, " EOT");
208       }
209       if (GMT_SM(mt_stat.mt_gstat)) {
210          stat |= BMT_SM;
211          Pmsg0(-20, " SM");
212       }
213       if (GMT_EOD(mt_stat.mt_gstat)) {
214          stat |= BMT_EOD;
215          Pmsg0(-20, " EOD");
216       }
217       if (GMT_WR_PROT(mt_stat.mt_gstat)) {
218          stat |= BMT_WR_PROT;
219          Pmsg0(-20, " WR_PROT");
220       }
221       if (GMT_ONLINE(mt_stat.mt_gstat)) {
222          stat |= BMT_ONLINE;
223          Pmsg0(-20, " ONLINE");
224       }
225       if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
226          stat |= BMT_DR_OPEN;
227          Pmsg0(-20, " DR_OPEN");
228       }
229       if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
230          stat |= BMT_IM_REP_EN;
231          Pmsg0(-20, " IM_REP_EN");
232       }
233 #elif defined(HAVE_WIN32)
234       if (GMT_EOF(mt_stat.mt_gstat)) {
235          stat |= BMT_EOF;
236          Pmsg0(-20, " EOF");
237       }
238       if (GMT_BOT(mt_stat.mt_gstat)) {
239          stat |= BMT_BOT;
240          Pmsg0(-20, " BOT");
241       }
242       if (GMT_EOT(mt_stat.mt_gstat)) {
243          stat |= BMT_EOT;
244          Pmsg0(-20, " EOT");
245       }
246       if (GMT_EOD(mt_stat.mt_gstat)) {
247          stat |= BMT_EOD;
248          Pmsg0(-20, " EOD");
249       }
250       if (GMT_WR_PROT(mt_stat.mt_gstat)) {
251          stat |= BMT_WR_PROT;
252          Pmsg0(-20, " WR_PROT");
253       }
254       if (GMT_ONLINE(mt_stat.mt_gstat)) {
255          stat |= BMT_ONLINE;
256          Pmsg0(-20, " ONLINE");
257       }
258       if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
259          stat |= BMT_DR_OPEN;
260          Pmsg0(-20, " DR_OPEN");
261       }
262       if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
263          stat |= BMT_IM_REP_EN;
264          Pmsg0(-20, " IM_REP_EN");
265       }
266 
267 #endif /* !SunOS && !OSF */
268       if (dev->has_cap(CAP_MTIOCGET)) {
269          Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
270       } else {
271          Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
272       }
273    } else {
274       stat |= BMT_ONLINE | BMT_BOT;
275    }
276    return stat;
277 }
278 
279 /*
280  * If implemented in system, clear the tape
281  * error status.
282  */
clrerror(int func)283 void DEVICE::clrerror(int func)
284 {
285    const char *msg = NULL;
286    char buf[100];
287 
288    dev_errno = errno;         /* save errno */
289    if (errno == EIO) {
290       VolCatInfo.VolCatErrors++;
291    }
292 
293    if (!is_tape()) {
294       return;
295    }
296 
297    if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
298       switch (func) {
299       case -1:
300          break;                  /* ignore message printed later */
301       case MTWEOF:
302          msg = "WTWEOF";
303          clear_cap(CAP_EOF);     /* turn off feature */
304          break;
305 #ifdef MTEOM
306       case MTEOM:
307          msg = "WTEOM";
308          clear_cap(CAP_EOM);     /* turn off feature */
309          break;
310 #endif
311       case MTFSF:
312          msg = "MTFSF";
313          clear_cap(CAP_FSF);     /* turn off feature */
314          break;
315       case MTBSF:
316          msg = "MTBSF";
317          clear_cap(CAP_BSF);     /* turn off feature */
318          break;
319       case MTFSR:
320          msg = "MTFSR";
321          clear_cap(CAP_FSR);     /* turn off feature */
322          break;
323       case MTBSR:
324          msg = "MTBSR";
325          clear_cap(CAP_BSR);     /* turn off feature */
326          break;
327       case MTREW:
328          msg = "MTREW";
329          break;
330 #ifdef MTSETBLK
331       case MTSETBLK:
332          msg = "MTSETBLK";
333          break;
334 #endif
335 #ifdef MTSETDRVBUFFER
336       case MTSETDRVBUFFER:
337          msg = "MTSETDRVBUFFER";
338          break;
339 #endif
340 #ifdef MTRESET
341       case MTRESET:
342          msg = "MTRESET";
343          break;
344 #endif
345 
346 #ifdef MTSETBSIZ
347       case MTSETBSIZ:
348          msg = "MTSETBSIZ";
349          break;
350 #endif
351 #ifdef MTSRSZ
352       case MTSRSZ:
353          msg = "MTSRSZ";
354          break;
355 #endif
356 #ifdef MTLOAD
357       case MTLOAD:
358          msg = "MTLOAD";
359          break;
360 #endif
361 #ifdef MTUNLOCK
362       case MTUNLOCK:
363          msg = "MTUNLOCK";
364          break;
365 #endif
366       case MTOFFL:
367          msg = "MTOFFL";
368          break;
369       default:
370          bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
371          msg = buf;
372          break;
373       }
374       if (msg != NULL) {
375          dev_errno = ENOSYS;
376          Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
377          Emsg0(M_ERROR, 0, errmsg);
378       }
379    }
380 
381    /*
382     * Now we try different methods of clearing the error
383     *  status on the drive so that it is not locked for
384     *  further operations.
385     */
386 
387    /* On some systems such as NetBSD, this clears all errors */
388    get_os_tape_file();
389 
390 /* Found on Solaris */
391 #ifdef MTIOCLRERR
392 {
393    d_ioctl(m_fd, MTIOCLRERR);
394    Dmsg0(200, "Did MTIOCLRERR\n");
395 }
396 #endif
397 
398 /* Typically on FreeBSD */
399 #ifdef MTIOCERRSTAT
400 {
401   berrno be;
402    /* Read and clear SCSI error status */
403    union mterrstat mt_errstat;
404    Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
405       be.bstrerror(dev_errno));
406    d_ioctl(m_fd, MTIOCERRSTAT, (char *)&mt_errstat);
407 }
408 #endif
409 
410 /* Clear Subsystem Exception TRU64 */
411 #ifdef MTCSE
412 {
413    struct mtop mt_com;
414    mt_com.mt_op = MTCSE;
415    mt_com.mt_count = 1;
416    /* Clear any error condition on the tape */
417    d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
418    Dmsg0(200, "Did MTCSE\n");
419 }
420 #endif
421 }
422