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)
120 if (dev->has_cap(CAP_TWOEOF)) {
125 if (dev->d_ioctl(dev->fd(), MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) {
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);
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;
142 if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) {
143 dev->clrerror(MTSRSZ);
150 bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
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;
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.
167 uint32_t status_dev(DEVICE *dev)
169 struct mtget mt_stat;
172 if (dev->state & (ST_EOT | ST_WEOT)) {
176 if (dev->state & ST_EOF) {
180 if (dev->is_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) {
186 dev->dev_errno = errno;
187 Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
188 dev->print_name(), be.bstrerror());
191 Pmsg0(-20, _(" Device status:"));
193 #if defined(HAVE_LINUX_OS)
194 if (GMT_EOF(mt_stat.mt_gstat)) {
198 if (GMT_BOT(mt_stat.mt_gstat)) {
202 if (GMT_EOT(mt_stat.mt_gstat)) {
206 if (GMT_SM(mt_stat.mt_gstat)) {
210 if (GMT_EOD(mt_stat.mt_gstat)) {
214 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
216 Pmsg0(-20, " WR_PROT");
218 if (GMT_ONLINE(mt_stat.mt_gstat)) {
220 Pmsg0(-20, " ONLINE");
222 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
224 Pmsg0(-20, " DR_OPEN");
226 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
227 stat |= BMT_IM_REP_EN;
228 Pmsg0(-20, " IM_REP_EN");
230 #elif defined(HAVE_WIN32)
231 if (GMT_EOF(mt_stat.mt_gstat)) {
235 if (GMT_BOT(mt_stat.mt_gstat)) {
239 if (GMT_EOT(mt_stat.mt_gstat)) {
243 if (GMT_EOD(mt_stat.mt_gstat)) {
247 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
249 Pmsg0(-20, " WR_PROT");
251 if (GMT_ONLINE(mt_stat.mt_gstat)) {
253 Pmsg0(-20, " ONLINE");
255 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
257 Pmsg0(-20, " DR_OPEN");
259 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
260 stat |= BMT_IM_REP_EN;
261 Pmsg0(-20, " IM_REP_EN");
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);
268 Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
271 stat |= BMT_ONLINE | BMT_BOT;
277 * If implemented in system, clear the tape
280 void DEVICE::clrerror(int func)
282 const char *msg = NULL;
285 dev_errno = errno; /* save errno */
287 VolCatInfo.VolCatErrors++;
294 if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
297 break; /* ignore message printed later */
300 clear_cap(CAP_EOF); /* turn off feature */
305 clear_cap(CAP_EOM); /* turn off feature */
310 clear_cap(CAP_FSF); /* turn off feature */
314 clear_cap(CAP_BSF); /* turn off feature */
318 clear_cap(CAP_FSR); /* turn off feature */
322 clear_cap(CAP_BSR); /* turn off feature */
332 #ifdef MTSETDRVBUFFER
334 msg = "MTSETDRVBUFFER";
367 bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
373 Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
374 Emsg0(M_ERROR, 0, errmsg);
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.
384 /* On some systems such as NetBSD, this clears all errors */
387 /* Found on Solaris */
390 d_ioctl(m_fd, MTIOCLRERR);
391 Dmsg0(200, "Did MTIOCLRERR\n");
395 /* Typically on FreeBSD */
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);
407 /* Clear Subsystem Exception TRU64 */
411 mt_com.mt_op = MTCSE;
413 /* Clear any error condition on the tape */
414 d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
415 Dmsg0(200, "Did MTCSE\n");