Makefiles:
$(SHELL) config.status
(cd scripts; \
- chmod 755 startmysql stopmysql bacula fd startit stopit btraceback; \
- chmod 755 mtx-changer bconsole gconsole devel_bacula)
+ chmod 755 startmysql stopmysql bacula startit stopit btraceback; \
+ chmod 755 mtx-changer bconsole gconsole devel_bacula; \
+ chmod 755 dvd-freespace dvd-writepart)
(cd src/cats; \
chmod 755 create_bacula_database update_bacula_tables make_bacula_tables; \
cd scripts
chmod 755 startmysql stopmysql bacula startit stopit btraceback mtx-changer
+chmod 755 dvd-writepart dvd-freespace
chmod 755 bconsole gconsole mtx-changer devel_bacula logrotate
cd ..
cd scripts
chmod 755 startmysql stopmysql bacula startit stopit btraceback mtx-changer
+chmod 755 dvd-writepart dvd-freespace
chmod 755 bconsole gconsole mtx-changer devel_bacula logrotate
cd ..
#7 Single Job Writing to Multiple Storage Devices
(probably not this version)
-## Integrate web-bacula into a new Bacula project with
- bimagemgr.
## Create a new GUI chapter explaining all the GUI programs.
Autochangers:
-- 7. Implement new Console commands to allow offlining/reserving drives,
- and possibly manipulating the autochanger (much asked for).
- Make "update slots" when pointing to Autochanger, remove
all Volumes from other drives. "update slots all-drives"?
- Document the multiple-drive-changer.txt script.
For 1.37:
-- Add # Job Level date to bsr file
-- Implement "PreferMountedVolumes = yes|no" in Job resource.
-=== rate design
- jcr->last_rate
- jcr->last_runtime
- MA = (last_MA * 3 + rate) / 4
- rate = (bytes - last_bytes) / (runtime - last_runtime)
-- Despool attributes simultaneously with data in a separate
- thread, rejoined at end of data spooling.
-- Implement Files/Bytes,... stats for restore job.
-- Implement Total Bytes Written, ... for restore job.
- Add setting Volume State via Python.
-- Max Vols limit in Pool off by one?
- Make bootstrap file handle multiple MediaTypes (SD)
-- Test restoring into a user restricted directory on Win32 -- see
- bug report.
- --without-openssl breaks at least on Solaris.
- Python:
- Make a callback when Rerun failed levels is called.
- Add global lock on all devices when creating a device structure.
Maybe in 1.37:
-- Add start/end date editing in messages (%t %T, %e?) ...
-- Add ClientDefs similar to JobDefs.
-- Print more info when bextract -p accepts a bad block.
- To mark files as deleted, run essentially a Verify to disk, and
when a file is found missing (MarkId != JobId), then create
a new File record with FileIndex == -1. This could be done
by the FD at the same time as the backup.
+=== rate design
+ jcr->last_rate
+ jcr->last_runtime
+ MA = (last_MA * 3 + rate) / 4
+ rate = (bytes - last_bytes) / (runtime - last_runtime)
+- Max Vols limit in Pool off by one?
+- Implement Files/Bytes,... stats for restore job.
+- Implement Total Bytes Written, ... for restore job.
+- Despool attributes simultaneously with data in a separate
+ thread, rejoined at end of data spooling.
+- 7. Implement new Console commands to allow offlining/reserving drives,
+ and possibly manipulating the autochanger (much asked for).
+- Add start/end date editing in messages (%t %T, %e?) ...
+- Add ClientDefs similar to JobDefs.
+- Print more info when bextract -p accepts a bad block.
- Fix FD JobType to be set before RunBeforeJob in FD.
- Look at adding full Volume and Pool information to a Volume
label so that bscan can get *all* the info.
in an Autochanger.
- Upgrade to MySQL 4.1.12 See:
http://dev.mysql.com/doc/mysql/en/Server_SQL_mode.html
+- Add # Job Level date to bsr file
+- Implement "PreferMountedVolumes = yes|no" in Job resource.
+## Integrate web-bacula into a new Bacula project with
+ bimagemgr.
+
General:
Changes to 1.37.24:
+18Jun05
+- DVD writing/reading seems to be mostly working.
+- Set execute bits on dvd-freespace and dvd-writepart
+- Make dvd-freespace use existing dummy file.
+- Modify dvd-freespace to pickup size from Track Size:
16Jun05
- Add Date, Job, level to updates to .bsr file in
dird/backup.c
import popen2
import os
import errno
-import tempfile
import sys
if len(sys.argv) != 3:
sys.exit(0)
if os.WEXITSTATUS(status) != 0:
print -errno.EPIPE
- print 'Cannot get media info.'
+ print "Cannot get media info from " + dvdrwmediainfo
sys.exit(0)
while 1:
result = processi.fromchild.readline()
+ if result.find("Track Size:") > -1:
+ index = result.find("*2KB")
+ if index > 0:
+ return long(result[12:index]) * 2048
+ else:
+ print -errno.EPIPE
+ print "Invalid format in media info lead-out line from " + dvdrwmediainfo
+ sys.exit(0)
if result.find("Legacy lead-out at:") > -1:
index = result.find("=")
if index > -1:
print -errno.EPIPE
print "Invalid format in media info lead-out line from " + dvdrwmediainfo
sys.exit(0)
- return int(res)
+ return long(res)
else:
print -errno.EPIPE
print "Invalid format in media info lead-out line from " + dvdrwmediainfo
print "Cannot get media lead-out index from " + dvdrwmediainfo
sys.exit(0)
-tmpfile = tempfile.NamedTemporaryFile()
if part_num == 0:
flag = "-Z"
else:
flag = "-M"
-cmd=growisofs + " " + growisofsparams + " -use-the-force-luke=tty -dry-run -quiet " + flag + " " + device + " -R " + tmpfile.name
+# the growisofs at the end is a dummy
+cmd=growisofs + " " + growisofsparams + " -use-the-force-luke=tty -dry-run -quiet " + flag + " " + device + " -R " + growisofs
process = popen2.Popen4(cmd)
status = process.wait()
if not os.WIFEXITED(status):
print -errno.EPIPE
print "Wrong seek argument in the output from " + growisofs
sys.exit(0)
- size = int(res)*32*1024
+ size = long(res)*32*1024
size = gettotalsize()-(size+margin)
if size < 0:
size = 0
print size
- print "No error occured"
+ print "No error occurred"
sys.exit(0)
#GROWARGS="${GROWARGS} -use-the-force-luke=notray"
# Uncomment the following line if you have a Linux kernel >=2.6.8, and
-# if you want to allow a session to start behind the 4gb boundary.
+# if you want to allow a session to start beyond the 4gb boundary.
#GROWARGS="${GROWARGS} -use-the-force-luke=4gms"
#### You should probably not modify anything below this line
#include "jcr.h"
int execvp_errors[] = {EACCES, ENOEXEC, EFAULT, EINTR, E2BIG,
- ENAMETOOLONG, ENOMEM, ETXTBSY, ENOENT};
+ ENAMETOOLONG, ENOMEM, ETXTBSY, ENOENT};
int num_execvp_errors = (int)(sizeof(execvp_errors)/sizeof(int));
tprog = get_pool_memory(PM_FNAME);
pm_strcpy(tprog, prog);
build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
-#ifdef xxxxxx
+#ifdef xxxxxx
printf("argc=%d\n", bargc);
for (i=0; i<bargc; i++) {
printf("argc=%d argv=%s:\n", i, bargv[i]);
if (mode_read && pipe(readp) == -1) {
save_errno = errno;
if (mode_write) {
- close(writep[0]);
- close(writep[1]);
+ close(writep[0]);
+ close(writep[1]);
}
free(bpipe);
errno = save_errno;
}
/* Start worker process */
switch (bpipe->worker_pid = fork()) {
- case -1: /* error */
+ case -1: /* error */
save_errno = errno;
if (mode_write) {
- close(writep[0]);
- close(writep[1]);
+ close(writep[0]);
+ close(writep[1]);
}
if (mode_read) {
- close(readp[0]);
- close(readp[1]);
+ close(readp[0]);
+ close(readp[1]);
}
free(bpipe);
errno = save_errno;
return NULL;
- case 0: /* child */
+ case 0: /* child */
if (mode_write) {
- close(writep[1]);
- dup2(writep[0], 0); /* Dup our write to his stdin */
+ close(writep[1]);
+ dup2(writep[0], 0); /* Dup our write to his stdin */
}
if (mode_read) {
- close(readp[0]); /* Close unused child fds */
- dup2(readp[1], 1); /* dup our read to his stdout */
- dup2(readp[1], 2); /* and his stderr */
+ close(readp[0]); /* Close unused child fds */
+ dup2(readp[1], 1); /* dup our read to his stdout */
+ dup2(readp[1], 2); /* and his stderr */
}
- closelog(); /* close syslog if open */
- for (i=3; i<=32; i++) { /* close any open file descriptors */
- close(i);
+ closelog(); /* close syslog if open */
+ for (i=3; i<=32; i++) { /* close any open file descriptors */
+ close(i);
}
- execvp(bargv[0], bargv); /* call the program */
+ execvp(bargv[0], bargv); /* call the program */
/* Convert errno into an exit code for later analysis */
for (i=0; i< num_execvp_errors; i++) {
- if (execvp_errors[i] == errno) {
- exit(200 + i); /* exit code => errno */
- }
+ if (execvp_errors[i] == errno) {
+ exit(200 + i); /* exit code => errno */
+ }
}
- exit(255); /* unknown errno */
+ exit(255); /* unknown errno */
- default: /* parent */
+ default: /* parent */
break;
}
if (mode_read) {
- close(readp[1]); /* close unused parent fds */
+ close(readp[1]); /* close unused parent fds */
bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
}
if (mode_write) {
if (bpipe->wfd) {
fflush(bpipe->wfd);
if (fclose(bpipe->wfd) != 0) {
- stat = 0;
+ stat = 0;
}
bpipe->wfd = NULL;
}
* Close both pipes and free resources
*
* Returns: 0 on success
- * berrno on failure
+ * berrno on failure
*/
int close_bpipe(BPIPE *bpipe)
{
}
if (bpipe->wait == 0) {
- wait_option = 0; /* wait indefinitely */
+ wait_option = 0; /* wait indefinitely */
} else {
wait_option = WNOHANG; /* don't hang */
}
for ( ;; ) {
Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
do {
- wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
+ wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
} while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
if (wpid == bpipe->worker_pid || wpid == -1) {
- stat = errno;
+ stat = errno;
Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
wpid==-1?strerror(errno):"none");
- break;
+ break;
}
Dmsg3(800, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
wpid==-1?strerror(errno):"none");
if (remaining_wait > 0) {
- bmicrosleep(1, 0); /* wait one second */
- remaining_wait--;
+ bmicrosleep(1, 0); /* wait one second */
+ remaining_wait--;
} else {
- stat = ETIME; /* set error status */
- wpid = -1;
+ stat = ETIME; /* set error status */
+ wpid = -1;
break; /* don't wait any longer */
}
}
if (wpid > 0) {
if (WIFEXITED(chldstatus)) { /* process exit()ed */
- stat = WEXITSTATUS(chldstatus);
- if (stat != 0) {
+ stat = WEXITSTATUS(chldstatus);
+ if (stat != 0) {
Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
- stat |= b_errno_exit; /* exit status returned */
- }
+ stat |= b_errno_exit; /* exit status returned */
+ }
Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
} else if (WIFSIGNALED(chldstatus)) { /* process died */
- stat = WTERMSIG(chldstatus);
+ stat = WTERMSIG(chldstatus);
Dmsg1(800, "Child died from signale %d\n", stat);
- stat |= b_errno_signal; /* exit signal returned */
+ stat |= b_errno_signal; /* exit signal returned */
}
}
if (bpipe->timer_id) {
* Contrary to my normal calling conventions, this program
*
* Returns: 0 on success
- * non-zero on error == berrno status
+ * non-zero on error == berrno status
*/
int run_program(char *prog, int wait, POOLMEM *results)
{
results[0] = 0;
fgets(results, sizeof_pool_memory(results), bpipe->rfd);
if (feof(bpipe->rfd)) {
- stat1 = 0;
+ stat1 = 0;
} else {
- stat1 = ferror(bpipe->rfd);
+ stat1 = ferror(bpipe->rfd);
}
if (stat1 < 0) {
Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
* Contrary to my normal calling conventions, this program
*
* Returns: 0 on success
- * non-zero on error == berrno status
+ * non-zero on error == berrno status
*
*/
int run_program_full_output(char *prog, int wait, POOLMEM *results)
Dmsg1(800, "Run program fgets=%s", tmp);
pm_strcat(results, tmp);
if (feof(bpipe->rfd)) {
- stat1 = 0;
- Dmsg1(100, "Run program fgets stat=%d\n", stat1);
- break;
+ stat1 = 0;
+ Dmsg1(900, "Run program fgets stat=%d\n", stat1);
+ break;
} else {
- stat1 = ferror(bpipe->rfd);
+ stat1 = ferror(bpipe->rfd);
}
if (stat1 < 0) {
- Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
- break;
+ Dmsg2(900, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
+ break;
} else if (stat1 != 0) {
- Dmsg1(100, "Run program fgets stat=%d\n", stat1);
+ Dmsg1(900, "Run program fgets stat=%d\n", stat1);
}
}
stat2 = close_bpipe(bpipe);
stat1 = stat2 != 0 ? stat2 : stat1;
- Dmsg1(100, "Run program returning %d\n", stat);
+ Dmsg1(900, "Run program returning %d\n", stat);
free_pool_memory(tmp);
return stat1;
}
}
if (*p) {
while (*p && argc < MAX_ARGV) {
- q = p;
- if (quote) {
- while (*q && *q != quote)
- q++;
- quote = 0;
- } else {
+ q = p;
+ if (quote) {
+ while (*q && *q != quote)
+ q++;
+ quote = 0;
+ } else {
while (*q && *q != ' ')
- q++;
- }
- if (*q)
+ q++;
+ }
+ if (*q)
*(q++) = '\0';
- bargv[argc++] = p;
- p = q;
+ bargv[argc++] = p;
+ p = q;
while (*p && (*p == ' ' || *p == '\t'))
- p++;
+ p++;
if (*p == '\"' || *p == '\'') {
- quote = *p;
- p++;
- }
+ quote = *p;
+ p++;
+ }
}
}
*bargc = argc;
if (already_dead) {
exit(1);
}
- Dmsg2(200, "sig=%d %s\n", sig, sig_names[sig]);
+ Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
/* Ignore certain signals -- SIGUSR2 used to interrupt threads */
if (sig == SIGCHLD || sig == SIGUSR2) {
return;
int exelen = strlen(exepath);
fprintf(stderr, "Kaboom! %s, %s got signal %d. Attempting traceback.\n",
- exename, my_name, sig);
+ exename, my_name, sig);
fprintf(stderr, "Kaboom! exepath=%s\n", exepath);
if (exelen + 12 > (int)sizeof(btpath)) {
- bstrncpy(btpath, "btraceback", sizeof(btpath));
+ bstrncpy(btpath, "btraceback", sizeof(btpath));
} else {
- bstrncpy(btpath, exepath, sizeof(btpath));
- if (btpath[exelen-1] == '/') {
- btpath[exelen-1] = 0;
- }
- bstrncat(btpath, "/btraceback", sizeof(btpath));
+ bstrncpy(btpath, exepath, sizeof(btpath));
+ if (btpath[exelen-1] == '/') {
+ btpath[exelen-1] = 0;
+ }
+ bstrncat(btpath, "/btraceback", sizeof(btpath));
}
if (exepath[exelen-1] != '/') {
- strcat(exepath, "/");
+ strcat(exepath, "/");
}
strcat(exepath, exename);
if (!working_directory) {
- working_directory = buf;
- *buf = 0;
+ working_directory = buf;
+ *buf = 0;
}
if (*working_directory == 0) {
- strcpy((char *)working_directory, "/tmp/");
+ strcpy((char *)working_directory, "/tmp/");
}
if (chdir(working_directory) != 0) { /* dump in working directory */
- berrno be;
- Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory, be.strerror());
- strcpy((char *)working_directory, "/tmp/");
+ berrno be;
+ Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory, be.strerror());
+ strcpy((char *)working_directory, "/tmp/");
}
unlink("./core"); /* get rid of any old core file */
sprintf(pid_buf, "%d", (int)main_pid);
Dmsg1(300, "btpath=%s\n", btpath);
Dmsg1(300, "exepath=%s\n", exepath);
switch (pid = fork()) {
- case -1: /* error */
- fprintf(stderr, "Fork error: ERR=%s\n", strerror(errno));
- break;
- case 0: /* child */
- argv[0] = btpath; /* path to btraceback */
- argv[1] = exepath; /* path to exe */
- argv[2] = pid_buf;
- argv[3] = (char *)NULL;
- fprintf(stderr, "Calling: %s %s %s\n", btpath, exepath, pid_buf);
- if (execv(btpath, argv) != 0) {
- printf("execv: %s failed: ERR=%s\n", btpath, strerror(errno));
- }
- exit(-1);
- default: /* parent */
- break;
+ case -1: /* error */
+ fprintf(stderr, "Fork error: ERR=%s\n", strerror(errno));
+ break;
+ case 0: /* child */
+ argv[0] = btpath; /* path to btraceback */
+ argv[1] = exepath; /* path to exe */
+ argv[2] = pid_buf;
+ argv[3] = (char *)NULL;
+ fprintf(stderr, "Calling: %s %s %s\n", btpath, exepath, pid_buf);
+ if (execv(btpath, argv) != 0) {
+ printf("execv: %s failed: ERR=%s\n", btpath, strerror(errno));
+ }
+ exit(-1);
+ default: /* parent */
+ break;
}
/* Parent continue here, waiting for child */
sigdefault.sa_flags = 0;
sigaction(sig, &sigdefault, NULL);
if (pid > 0) {
- Dmsg0(500, "Doing waitpid\n");
- waitpid(pid, NULL, 0); /* wait for child to produce dump */
- fprintf(stderr, "Traceback complete, attempting cleanup ...\n");
- Dmsg0(500, "Done waitpid\n");
- exit_handler(sig); /* clean up if possible */
- Dmsg0(500, "Done exit_handler\n");
+ Dmsg0(500, "Doing waitpid\n");
+ waitpid(pid, NULL, 0); /* wait for child to produce dump */
+ fprintf(stderr, "Traceback complete, attempting cleanup ...\n");
+ Dmsg0(500, "Done waitpid\n");
+ exit_handler(sig); /* clean up if possible */
+ Dmsg0(500, "Done exit_handler\n");
} else {
- Dmsg0(500, "Doing sleep\n");
- bmicrosleep(30, 0);
+ Dmsg0(500, "Doing sleep\n");
+ bmicrosleep(30, 0);
}
fprintf(stderr, "It looks like the traceback worked ...\n");
}
sigfillset(&sigdefault.sa_mask);
- sigaction(SIGPIPE, &sigignore, NULL);
- sigaction(SIGCHLD, &sighandle, NULL);
- sigaction(SIGCONT, &sigignore, NULL);
- sigaction(SIGPROF, &sigignore, NULL);
- sigaction(SIGWINCH, &sigignore, NULL);
- sigaction(SIGIO, &sighandle, NULL);
+ sigaction(SIGPIPE, &sigignore, NULL);
+ sigaction(SIGCHLD, &sighandle, NULL);
+ sigaction(SIGCONT, &sigignore, NULL);
+ sigaction(SIGPROF, &sigignore, NULL);
+ sigaction(SIGWINCH, &sigignore, NULL);
+ sigaction(SIGIO, &sighandle, NULL);
- sigaction(SIGINT, &sigdefault, NULL);
- sigaction(SIGXCPU, &sigdefault, NULL);
- sigaction(SIGXFSZ, &sigdefault, NULL);
+ sigaction(SIGINT, &sigdefault, NULL);
+ sigaction(SIGXCPU, &sigdefault, NULL);
+ sigaction(SIGXFSZ, &sigdefault, NULL);
- sigaction(SIGHUP, &sigignore, NULL);
- sigaction(SIGQUIT, &sighandle, NULL);
- sigaction(SIGILL, &sighandle, NULL);
- sigaction(SIGTRAP, &sighandle, NULL);
-/* sigaction(SIGABRT, &sighandle, NULL); */
+ sigaction(SIGHUP, &sigignore, NULL);
+ sigaction(SIGQUIT, &sighandle, NULL);
+ sigaction(SIGILL, &sighandle, NULL);
+ sigaction(SIGTRAP, &sighandle, NULL);
+/* sigaction(SIGABRT, &sighandle, NULL); */
#ifdef SIGEMT
- sigaction(SIGEMT, &sighandle, NULL);
+ sigaction(SIGEMT, &sighandle, NULL);
#endif
#ifdef SIGIOT
-/* sigaction(SIGIOT, &sighandle, NULL); used by debugger */
+/* sigaction(SIGIOT, &sighandle, NULL); used by debugger */
#endif
- sigaction(SIGBUS, &sighandle, NULL);
- sigaction(SIGFPE, &sighandle, NULL);
- sigaction(SIGKILL, &sighandle, NULL);
- sigaction(SIGUSR1, &sighandle, NULL);
- sigaction(SIGSEGV, &sighandle, NULL);
- sigaction(SIGUSR2, &sighandle, NULL);
- sigaction(SIGALRM, &sighandle, NULL);
- sigaction(SIGTERM, &sighandle, NULL);
+ sigaction(SIGBUS, &sighandle, NULL);
+ sigaction(SIGFPE, &sighandle, NULL);
+ sigaction(SIGKILL, &sighandle, NULL);
+ sigaction(SIGUSR1, &sighandle, NULL);
+ sigaction(SIGSEGV, &sighandle, NULL);
+ sigaction(SIGUSR2, &sighandle, NULL);
+ sigaction(SIGALRM, &sighandle, NULL);
+ sigaction(SIGTERM, &sighandle, NULL);
#ifdef SIGSTKFLT
sigaction(SIGSTKFLT, &sighandle, NULL);
#endif
- sigaction(SIGSTOP, &sighandle, NULL);
- sigaction(SIGTSTP, &sighandle, NULL);
- sigaction(SIGTTIN, &sighandle, NULL);
- sigaction(SIGTTOU, &sighandle, NULL);
- sigaction(SIGURG, &sighandle, NULL);
+ sigaction(SIGSTOP, &sighandle, NULL);
+ sigaction(SIGTSTP, &sighandle, NULL);
+ sigaction(SIGTTIN, &sighandle, NULL);
+ sigaction(SIGTTOU, &sighandle, NULL);
+ sigaction(SIGURG, &sighandle, NULL);
sigaction(SIGVTALRM, &sighandle, NULL);
#ifdef SIGPWR
- sigaction(SIGPWR, &sighandle, NULL);
+ sigaction(SIGPWR, &sighandle, NULL);
#endif
#ifdef SIGWAITING
sigaction(SIGWAITING,&sighandle, NULL);
#endif
#ifdef SIGLWP
- sigaction(SIGLWP, &sighandle, NULL);
+ sigaction(SIGLWP, &sighandle, NULL);
#endif
#ifdef SIGFREEZE
sigaction(SIGFREEZE, &sighandle, NULL);
#endif
#ifdef SIGTHAW
- sigaction(SIGTHAW, &sighandle, NULL);
+ sigaction(SIGTHAW, &sighandle, NULL);
#endif
#ifdef SIGCANCEL
sigaction(SIGCANCEL, &sighandle, NULL);
#endif
#ifdef SIGLOST
- sigaction(SIGLOST, &sighandle, NULL);
+ sigaction(SIGLOST, &sighandle, NULL);
#endif
}
#endif
/* If the device requires mount, close it, so the device can be ejected.
* FIXME: This should perhaps be done for all devices. */
- if (dev_cap(dev, CAP_REQMOUNT)) {
+ if (dev->requires_mount()) {
force_close_device(dev);
}
create_restore_volume_list(jcr);
if (mode) { /* read only access? */
+ Dmsg0(100, "Acquire device for read\n");
if (!acquire_device_for_read(dcr)) {
return NULL;
}
* - Check that the mount point is available
* - Check that (un)mount commands are defined
*/
- if (dev->is_file() && device->cap_bits & CAP_REQMOUNT) {
+ if (dev->is_file() && dev->requires_mount()) {
if (stat(device->mount_point, &statp) < 0) {
berrno be;
dev->dev_errno = errno;
VolCatInfo.VolCatName[0] = 0;
}
- Dmsg3(29, "open dev: tape=%d dev_name=%s vol=%s\n", is_tape(),
- dev_name, VolCatInfo.VolCatName);
+ Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%d\n", is_tape(),
+ dev_name, VolCatInfo.VolCatName, mode);
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
label_type = B_BACULA_LABEL;
if (is_tape() || is_fifo()) {
open_tape_device(this, mode);
} else {
+ Dmsg1(100, "call open_file_device mode=%d\n", mode);
open_file_device(this, mode);
}
return fd;
{
POOL_MEM archive_name(PM_FNAME);
struct stat filestat;
+
/*
* Handle opening of File Archive (not a tape)
*/
- if (dev->part == 0) {
- dev->file_size = 0;
- }
- dev->part_size = 0;
-
- /* if num_parts has not been set, but VolCatInfo is available, copy
- * it from the VolCatInfo.VolCatParts */
- if (dev->num_parts < dev->VolCatInfo.VolCatParts) {
- dev->num_parts = dev->VolCatInfo.VolCatParts;
- }
-
+ Dmsg3(29, "Enter: open_file_dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
+ archive_name.c_str(), mode);
+
if (dev->VolCatInfo.VolCatName[0] == 0) {
Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"),
dev->print_name());
dev->fd = -1;
return;
}
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
- if (mount_dev(dev, 1) < 0) {
- Mmsg(dev->errmsg, _("Could not mount device %s.\n"),
- dev->print_name());
- Emsg0(M_FATAL, 0, dev->errmsg);
- dev->fd = -1;
- return;
+ if (dev->is_dvd()) {
+ if (dev->part == 0) {
+ dev->file_size = 0;
+ }
+ dev->part_size = 0;
+
+ /* if num_parts has not been set, but VolCatInfo is available, copy
+ * it from the VolCatInfo.VolCatParts */
+ if (dev->num_parts < dev->VolCatInfo.VolCatParts) {
+ dev->num_parts = dev->VolCatInfo.VolCatParts;
+ }
+
+ get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+
+ if (mount_dev(dev, 1) < 0) {
+ Mmsg(dev->errmsg, _("Could not mount device %s.\n"),
+ dev->print_name());
+ Emsg0(M_FATAL, 0, dev->errmsg);
+ dev->fd = -1;
+ return;
+ }
+ } else {
+ get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
}
- Dmsg3(29, "open dev: device is %s (mode:%d)\n", dev->is_dvd()?"DVD":"disk",
+ Dmsg3(29, "open dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
archive_name.c_str(), mode);
dev->openmode = mode;
Dmsg5(29, "open dev: %s fd=%d opened, part=%d/%d, part_size=%u\n",
dev->is_dvd()?"DVD":"disk", dev->fd, dev->part, dev->num_parts,
dev->part_size);
- if (dev->is_dvd() && (dev->mode != OPEN_READ_ONLY) &&
+ if (dev->is_dvd() && (mode != OPEN_READ_ONLY) &&
(dev->free_space_errno == 0 || dev->num_parts == dev->part)) {
update_free_space_dev(dev);
}
if (dev->num_parts > 0) {
dev->num_parts = 0;
dev->VolCatInfo.VolCatParts = 0;
- if (open_first_part(dev) < 0) {
+ if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
berrno be;
Mmsg1(dev->errmsg, "Unable to truncate device, because I'm unable to open the first part. ERR=%s\n", be.strerror());
}
/* Methods */
int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
+ int requires_mount() const { return capabilities & CAP_REQMOUNT; }
int is_tape() const { return state & ST_TAPE; }
int is_file() const { return state & ST_FILE; }
int is_fifo() const { return state & ST_FIFO; }
}
bail_out:
+ if (!dev->is_open()) {
+ free_volume(dev);
+ }
give_back_device_lock(dev, &hold);
return;
}
char partnumber[20];
if (dev->is_dvd()) {
- /* If we try to open the last part, just open it from disk,
- * otherwise, open it from the spooling directory */
- if (dev->part < dev->num_parts) {
+ /* If we try to open the last part, just open it from disk,
+ * otherwise, open it from the spooling directory.
+ */
+ Dmsg2(100, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
+ if (dev->num_parts == 0 || dev->part < dev->num_parts) {
pm_strcpy(archive_name, dev->device->mount_point);
} else {
/* Use the working directory if spool directory is not defined */
*/
bool mount_dev(DEVICE* dev, int timeout)
{
+ Dmsg0(900, "Enter mount_dev\n");
if (dev->is_mounted()) {
- Dmsg0(100, "mount_dev: Device already mounted\n");
return true;
- } else if (dev_cap(dev, CAP_REQMOUNT)) {
+ } else if (dev->requires_mount()) {
return do_mount_dev(dev, 1, timeout);
}
return true;
*/
bool unmount_dev(DEVICE *dev, int timeout)
{
+ Dmsg0(900, "Enter unmount_dev\n");
if (dev->is_mounted()) {
return do_mount_dev(dev, 0, timeout);
}
- Dmsg0(100, "mount_dev: Device already unmounted\n");
return true;
}
{
POOL_MEM ocmd(PM_FNAME);
POOLMEM* results;
- results = get_pool_memory(PM_MESSAGE);
char* icmd;
int status, timeout;
edit_device_codes_dev(dev, ocmd.c_str(), icmd);
- Dmsg2(29, "do_mount_dev: cmd=%s state=%d\n", ocmd.c_str(), dev->is_mounted());
+ Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), dev->is_mounted());
if (dotimeout) {
- /* Try at most 5 times to (un)mount the device. This should perhaps be configurable. */
- timeout = 5;
- }
- else {
+ /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
+ timeout = 1;
+ } else {
timeout = 0;
}
+ results = get_pool_memory(PM_MESSAGE);
/* If busy retry each second */
while ((status = run_program_full_output(ocmd.c_str(),
dev->max_open_wait/2, results)) != 0) {
- if (--timeout > 0) {
- Dmsg2(40, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results);
+ if (timeout-- > 0) {
+ Dmsg2(400, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results);
/* Sometimes the device cannot be mounted because it is already mounted.
* Try to unmount it, then remount it */
if (mount) {
- Dmsg1(40, "Trying to unmount the device %s...\n", dev->dev_name);
+ Dmsg1(400, "Trying to unmount the device %s...\n", dev->dev_name);
do_mount_dev(dev, 0, 0);
}
bmicrosleep(1, 0);
}
dev->set_mounted(mount); /* set/clear mounted flag */
+ free_pool_memory(results);
get_out:
- free_pool_memory(results);
- Dmsg1(29, "do_mount_dev: end_state=%d\n", dev->is_mounted());
+ Dmsg1(29, "Exit do_mount_dev: mounted=%d\n", dev->is_mounted());
return true;
}
-/* Only for devices that require a mount.
- * Try to find the Volume name of the loaded device, and open the
- * first part of this volume.
+/* Only for devices that require a mount -- currently DVDs only
+ *
+ * Try to find the Volume name of the loaded device.
+ *
+ * Returns true if read_dev_volume_label can now read the label,
+ * NOTE!!! at this point the device may not be
+ * opened.
+ * Maybe it should open the first part. ***FIXME***
*
- * Returns 0 if read_dev_volume_label can now read the label,
- * -1 if an error occured, and read_dvd_volume_label
- * must abort with an IO_ERROR.
+ * false if an error occured, and read_dvd_volume_label
+ * must abort with an IO_ERROR.
*
* To find the Volume name, it lists all the files on the DVD,
* and searches for a file which has a minimum size (500 bytes).
* the label name of the current volume. We can also check that the currently
* mounted disk is writable. (See also read_dev_volume_label_guess in label.c).
*
- * Note that if the right volume is mounted, open_mounted_dev returns
- * the same result as an usual dev->open().
*/
-int open_mounted_dev(DEVICE *dev)
+bool can_open_mounted_dev(DEVICE *dev)
{
- Dmsg1(29, "open_mounted_dev: dev=%s\n", dev->dev_name);
+ Dmsg1(29, "Enter: dev=%s\n", dev->dev_name);
POOL_MEM guessedname(PM_FNAME);
DIR* dp;
struct dirent *entry, *result;
int name_max;
if (!dev->is_dvd()) {
- Dmsg1(100, "open_mounted_dev: device does not require mount, returning 0. dev=%s\n", dev->dev_name);
- return 0;
+ Dmsg1(100, "device does not require mount, returning 0. dev=%s\n", dev->dev_name);
+ return true;
}
#ifndef HAVE_DIRENT_H
- Dmsg0(29, "open_mounted_dev: readdir not available, cannot guess volume name\n");
- return 0;
+ Dmsg0(29, "readdir not available, cannot guess volume name\n");
+ return true;
#endif
update_free_space_dev(dev);
if (mount_dev(dev, 1) < 0) {
/* If the device cannot be mounted, check if it is writable */
if (dev->have_media()) {
- Dmsg1(100, "open_mounted_dev: device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name);
- return 0;
+ Dmsg1(100, "device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name);
+ return true;
} else {
- Dmsg1(100, "open_mounted_dev: device cannot be mounted, and is not writable, returning -1. dev=%s\n", dev->dev_name);
- return -1;
+ Dmsg1(100, "device cannot be mounted, and is not writable, returning -1. dev=%s\n", dev->dev_name);
+ return false;
}
}
if (!(dp = opendir(dev->device->mount_point))) {
berrno be;
dev->dev_errno = errno;
- Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
- return -1;
+ Dmsg3(29, "failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
+ return false;
}
entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
while (1) {
if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
dev->dev_errno = ENOENT;
- Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
+ Dmsg2(29, "failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
closedir(dp);
- return -1;
+ free(entry);
+ return false;
}
ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
if (stat(guessedname.c_str(), &statp) < 0) {
berrno be;
- Dmsg3(29, "open_mounted_dev: failed to stat %s (dev=%s), ERR=%s\n",
+ Dmsg3(29, "failed to stat %s (dev=%s), ERR=%s\n",
guessedname.c_str(), dev->dev_name, be.strerror());
continue;
}
if (!S_ISREG(statp.st_mode) || (statp.st_size < 500)) {
- Dmsg2(100, "open_mounted_dev: %s is not a regular file, or less than 500 bytes (dev=%s)\n",
+ Dmsg2(100, "%s is not a regular file, or less than 500 bytes (dev=%s)\n",
guessedname.c_str(), dev->dev_name);
continue;
}
if ((stat(guessedname.c_str(), &statp) < 0) || (statp.st_size < 500)) {
/* The file with extension truncated does not exists or is too small, so use it with its extension. */
berrno be;
- Dmsg3(100, "open_mounted_dev: failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n",
+ Dmsg3(100, "failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n",
guessedname.c_str(), dev->dev_name, be.strerror());
pm_strcpy(guessedname, dev->device->mount_point);
if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') {
}
break;
}
-
closedir(dp);
+ free(entry);
if (dev->fd >= 0) {
close(dev->fd);
}
+ Dmsg1(100, "open(%s) read-only\n", guessedname.c_str());
if ((dev->fd = open(guessedname.c_str(), O_RDONLY | O_BINARY)) < 0) {
berrno be;
dev->dev_errno = errno;
- Dmsg3(29, "open_mounted_dev: failed to open %s (dev=%s), ERR=%s\n",
+ Dmsg3(29, "failed to open %s (dev=%s), ERR=%s\n",
guessedname.c_str(), dev->dev_name, be.strerror());
- if (open_first_part(dev) < 0) {
+ Dmsg0(100, "Call open_first_part\n");
+ if (open_first_part(dev, OPEN_READ_ONLY) < 0) {
berrno be;
dev->dev_errno = errno;
Mmsg1(&dev->errmsg, _("Could not open_first_part, ERR=%s\n"), be.strerror());
Emsg0(M_FATAL, 0, dev->errmsg);
}
- return -1;
+ return false;
}
dev->part_start = 0;
dev->part_size = statp.st_size;
dev->part = 0;
dev->set_opened();
dev->use_count = 1;
+ Dmsg2(29, "Exit: %s opened (dev=%s)\n", guessedname.c_str(), dev->dev_name);
- Dmsg2(29, "open_mounted_dev: %s opened (dev=%s)\n", guessedname.c_str(), dev->dev_name);
-
- return 0;
+ return true;
}
dev->dev_errno = EIO;
free_pool_memory(results);
return -1;
- }
- else {
+ } else {
Dmsg1(29, "dvd_write_part: command output=%s\n", results);
POOL_MEM archive_name(PM_FNAME);
get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
int open_next_part(DEVICE *dev)
{
- Dmsg3(29, "open_next_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode);
+ Dmsg3(29, "Enter: open_next_part %s %s %d\n", dev->dev_name,
+ dev->VolCatInfo.VolCatName, dev->openmode);
/* When appending, do not open a new part if the current is empty */
if (dev->can_append() && (dev->part == dev->num_parts) &&
(dev->part_size == 0)) {
* - Close the fd
* - Reopen the device
*/
-int open_first_part(DEVICE *dev)
+int open_first_part(DEVICE *dev, int mode)
{
- Dmsg3(29, "open_first_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode);
+ Dmsg3(29, "Enter: open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name,
+ dev->VolCatInfo.VolCatName, dev->openmode);
if (dev->fd >= 0) {
close(dev->fd);
}
dev->part_start = 0;
dev->part = 0;
- Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName,
- dev->openmode);
- if (dev->open(dev->VolCatInfo.VolCatName, dev->openmode) < 0) {
+ Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dev->VolCatInfo.VolCatName,
+ mode);
+ if (dev->open(dev->VolCatInfo.VolCatName, mode) < 0) {
Dmsg0(50, "open dev() failed\n");
return -1;
}
* We need to access a previous part,
* so just load the first one, and seek again
* until the right one is loaded */
- if (open_first_part(dev) < 0) {
+ if (open_first_part(dev, dev->openmode) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
return -1;
}
* This is the only way to be sure we compute the right file address. */
/* Save previous openmode, and open all but last part read-only (useful for DVDs) */
openmode = dev->openmode;
- dev->openmode = OPEN_READ_ONLY;
/* Works because num_parts > 0. */
- if (open_first_part(dev) < 0) {
+ if (open_first_part(dev, OPEN_READ_ONLY) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
return -1;
}
int vol_label_status;
DEVICE *dev = dcr->dev;
JCR *jcr = dcr->jcr;
- Dmsg3(100, "Enter read_dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
+ Dmsg3(100, "Enter: dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
dev->print_name(), dcr->VolumeName, dev->VolHdr.VolumeName);
if (!dev->is_dvd()) {
* For mounted devices, try to guess the Volume name
* and read the label if possible.
*/
- if (open_mounted_dev(dev) < 0) {
+ if (!can_open_mounted_dev(dev)) {
if (!write || dcr->VolCatInfo.VolCatParts > 0) {
Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
dev->print_name(), dcr->VolumeName);
return VOL_NO_LABEL;
}
- if (write && dev->free_space_errno < 0) {
- Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
+ /* At this point, we are writing */
+ if (dev->free_space_errno < 0) {
+ Dmsg0(100, "Exit: read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
dev->print_name(), dev->errmsg);
return VOL_NO_MEDIA;
* If we can't guess the name, and we are writing,
* just reopen the right file with open_first_part.
*/
- if (open_first_part(dev) < 0) {
+ if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
berrno be;
Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
dev->print_name(), be.strerror());
Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
return read_dev_volume_label(dcr);
+
} else {
+ /*
+ * If we get here, we can open the mounted device
+ */
if (write && dcr->dev->free_space_errno < 0) {
Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
return VOL_NO_MEDIA;
}
- vol_label_status = read_dev_volume_label(dcr);
-
if (!write || dcr->VolCatInfo.VolCatParts > 0) {
- Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
- return vol_label_status;
+ Dmsg0(100, "Exit: read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
+ return read_dev_volume_label(dcr);
}
- if (open_first_part(dcr->dev) < 0) {
+ /* At this point, we are writing */
+ if (open_first_part(dcr->dev, OPEN_READ_WRITE) < 0) {
berrno be;
Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
dev->print_name(), be.strerror());
Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
return VOL_IO_ERROR;
}
+ vol_label_status = read_dev_volume_label(dcr);
/* When writing, if the guessed volume name is not the right volume name,
* report the error, otherwise, just continue with the right file.
}
ask = true;
/* Needed, so the medium can be changed */
- if (dev_cap(dev, CAP_REQMOUNT)) {
+ if (dev->requires_mount()) {
close_device(dev);
}
goto mount_next_vol;
/* From dev.c */
DEVICE *init_dev(JCR *jcr, DEVRES *device);
off_t lseek_dev(DEVICE *dev, off_t offset, int whence);
-int open_first_part(DEVICE *dev);
+int open_first_part(DEVICE *dev, int mode);
int open_next_part(DEVICE *dev);
-int open_mounted_dev(DEVICE *dev);
+bool can_open_mounted_dev(DEVICE *dev);
bool truncate_dev(DEVICE *dev);
void term_dev(DEVICE *dev);
char * strerror_dev(DEVICE *dev);
bool ok;
int Copy, Stripe;
DIRSTORE *store;
- char *device_name;
RCTX rctx;
rctx.jcr = jcr;
#ifdef implemented
#ifdef DEVELOPER
/* This loop is debug code and can be removed */
/* ***FIXME**** remove after 1.38 release */
+ char *device_name;
foreach_alist(store, jcr->dirstore) {
Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n",
store->name, store->media_type, store->pool_name,
/* */
#undef VERSION
#define VERSION "1.37.24"
-#define BDATE "16 June 2005"
-#define LSMDATE "16Jun05"
+#define BDATE "18 June 2005"
+#define LSMDATE "18Jun05"
/* Debug flags */
#undef DEBUG
#define TRACE_FILE 1
/* If this is set stdout will not be closed on startup */
-/* #define DEVELOPER 1 */
+#define DEVELOPER 1