]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/os.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / stored / os.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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 */
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
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    uint32_t neof;
120    if (dev->has_cap(CAP_TWOEOF)) {
121       neof = 2;
122    } else {
123       neof = 1;
124    }
125    if (dev->d_ioctl(dev->fd(), MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) {
126       berrno be;
127       dev->dev_errno = errno;         /* save errno */
128       Mmsg2(dev->errmsg, _("Unable to set eotmodel on device %s: ERR=%s\n"),
129             dev->print_name(), be.bstrerror(dev->dev_errno));
130       Jmsg(dcr->jcr, M_FATAL, 0, dev->errmsg);
131    }
132 #endif
133    return;
134 #endif
135
136 #ifdef HAVE_SUN_OS
137    struct mtop mt_com;
138    if (dev->min_block_size == dev->max_block_size &&
139        dev->min_block_size == 0) {    /* variable block mode */
140       mt_com.mt_op = MTSRSZ;
141       mt_com.mt_count = 0;
142       if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
143          dev->clrerror(MTSRSZ);
144       }
145    }
146    return;
147 #endif
148 }
149
150 bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
151 {
152    Dmsg0(100, "dev_get_os_pos\n");
153    return dev->has_cap(CAP_MTIOCGET) &&
154           dev->d_ioctl(dev->fd(), MTIOCGET, (char *)mt_stat) == 0 &&
155           mt_stat->mt_fileno >= 0;
156 }
157
158 /*
159  * Return the status of the device.  This was meant
160  * to be a generic routine. Unfortunately, it doesn't
161  * seem possible (at least I do not know how to do it
162  * currently), which means that for the moment, this
163  * routine has very little value.
164  *
165  *   Returns: status
166  */
167 uint32_t status_dev(DEVICE *dev)
168 {
169    struct mtget mt_stat;
170    uint32_t stat = 0;
171
172    if (dev->state & (ST_EOT | ST_WEOT)) {
173       stat |= BMT_EOD;
174       Pmsg0(-20, " EOD");
175    }
176    if (dev->state & ST_EOF) {
177       stat |= BMT_EOF;
178       Pmsg0(-20, " EOF");
179    }
180    if (dev->is_tape()) {
181       stat |= BMT_TAPE;
182       Pmsg0(-20,_(" Bacula status:"));
183       Pmsg2(-20,_(" file=%d block=%d\n"), dev->file, dev->block_num);
184       if (dev->d_ioctl(dev->fd(), MTIOCGET, (char *)&mt_stat) < 0) {
185          berrno be;
186          dev->dev_errno = errno;
187          Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
188             dev->print_name(), be.bstrerror());
189          return 0;
190       }
191       Pmsg0(-20, _(" Device status:"));
192
193 #if defined(HAVE_LINUX_OS)
194       if (GMT_EOF(mt_stat.mt_gstat)) {
195          stat |= BMT_EOF;
196          Pmsg0(-20, " EOF");
197       }
198       if (GMT_BOT(mt_stat.mt_gstat)) {
199          stat |= BMT_BOT;
200          Pmsg0(-20, " BOT");
201       }
202       if (GMT_EOT(mt_stat.mt_gstat)) {
203          stat |= BMT_EOT;
204          Pmsg0(-20, " EOT");
205       }
206       if (GMT_SM(mt_stat.mt_gstat)) {
207          stat |= BMT_SM;
208          Pmsg0(-20, " SM");
209       }
210       if (GMT_EOD(mt_stat.mt_gstat)) {
211          stat |= BMT_EOD;
212          Pmsg0(-20, " EOD");
213       }
214       if (GMT_WR_PROT(mt_stat.mt_gstat)) {
215          stat |= BMT_WR_PROT;
216          Pmsg0(-20, " WR_PROT");
217       }
218       if (GMT_ONLINE(mt_stat.mt_gstat)) {
219          stat |= BMT_ONLINE;
220          Pmsg0(-20, " ONLINE");
221       }
222       if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
223          stat |= BMT_DR_OPEN;
224          Pmsg0(-20, " DR_OPEN");
225       }
226       if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
227          stat |= BMT_IM_REP_EN;
228          Pmsg0(-20, " IM_REP_EN");
229       }
230 #elif defined(HAVE_WIN32)
231       if (GMT_EOF(mt_stat.mt_gstat)) {
232          stat |= BMT_EOF;
233          Pmsg0(-20, " EOF");
234       }
235       if (GMT_BOT(mt_stat.mt_gstat)) {
236          stat |= BMT_BOT;
237          Pmsg0(-20, " BOT");
238       }
239       if (GMT_EOT(mt_stat.mt_gstat)) {
240          stat |= BMT_EOT;
241          Pmsg0(-20, " EOT");
242       }
243       if (GMT_EOD(mt_stat.mt_gstat)) {
244          stat |= BMT_EOD;
245          Pmsg0(-20, " EOD");
246       }
247       if (GMT_WR_PROT(mt_stat.mt_gstat)) {
248          stat |= BMT_WR_PROT;
249          Pmsg0(-20, " WR_PROT");
250       }
251       if (GMT_ONLINE(mt_stat.mt_gstat)) {
252          stat |= BMT_ONLINE;
253          Pmsg0(-20, " ONLINE");
254       }
255       if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
256          stat |= BMT_DR_OPEN;
257          Pmsg0(-20, " DR_OPEN");
258       }
259       if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
260          stat |= BMT_IM_REP_EN;
261          Pmsg0(-20, " IM_REP_EN");
262       }
263
264 #endif /* !SunOS && !OSF */
265       if (dev->has_cap(CAP_MTIOCGET)) {
266          Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
267       } else {
268          Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
269       }
270    } else {
271       stat |= BMT_ONLINE | BMT_BOT;
272    }
273    return stat;
274 }
275
276 /*
277  * If implemented in system, clear the tape
278  * error status.
279  */
280 void DEVICE::clrerror(int func)
281 {
282    const char *msg = NULL;
283    char buf[100];
284
285    dev_errno = errno;         /* save errno */
286    if (errno == EIO) {
287       VolCatInfo.VolCatErrors++;
288    }
289
290    if (!is_tape()) {
291       return;
292    }
293
294    if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
295       switch (func) {
296       case -1:
297          break;                  /* ignore message printed later */
298       case MTWEOF:
299          msg = "WTWEOF";
300          clear_cap(CAP_EOF);     /* turn off feature */
301          break;
302 #ifdef MTEOM
303       case MTEOM:
304          msg = "WTEOM";
305          clear_cap(CAP_EOM);     /* turn off feature */
306          break;
307 #endif
308       case MTFSF:
309          msg = "MTFSF";
310          clear_cap(CAP_FSF);     /* turn off feature */
311          break;
312       case MTBSF:
313          msg = "MTBSF";
314          clear_cap(CAP_BSF);     /* turn off feature */
315          break;
316       case MTFSR:
317          msg = "MTFSR";
318          clear_cap(CAP_FSR);     /* turn off feature */
319          break;
320       case MTBSR:
321          msg = "MTBSR";
322          clear_cap(CAP_BSR);     /* turn off feature */
323          break;
324       case MTREW:
325          msg = "MTREW";
326          break;
327 #ifdef MTSETBLK
328       case MTSETBLK:
329          msg = "MTSETBLK";
330          break;
331 #endif
332 #ifdef MTSETDRVBUFFER
333       case MTSETDRVBUFFER:
334          msg = "MTSETDRVBUFFER";
335          break;
336 #endif
337 #ifdef MTRESET
338       case MTRESET:
339          msg = "MTRESET";
340          break;
341 #endif
342
343 #ifdef MTSETBSIZ
344       case MTSETBSIZ:
345          msg = "MTSETBSIZ";
346          break;
347 #endif
348 #ifdef MTSRSZ
349       case MTSRSZ:
350          msg = "MTSRSZ";
351          break;
352 #endif
353 #ifdef MTLOAD
354       case MTLOAD:
355          msg = "MTLOAD";
356          break;
357 #endif
358 #ifdef MTUNLOCK
359       case MTUNLOCK:
360          msg = "MTUNLOCK";
361          break;
362 #endif
363       case MTOFFL:
364          msg = "MTOFFL";
365          break;
366       default:
367          bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
368          msg = buf;
369          break;
370       }
371       if (msg != NULL) {
372          dev_errno = ENOSYS;
373          Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
374          Emsg0(M_ERROR, 0, errmsg);
375       }
376    }
377
378    /*
379     * Now we try different methods of clearing the error
380     *  status on the drive so that it is not locked for
381     *  further operations.
382     */
383
384    /* On some systems such as NetBSD, this clears all errors */
385    get_os_tape_file();
386
387 /* Found on Solaris */
388 #ifdef MTIOCLRERR
389 {
390    d_ioctl(m_fd, MTIOCLRERR);
391    Dmsg0(200, "Did MTIOCLRERR\n");
392 }
393 #endif
394
395 /* Typically on FreeBSD */
396 #ifdef MTIOCERRSTAT
397 {
398   berrno be;
399    /* Read and clear SCSI error status */
400    union mterrstat mt_errstat;
401    Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
402       be.bstrerror(dev_errno));
403    d_ioctl(m_fd, MTIOCERRSTAT, (char *)&mt_errstat);
404 }
405 #endif
406
407 /* Clear Subsystem Exception TRU64 */
408 #ifdef MTCSE
409 {
410    struct mtop mt_com;
411    mt_com.mt_op = MTCSE;
412    mt_com.mt_count = 1;
413    /* Clear any error condition on the tape */
414    d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
415    Dmsg0(200, "Did MTCSE\n");
416 }
417 #endif
418 }