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 * file_dev.c -- low level operations on file devices
23 * written by, Kern Sibbald, MM
24 * separated from dev.c February 2014
31 static const int dbglvl = 100;
33 /* Imported functions */
34 const char *mode_to_str(int mode);
37 /* default primitives are designed for file */
38 int DEVICE::d_open(const char *pathname, int flags)
40 return ::open(pathname, flags | O_CLOEXEC);
43 int DEVICE::d_close(int fd)
48 int DEVICE::d_ioctl(int fd, ioctl_req_t request, char *mt_com)
53 return ::ioctl(fd, request, mt_com);
57 ssize_t DEVICE::d_read(int fd, void *buffer, size_t count)
59 return ::read(fd, buffer, count);
62 ssize_t DEVICE::d_write(int fd, const void *buffer, size_t count)
64 return ::write(fd, buffer, count);
67 /* Rewind file device */
68 bool DEVICE::rewind(DCR *dcr)
72 Dmsg3(400, "rewind res=%d fd=%d %s\n", num_reserved(), m_fd, print_name());
73 state &= ~(ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
78 Mmsg1(errmsg, _("Rewind failed: device %s is not open.\n"), print_name());
82 if (lseek(dcr, (boffset_t)0, SEEK_SET) < 0) {
85 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
86 print_name(), be.bstrerror());
94 * Reposition the device to file, block
95 * Returns: false on failure
98 bool DEVICE::reposition(DCR *dcr, uint64_t raddr)
102 Mmsg0(errmsg, _("Bad call to reposition. Device not open\n"));
103 Emsg0(M_FATAL, 0, errmsg);
107 Dmsg1(100, "===== lseek to %llu\n", raddr);
108 if (lseek(dcr, (boffset_t)raddr, SEEK_SET) == (boffset_t)-1) {
111 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
112 print_name(), be.bstrerror());
120 /* Seek to specified place */
121 boffset_t DEVICE::lseek(DCR *dcr, boffset_t offset, int whence)
123 #if defined(HAVE_WIN32)
124 return ::_lseeki64(m_fd, (__int64)offset, whence);
126 return ::lseek(m_fd, offset, whence);
131 * Open a file device. For Aligned type we open both Volumes
133 bool file_dev::open_device(DCR *dcr, int omode)
135 POOL_MEM archive_name(PM_FNAME);
139 if (DEVICE::open_device(dcr, omode)) {
145 get_autochanger_loaded_slot(dcr);
148 * Handle opening of File Autochanger
151 pm_strcpy(archive_name, dev_name);
153 * If this is a virtual autochanger (i.e. changer_res != NULL)
154 * we simply use the device name, assuming it has been
155 * appropriately setup by the "autochanger".
157 if (!device->changer_res || device->changer_command[0] == 0 ||
158 strcmp(device->changer_command, "/dev/null") == 0) {
159 if (VolCatInfo.VolCatName[0] == 0) {
160 Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"),
163 pm_strcpy(dcr->jcr->errmsg, errmsg);
170 /* If not /dev/null concatenate VolumeName */
172 if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
173 pm_strcat(archive_name, "/");
175 pm_strcat(archive_name, getVolCatName());
179 mount(1); /* do mount if required */
182 /* If creating file, give 0640 permissions */
183 Dmsg3(100, "open disk: mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode),
184 archive_name.c_str(), mode);
185 /* Use system open() */
186 if ((m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC, 0640)) < 0) {
189 Mmsg3(errmsg, _("Could not open(%s,%s,0640): ERR=%s\n"),
190 archive_name.c_str(), mode_to_str(omode), be.bstrerror());
191 Dmsg1(40, "open failed: %s", errmsg);
193 /* Open is OK, now let device get control */
194 Dmsg2(40, "Did open(%s,%s,0640)\n", archive_name.c_str(), mode_to_str(omode));
195 device_specific_open(dcr);
202 /* Refresh the underline device id */
203 if (fstat(m_fd, &sp) == 0) {
208 pm_strcpy(dcr->jcr->errmsg, errmsg);
211 Dmsg1(100, "open dev: disk fd=%d opened, aligned=%d\n", m_fd);
213 state |= preserve; /* reset any important state info */
219 * Truncate a volume. If this is aligned disk, we
220 * truncate both volumes.
222 bool DEVICE::truncate(DCR *dcr)
227 Dmsg1(100, "truncate %s\n", print_name());
232 /* maybe we should rewind and write and eof ???? */
233 return true; /* we don't really truncate tapes */
238 /* Do truncate for 1 or 2 devices */
239 Dmsg2(100, "Truncate adata=%d fd=%d\n", dev->adata, dev->m_fd);
240 if (ftruncate(dev->m_fd, 0) != 0) {
242 Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"),
243 print_name(), be.bstrerror());
248 * Check for a successful ftruncate() and issue a work-around for devices
249 * (mostly cheap NAS) that don't support truncation.
250 * Workaround supplied by Martin Schmid as a solution to bug #1011.
253 * 3. open new file with same mode
254 * 4. change ownership to original
257 if (fstat(dev->m_fd, &st) != 0) {
259 Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"),
260 print_name(), be.bstrerror());
264 if (st.st_size != 0) { /* ftruncate() didn't work */
265 POOL_MEM archive_name(PM_FNAME);
267 pm_strcpy(archive_name, dev_name);
268 if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
269 pm_strcat(archive_name, "/");
271 pm_strcat(archive_name, dcr->VolumeName);
272 if (dev->is_adata()) {
273 pm_strcat(archive_name, ADATA_EXTENSION);
276 Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"),
277 print_name(), archive_name.c_str());
279 /* Close file and blow it away */
281 ::unlink(archive_name.c_str());
283 /* Recreate the file -- of course, empty */
284 dev->set_mode(CREATE_READ_WRITE);
285 if ((dev->m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC, st.st_mode)) < 0) {
288 Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(),
290 Dmsg1(40, "reopen failed: %s", errmsg);
291 Emsg0(M_FATAL, 0, errmsg);
295 /* Reset proper owner */
296 chown(archive_name.c_str(), st.st_uid, st.st_gid);
303 * (Un)mount the device
305 bool DEVICE::mount_file(int mount, int dotimeout)
307 POOL_MEM ocmd(PM_FNAME);
311 struct dirent *entry, *result;
312 int status, tries, name_max, count;
317 icmd = device->mount_command;
319 icmd = device->unmount_command;
322 clear_freespace_ok();
323 edit_mount_codes(ocmd, icmd);
325 Dmsg2(100, "mount_file: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
328 /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */
333 results = get_memory(4000);
335 /* If busy retry each second */
336 Dmsg1(100, "mount_file run_prog=%s\n", ocmd.c_str());
337 while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) {
338 /* Doesn't work with internationalization (This is not a problem) */
339 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
342 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
346 /* Sometimes the device cannot be mounted because it is already mounted.
347 * Try to unmount it, then remount it */
349 Dmsg1(400, "Trying to unmount the device %s...\n", print_name());
355 Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
356 (mount ? "" : "un"), status, results, be.bstrerror(status));
357 Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
358 print_name(), (mount ? "" : "un"), be.bstrerror(status));
361 * Now, just to be sure it is not mounted, try to read the filesystem.
363 name_max = pathconf(".", _PC_NAME_MAX);
364 if (name_max < 1024) {
368 if (!(dp = opendir(device->mount_point))) {
371 Dmsg3(100, "mount_file: failed to open dir %s (dev=%s), ERR=%s\n",
372 device->mount_point, print_name(), be.bstrerror());
376 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
379 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
381 Dmsg2(129, "mount_file: failed to find suitable file in dir %s (dev=%s)\n",
382 device->mount_point, print_name());
385 if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
386 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
389 Dmsg2(129, "mount_file: ignoring %s in %s\n", result->d_name, device->mount_point);
395 Dmsg1(100, "mount_file: got %d files in the mount point (not counting ., .. and .keep)\n", count);
398 /* If we got more than ., .. and .keep */
399 /* there must be something mounted */
401 Dmsg1(100, "Did Mount by count=%d\n", count);
404 /* An unmount request. We failed to unmount - report an error */
406 free_pool_memory(results);
407 Dmsg0(200, "== error mount=1 wanted unmount\n");
413 free_pool_memory(results);
414 Dmsg0(200, "============ mount=0\n");
419 set_mounted(mount); /* set/clear mounted flag */
420 free_pool_memory(results);
421 /* Do not check free space when unmounting */
422 Dmsg1(200, "============ mount=%d\n", mount);
427 * Check if the current position on the volume corresponds to
428 * what is in the catalog.
431 bool file_dev::is_eod_valid(DCR *dcr)
435 if (has_cap(CAP_LSEEK)) {
436 char ed1[50], ed2[50];
437 boffset_t ameta_size, adata_size, size;
439 ameta_size = lseek(dcr, (boffset_t)0, SEEK_END);
440 adata_size = get_adata_size(dcr);
441 size = ameta_size + adata_size;
442 if (VolCatInfo.VolCatAmetaBytes == (uint64_t)ameta_size &&
443 VolCatInfo.VolCatAdataBytes == (uint64_t)adata_size) {
445 Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volumes \"%s\""
446 " ameta size=%s adata size=%s\n"), dcr->VolumeName,
447 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed1),
448 edit_uint64_with_commas(VolCatInfo.VolCatAdataBytes, ed2));
450 Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
451 " size=%s\n"), dcr->VolumeName,
452 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed1));
454 } else if ((uint64_t)ameta_size >= VolCatInfo.VolCatAmetaBytes &&
455 (uint64_t)adata_size >= VolCatInfo.VolCatAdataBytes) {
456 if ((uint64_t)ameta_size != VolCatInfo.VolCatAmetaBytes) {
457 Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
458 " The sizes do not match! Metadata Volume=%s Catalog=%s\n"
459 " Correcting Catalog\n"),
460 dcr->VolumeName, edit_uint64_with_commas(ameta_size, ed1),
461 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed2));
463 if ((uint64_t)adata_size != VolCatInfo.VolCatAdataBytes) {
464 Jmsg(jcr, M_WARNING, 0, _("For aligned Volume \"%s\":\n"
465 " Aligned sizes do not match! Aligned Volume=%s Catalog=%s\n"
466 " Correcting Catalog\n"),
467 dcr->VolumeName, edit_uint64_with_commas(adata_size, ed1),
468 edit_uint64_with_commas(VolCatInfo.VolCatAdataBytes, ed2));
470 VolCatInfo.VolCatAmetaBytes = ameta_size;
471 VolCatInfo.VolCatAdataBytes = adata_size;
472 VolCatInfo.VolCatBytes = size;
473 VolCatInfo.VolCatFiles = (uint32_t)(size >> 32);
474 if (!dir_update_volume_info(dcr, false, true)) {
475 Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
476 dcr->mark_volume_in_error();
480 Mmsg(jcr->errmsg, _("Bacula cannot write on disk Volume \"%s\" because: "
481 "The sizes do not match! Volume=%s Catalog=%s\n"),
483 edit_uint64_with_commas(size, ed1),
484 edit_uint64_with_commas(VolCatInfo.VolCatBytes, ed2));
485 Jmsg(jcr, M_ERROR, 0, jcr->errmsg);
486 Dmsg0(100, jcr->errmsg);
487 dcr->mark_volume_in_error();
496 * Position device to end of medium (end of data)
497 * Returns: true on succes
500 bool file_dev::eod(DCR *dcr)
507 Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), print_name());
508 Dmsg1(100, "%s", errmsg);
516 clear_eof(); /* remove EOF flag */
517 block_num = file = 0;
524 pos = lseek(dcr, (boffset_t)0, SEEK_END);
525 Dmsg1(200, "====== Seek to %lld\n", pos);
534 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
535 print_name(), be.bstrerror());
536 Dmsg1(100, "%s", errmsg);
541 const char *file_dev::print_type()