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