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