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\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 Dmsg2(100, "Truncate adata=%d fd=%d\n", dev->adata, dev->m_fd);
239 if (ftruncate(dev->m_fd, 0) != 0) {
241 Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"),
242 print_name(), be.bstrerror());
247 * Check for a successful ftruncate() and issue a work-around for devices
248 * (mostly cheap NAS) that don't support truncation.
249 * Workaround supplied by Martin Schmid as a solution to bug #1011.
252 * 3. open new file with same mode
253 * 4. change ownership to original
256 if (fstat(dev->m_fd, &st) != 0) {
258 Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"),
259 print_name(), be.bstrerror());
263 if (st.st_size != 0) { /* ftruncate() didn't work */
264 POOL_MEM archive_name(PM_FNAME);
266 pm_strcpy(archive_name, dev_name);
267 if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
268 pm_strcat(archive_name, "/");
270 pm_strcat(archive_name, dcr->VolumeName);
271 if (dev->is_adata()) {
272 pm_strcat(archive_name, ADATA_EXTENSION);
275 Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"),
276 print_name(), archive_name.c_str());
278 /* Close file and blow it away */
280 ::unlink(archive_name.c_str());
282 /* Recreate the file -- of course, empty */
283 dev->set_mode(CREATE_READ_WRITE);
284 if ((dev->m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC, st.st_mode)) < 0) {
287 Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(),
289 Dmsg1(40, "reopen failed: %s", errmsg);
290 Emsg0(M_FATAL, 0, errmsg);
294 /* Reset proper owner */
295 chown(archive_name.c_str(), st.st_uid, st.st_gid);
302 * (Un)mount the device
304 bool DEVICE::mount_file(int mount, int dotimeout)
306 POOL_MEM ocmd(PM_FNAME);
310 struct dirent *entry, *result;
311 int status, tries, name_max, count;
316 icmd = device->mount_command;
318 icmd = device->unmount_command;
321 clear_freespace_ok();
322 edit_mount_codes(ocmd, icmd);
324 Dmsg2(100, "mount_file: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
327 /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */
332 results = get_memory(4000);
334 /* If busy retry each second */
335 Dmsg1(100, "mount_file run_prog=%s\n", ocmd.c_str());
336 while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) {
337 /* Doesn't work with internationalization (This is not a problem) */
338 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
341 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
345 /* Sometimes the device cannot be mounted because it is already mounted.
346 * Try to unmount it, then remount it */
348 Dmsg1(400, "Trying to unmount the device %s...\n", print_name());
354 Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
355 (mount ? "" : "un"), status, results, be.bstrerror(status));
356 Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
357 print_name(), (mount ? "" : "un"), be.bstrerror(status));
360 * Now, just to be sure it is not mounted, try to read the filesystem.
362 name_max = pathconf(".", _PC_NAME_MAX);
363 if (name_max < 1024) {
367 if (!(dp = opendir(device->mount_point))) {
370 Dmsg3(100, "mount_file: failed to open dir %s (dev=%s), ERR=%s\n",
371 device->mount_point, print_name(), be.bstrerror());
375 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
378 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
380 Dmsg2(129, "mount_file: failed to find suitable file in dir %s (dev=%s)\n",
381 device->mount_point, print_name());
384 if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
385 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
388 Dmsg2(129, "mount_file: ignoring %s in %s\n", result->d_name, device->mount_point);
394 Dmsg1(100, "mount_file: got %d files in the mount point (not counting ., .. and .keep)\n", count);
397 /* If we got more than ., .. and .keep */
398 /* there must be something mounted */
400 Dmsg1(100, "Did Mount by count=%d\n", count);
403 /* An unmount request. We failed to unmount - report an error */
405 free_pool_memory(results);
406 Dmsg0(200, "== error mount=1 wanted unmount\n");
412 free_pool_memory(results);
413 Dmsg0(200, "============ mount=0\n");
418 set_mounted(mount); /* set/clear mounted flag */
419 free_pool_memory(results);
420 /* Do not check free space when unmounting */
421 Dmsg1(200, "============ mount=%d\n", mount);
426 * Check if the current position on the volume corresponds to
427 * what is in the catalog.
430 bool file_dev::is_eod_valid(DCR *dcr)
434 if (has_cap(CAP_LSEEK)) {
435 char ed1[50], ed2[50];
436 boffset_t ameta_size, adata_size, size;
438 ameta_size = lseek(dcr, (boffset_t)0, SEEK_END);
439 adata_size = get_adata_size(dcr);
440 size = ameta_size + adata_size;
441 if (VolCatInfo.VolCatAmetaBytes == (uint64_t)ameta_size &&
442 VolCatInfo.VolCatAdataBytes == (uint64_t)adata_size) {
444 Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volumes \"%s\""
445 " ameta size=%s adata size=%s\n"), dcr->VolumeName,
446 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed1),
447 edit_uint64_with_commas(VolCatInfo.VolCatAdataBytes, ed2));
449 Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
450 " size=%s\n"), dcr->VolumeName,
451 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed1));
453 } else if ((uint64_t)ameta_size >= VolCatInfo.VolCatAmetaBytes &&
454 (uint64_t)adata_size >= VolCatInfo.VolCatAdataBytes) {
455 if ((uint64_t)ameta_size != VolCatInfo.VolCatAmetaBytes) {
456 Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
457 " The sizes do not match! Metadata Volume=%s Catalog=%s\n"
458 " Correcting Catalog\n"),
459 dcr->VolumeName, edit_uint64_with_commas(ameta_size, ed1),
460 edit_uint64_with_commas(VolCatInfo.VolCatAmetaBytes, ed2));
462 if ((uint64_t)adata_size != VolCatInfo.VolCatAdataBytes) {
463 Jmsg(jcr, M_WARNING, 0, _("For aligned Volume \"%s\":\n"
464 " Aligned sizes do not match! Aligned Volume=%s Catalog=%s\n"
465 " Correcting Catalog\n"),
466 dcr->VolumeName, edit_uint64_with_commas(adata_size, ed1),
467 edit_uint64_with_commas(VolCatInfo.VolCatAdataBytes, ed2));
469 VolCatInfo.VolCatAmetaBytes = ameta_size;
470 VolCatInfo.VolCatAdataBytes = adata_size;
471 VolCatInfo.VolCatBytes = size;
472 VolCatInfo.VolCatFiles = (uint32_t)(size >> 32);
473 if (!dir_update_volume_info(dcr, false, true)) {
474 Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
475 dcr->mark_volume_in_error();
479 Mmsg(jcr->errmsg, _("Bacula cannot write on disk Volume \"%s\" because: "
480 "The sizes do not match! Volume=%s Catalog=%s\n"),
482 edit_uint64_with_commas(size, ed1),
483 edit_uint64_with_commas(VolCatInfo.VolCatBytes, ed2));
484 Jmsg(jcr, M_ERROR, 0, jcr->errmsg);
485 Dmsg0(100, jcr->errmsg);
486 dcr->mark_volume_in_error();
495 * Position device to end of medium (end of data)
496 * Returns: true on succes
499 bool file_dev::eod(DCR *dcr)
506 Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), print_name());
507 Dmsg1(100, "%s", errmsg);
515 clear_eof(); /* remove EOF flag */
516 block_num = file = 0;
523 pos = lseek(dcr, (boffset_t)0, SEEK_END);
524 Dmsg1(200, "====== Seek to %lld\n", pos);
533 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
534 print_name(), be.bstrerror());
535 Dmsg1(100, "%s", errmsg);
540 const char *file_dev::print_type()