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