2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * os.c -- Operating System dependent dev.c routines
23 * written by, Kern Sibbald, MM
24 * separated from dev.c February 2014
26 * Note, this is the device dependent code, and may have
27 * to be modified for each system.
34 /* Returns file position on tape or -1 */
35 int32_t DEVICE::get_os_tape_file()
39 if (has_cap(CAP_MTIOCGET) &&
40 d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) == 0) {
41 return mt_stat.mt_fileno;
47 void set_os_device_parameters(DCR *dcr)
49 DEVICE *dev = dcr->dev;
51 if (strcmp(dev->dev_name, "/dev/null") == 0) {
52 return; /* no use trying to set /dev/null */
55 #if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32)
58 Dmsg0(100, "In set_os_device_parameters\n");
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;
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);
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;
77 if (dev->has_cap(CAP_EOM)) {
78 mt_com.mt_count |= MT_ST_FAST_MTEOM;
80 Dmsg0(100, "MTSETDRVBUFFER\n");
81 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
82 dev->clrerror(MTSETDRVBUFFER);
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;
95 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
96 dev->clrerror(MTSETBSIZ);
98 /* Get notified at logical end of tape */
99 mt_com.mt_op = MTEWARN;
101 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
102 dev->clrerror(MTEWARN);
108 #if HAVE_FREEBSD_OS || HAVE_OPENBSD_OS
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;
114 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
115 dev->clrerror(MTSETBSIZ);
118 #if defined(MTIOCSETEOTMODEL)
119 if (dev->is_fifo()) {
120 return; /* do not do tape stuff */
123 if (dev->has_cap(CAP_TWOEOF)) {
128 if (dev->d_ioctl(dev->fd(), MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) {
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);
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;
145 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
146 dev->clrerror(MTSRSZ);
153 bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
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;
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.
170 uint32_t status_dev(DEVICE *dev)
172 struct mtget mt_stat;
175 if (dev->state & (ST_EOT | ST_WEOT)) {
179 if (dev->state & ST_EOF) {
183 if (dev->is_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) {
189 dev->dev_errno = errno;
190 Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
191 dev->print_name(), be.bstrerror());
194 Pmsg0(-20, _(" Device status:"));
196 #if defined(HAVE_LINUX_OS)
197 if (GMT_EOF(mt_stat.mt_gstat)) {
201 if (GMT_BOT(mt_stat.mt_gstat)) {
205 if (GMT_EOT(mt_stat.mt_gstat)) {
209 if (GMT_SM(mt_stat.mt_gstat)) {
213 if (GMT_EOD(mt_stat.mt_gstat)) {
217 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
219 Pmsg0(-20, " WR_PROT");
221 if (GMT_ONLINE(mt_stat.mt_gstat)) {
223 Pmsg0(-20, " ONLINE");
225 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
227 Pmsg0(-20, " DR_OPEN");
229 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
230 stat |= BMT_IM_REP_EN;
231 Pmsg0(-20, " IM_REP_EN");
233 #elif defined(HAVE_WIN32)
234 if (GMT_EOF(mt_stat.mt_gstat)) {
238 if (GMT_BOT(mt_stat.mt_gstat)) {
242 if (GMT_EOT(mt_stat.mt_gstat)) {
246 if (GMT_EOD(mt_stat.mt_gstat)) {
250 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
252 Pmsg0(-20, " WR_PROT");
254 if (GMT_ONLINE(mt_stat.mt_gstat)) {
256 Pmsg0(-20, " ONLINE");
258 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
260 Pmsg0(-20, " DR_OPEN");
262 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
263 stat |= BMT_IM_REP_EN;
264 Pmsg0(-20, " IM_REP_EN");
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);
271 Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
274 stat |= BMT_ONLINE | BMT_BOT;
280 * If implemented in system, clear the tape
283 void DEVICE::clrerror(int func)
285 const char *msg = NULL;
288 dev_errno = errno; /* save errno */
290 VolCatInfo.VolCatErrors++;
297 if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
300 break; /* ignore message printed later */
303 clear_cap(CAP_EOF); /* turn off feature */
308 clear_cap(CAP_EOM); /* turn off feature */
313 clear_cap(CAP_FSF); /* turn off feature */
317 clear_cap(CAP_BSF); /* turn off feature */
321 clear_cap(CAP_FSR); /* turn off feature */
325 clear_cap(CAP_BSR); /* turn off feature */
335 #ifdef MTSETDRVBUFFER
337 msg = "MTSETDRVBUFFER";
370 bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
376 Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
377 Emsg0(M_ERROR, 0, errmsg);
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.
387 /* On some systems such as NetBSD, this clears all errors */
390 /* Found on Solaris */
393 d_ioctl(m_fd, MTIOCLRERR);
394 Dmsg0(200, "Did MTIOCLRERR\n");
398 /* Typically on FreeBSD */
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);
410 /* Clear Subsystem Exception TRU64 */
414 mt_com.mt_op = MTCSE;
416 /* Clear any error condition on the tape */
417 d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
418 Dmsg0(200, "Did MTCSE\n");