From 6989b96874450f0010441c731561acfd5b4446be Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 20 Aug 2003 09:42:21 +0000 Subject: [PATCH] Misc cleanup git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@670 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/examples/backup-every-other-week.txt | 92 ++++++++++++++ bacula/kernstodo | 2 +- bacula/src/filed/job.c | 4 +- bacula/src/lib/protos.h | 4 +- bacula/src/lib/util.c | 6 +- bacula/src/stored/block.c | 27 ++--- bacula/src/stored/btape.c | 127 ++++++++++++++------ 7 files changed, 201 insertions(+), 61 deletions(-) create mode 100644 bacula/examples/backup-every-other-week.txt diff --git a/bacula/examples/backup-every-other-week.txt b/bacula/examples/backup-every-other-week.txt new file mode 100644 index 0000000000..f2f91730ba --- /dev/null +++ b/bacula/examples/backup-every-other-week.txt @@ -0,0 +1,92 @@ + +From bacula-users-admin@lists.sourceforge.net Wed Aug 13 19:22:21 2003 +From: Robert L Mathews +To: +Content-Type: text/plain; charset="US-ASCII" +Message-Id: <20030813170422.E48403FC65F@fry.tigertech.net> +Subject: [Bacula-users] Making Backups Run Every Other Week +Sender: bacula-users-admin@lists.sourceforge.net +Date: Wed, 13 Aug 2003 10:04:23 -0700 + +In case anyone is interested, here's a tip I came up with. + +My backup policy is such that I need backups to run every other week. I +have two separate "offsite" tape pools, and a backup is made to each of +them on alternating weeks. + +Bacula's scheduler currently doesn't handle "every two weeks", and using +something like "the first and third weeks for backup A, and the second +and fourth weeks for backup B" means there will be no backup done on the +fifth week if the month contains one. Scheduling a backup for the fifth +week doesn't help; it means that the same backup would sometimes run +twice in a row, which ruins the alternating week scheme. + +I first thought of poking around the code to make the scheduler support +"every two weeks", and I someday may still do so. However, I found an +easier way to do this is in the meantime: with a RunBeforeJob line. + +What I do is schedule both jobs to run every single week. Then the job +that runs my "Offsite Backup A" has this line: + + RunBeforeJob = "/etc/bacula/two_week_script 'July 6 2003'" + +And the job with my "Offsite Backup B" has this one: + + RunBeforeJob = "/etc/bacula/two_week_script 'July 13 2003'" + +And two_week_script is the following Perl script: + +---------------- + +#!/usr/bin/perl -w + +use strict; +use constant SECONDS_IN_WEEK => 86400 * 7; +use constant SECONDS_IN_TWO_WEEKS => SECONDS_IN_WEEK * 2; + +# Calculate the elapsed seconds since the starting date, +# which must be in a format that /bin/date can understand +# Note that this relies on the GNU "%s" date extension +my $start_date = shift; +$start_date = `/bin/date -d '$start_date' +'%s'`; +chomp $start_date; +my $time_since_start_date = time - $start_date; + +# Now take those seconds modulo the number of seconds in +# two weeks. If we're in the second half of the two week +# period, exit with an error to stop the Bacula job. If +# we're in the first half, the script will terminate normally +# and the Bacula job will run. +if ($time_since_start_date % SECONDS_IN_TWO_WEEKS + >= SECONDS_IN_WEEK) +{ + exit 1; +} + +---------------- + +The result is that the script cancels the job that should not be run that +week, while allowing the other job to continue. + +This idea could be trivially changed to support running every three +weeks, every two months, every prime number of days, etc. + +Anyway, just a tip in case anyone else needs to schedule things in a way +that the scheduler doesn't currently support. It's pretty obvious that +this is the right way to do it now, but I puzzled over it for a little +while before coming up with this. + +-- +Robert L Mathews, Tiger Technologies + + + +------------------------------------------------------- +This SF.Net email sponsored by: Free pre-built ASP.NET sites including +Data Reports, E-commerce, Portals, and Forums are available now. +Download today and enter to win an XBOX or Visual Studio .NET. +http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 +_______________________________________________ +Bacula-users mailing list +Bacula-users@lists.sourceforge.net +https://lists.sourceforge.net/lists/listinfo/bacula-users diff --git a/bacula/kernstodo b/bacula/kernstodo index 5eaee27ecb..f527d2a149 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -27,6 +27,7 @@ Testing to do: (painful) - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.32: +- Edit the Client/Storage name into authentication failure messages. - Implement job in VerifyToCatalog - Implement migrate - Implement List Volume Job=xxx or List scheduled volumes or Status Director @@ -797,4 +798,3 @@ Done: (see kernsdone for more) - Add user configurable timeout for connecting to SD. - Unsaved Flag in Job record (use JobMissingFiles). - Base Flag in Job record. - diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 8398434894..e23828c37f 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -312,8 +312,8 @@ static int job_cmd(JCR *jcr) &jcr->VolSessionId, &jcr->VolSessionTime, sd_auth_key) != 5) { pm_strcpy(&jcr->errmsg, dir->msg); - bnet_fsend(dir, BADjob); Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg); + bnet_fsend(dir, BADjob); free_pool_memory(sd_auth_key); return 0; } @@ -943,7 +943,7 @@ static int send_bootstrap_file(JCR *jcr) set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } - strcpy(sd->msg, bootstrap); + pm_strcpy(&sd->msg, bootstrap); sd->msglen = strlen(sd->msg); bnet_send(sd); while (fgets(buf, sizeof(buf), bs)) { diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 413c3b6494..15d561dad1 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -177,8 +177,8 @@ char * encode_time (time_t time, char *buf); char * encode_mode (mode_t mode, char *buf); int do_shell_expansion (char *name, int name_len); void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); -void pm_strcat (POOLMEM **pm, char *str); -void pm_strcpy (POOLMEM **pm, char *str); +int pm_strcat (POOLMEM **pm, char *str); +int pm_strcpy (POOLMEM **pm, char *str); int run_program (char *prog, int wait, POOLMEM *results); char * job_type_to_str (int type); char * job_status_to_str (int stat); diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 71518c3b81..59bb7ad69c 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -112,25 +112,27 @@ char *encode_time(time_t time, char *buf) /* * Concatenate a string (str) onto a pool memory buffer pm */ -void pm_strcat(POOLMEM **pm, char *str) +in pm_strcat(POOLMEM **pm, char *str) { int pmlen = strlen(*pm); int len = strlen(str) + 1; *pm = check_pool_memory_size(*pm, pmlen + len); memcpy(*pm+pmlen, str, len); + return pmlen + len - 1; } /* * Copy a string (str) into a pool memory buffer pm */ -void pm_strcpy(POOLMEM **pm, char *str) +int pm_strcpy(POOLMEM **pm, char *str) { int len = strlen(str) + 1; *pm = check_pool_memory_size(*pm, len); memcpy(*pm, str, len); + return len - 1; } diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index ca96d6d394..ef24940c48 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -314,7 +314,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) ssize_t stat = 0; uint32_t wlen; /* length to write */ int hit_max1, hit_max2; - int ok; + bool ok; #ifdef NO_TAPE_WRITE_TEST empty_block(block); @@ -396,7 +396,8 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) dev->VolCatInfo.VolCatWrites++; Dmsg1(300, "Write block of %u bytes\n", wlen); - if ((uint32_t)(stat=write(dev->fd, block->buf, (size_t)wlen)) != wlen) { + stat = write(dev->fd, block->buf, (size_t)wlen); + if (stat != (ssize_t)wlen) { /* We should check for errno == ENOSPC, BUT many * devices simply report EIO when the volume is full. * With a little more thought we may be able to check @@ -412,11 +413,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) * systems (FreeBSD like), do the clrerror() only after * the weof_dev() call. */ -#ifndef MTIOCERRSTAT clrerror_dev(dev, -1); -#else - dev->dev_errno = errno; /* save errno */ -#endif if (dev->dev_errno == 0) { dev->dev_errno = ENOSPC; /* out of space */ } @@ -428,18 +425,16 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) dev->dev_name, wlen, stat); } - Dmsg4(10, "=== Write error. size=%u rtn=%d errno=%d: ERR=%s\n", - wlen, stat, dev->dev_errno, strerror(dev->dev_errno)); + Dmsg6(100, "=== Write error. size=%u rtn=%d dev_blk=%d blk_blk=%d errno=%d: ERR=%s\n", + wlen, stat, dev->block_num, block->BlockNumber, dev->dev_errno, strerror(dev->dev_errno)); block->write_failed = true; - weof_dev(dev, 1); /* end the tape */ - weof_dev(dev, 1); /* write second eof */ -#ifdef MTIOCERRSTAT - clrerror_dev(dev, -1); -#endif + if (weof_dev(dev, 2) != 0) { /* end the tape */ + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + } dev->state |= (ST_EOF | ST_EOT | ST_WEOT); - ok = TRUE; + ok = true; #define CHECK_LAST_BLOCK #ifdef CHECK_LAST_BLOCK /* @@ -452,12 +447,12 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* Now back up over what we wrote and read the last block */ if (bsf_dev(dev, 1) != 0 || bsf_dev(dev, 1) != 0) { - ok = FALSE; + ok = false; Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); } /* Backspace over record */ if (ok && bsr_dev(dev, 1) != 0) { - ok = FALSE; + ok = false; Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); /* * On FreeBSD systems, if the user got here, it is likely that his/her diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index eed019ac31..91e42c4776 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -69,6 +69,7 @@ static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); static void scan_blocks(); static void set_volume_name(char *VolName, int volnum); static void rawfill_cmd(); +static void bfill_cmd(); /* Static variables */ @@ -136,37 +137,37 @@ int main(int argc, char *argv[]) while ((ch = getopt(argc, argv, "b:c:d:sv?")) != -1) { switch (ch) { - case 'b': /* bootstrap file */ - bsr = parse_bsr(NULL, optarg); -// dump_bsr(bsr); - break; + case 'b': /* bootstrap file */ + bsr = parse_bsr(NULL, optarg); +// dump_bsr(bsr); + break; - case 'c': /* specify config file */ - if (configfile != NULL) { - free(configfile); - } - configfile = bstrdup(optarg); - break; + case 'c': /* specify config file */ + if (configfile != NULL) { + free(configfile); + } + configfile = bstrdup(optarg); + break; - case 'd': /* set debug level */ - debug_level = atoi(optarg); - if (debug_level <= 0) { - debug_level = 1; - } - break; + case 'd': /* set debug level */ + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } + break; - case 's': - signals = FALSE; - break; + case 's': + signals = FALSE; + break; - case 'v': - verbose++; - break; + case 'v': + verbose++; + break; - case '?': - default: - helpcmd(); - exit(0); + case '?': + default: + helpcmd(); + exit(0); } } @@ -1020,14 +1021,14 @@ static void scan_blocks() blocks++; tot_blocks++; bytes += block->block_len; - Dmsg5(100, "Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n", - block->BlockNumber, block->block_len, block->BlockVer, + Dmsg6(100, "Blk_blk=%u dev_blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n", + block->BlockNumber, dev->block_num, block->block_len, block->BlockVer, block->VolSessionId, block->VolSessionTime); if (verbose == 1) { DEV_RECORD *rec = new_record(); read_record_from_block(block, rec); - Pmsg7(-1, "Block: %u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n", - block->BlockNumber, block->block_len, + Pmsg8(-1, "Blk_block: %u dev_blk=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n", + block->BlockNumber, dev->block_num, block->block_len, FI_to_ascii(rec->FileIndex), rec->VolSessionId, rec->VolSessionTime, stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len); rec->remainder = 0; @@ -1148,7 +1149,8 @@ This may take a long time -- hours! ...\n\n"); */ jcr->VolFirstIndex = 0; time(&jcr->run_time); /* start counting time for rates */ - Pmsg0(-1, "Begin writing records to first tape ...\n"); + Pmsg0(-1, "Begin writing Bacula records to first tape ...\n"); + Pmsg1(-1, "Block num = %d\n", dev->block_num); for (file_index = 0; ok && !job_canceled(jcr); ) { rec.VolSessionId = jcr->VolSessionId; rec.VolSessionTime = jcr->VolSessionTime; @@ -1177,7 +1179,7 @@ This may take a long time -- hours! ...\n\n"); /* Write block to tape */ if (!flush_block(block, 1)) { - return; + break; } /* Every 5000 blocks (approx 322MB) report where we are. @@ -1189,7 +1191,8 @@ This may take a long time -- hours! ...\n\n"); now = 1; } kbs = (double)dev->VolCatInfo.VolCatBytes / (1000.0 * (double)now); - Pmsg3(-1, "Wrote block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber, + Pmsg4(-1, "Wrote block=%u, blk_num=%d VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber, + dev->block_num, edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs); } /* Every 15000 blocks (approx 1GB) write an EOF. @@ -1248,10 +1251,11 @@ This may take a long time -- hours! ...\n\n"); free_block(block); free_memory(rec.data); - Pmsg0(-1, _("\n\nDone filling tape. Now beginning re-read of tape ...\n")); dump_block(last_block, _("Last block written to tape.\n")); + Pmsg0(-1, _("\n\nDone filling tape. Now beginning re-read of tape ...\n")); + unfillcmd(); } @@ -1476,7 +1480,6 @@ static int flush_block(DEV_BLOCK *block, int dump) this_file = dev->file; this_block_num = dev->block_num; if (!write_block_to_dev(jcr, dev, block)) { - Pmsg0(000, strerror_dev(dev)); Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", (unsigned)file_index, block->BlockNumber, block->block_len); Pmsg2(000, "last_block_num=%u this_block_num=%d\n", last_block_num, @@ -1561,10 +1564,11 @@ static void qfillcmd() memset(rec->data, i & 0xFF, i); rec->data_len = i; rewindcmd(); - Pmsg1(0, "Begin writing %d blocks to tape ...\n", count); + Pmsg1(0, "Begin writing %d Bacula blocks to tape ...\n", count); for (i=0; i < count; i++) { if (i % 100 == 0) { printf("+"); + fflush(stdout); } if (!write_record_to_block(block, rec)) { Pmsg0(0, _("Error writing record to block.\n")); @@ -1589,6 +1593,9 @@ bail_out: } +/* + * Fill a tape using raw write() command + */ static void rawfill_cmd() { DEV_BLOCK *block; @@ -1608,13 +1615,14 @@ static void rawfill_cmd() return; } p = (uint32_t *)block->buf; - Pmsg1(0, "Begin writing blocks of %u bytes.\n", block->buf_len); + Pmsg1(0, "Begin writing raw blocks of %u bytes.\n", block->buf_len); for ( ;; ) { *p = block_num; stat = write(dev->fd, block->buf, block->buf_len); if (stat == (int)block->buf_len) { if ((block_num++ % 100) == 0) { printf("+"); + fflush(stdout); } continue; } @@ -1622,17 +1630,60 @@ static void rawfill_cmd() } my_errno = errno; printf("\n"); - weofcmd(); printf("Write failed at block %u. stat=%d ERR=%s\n", block_num, stat, strerror(my_errno)); + weofcmd(); free_block(block); +} + +/* + * Fill a tape using raw write() command + */ +static void bfill_cmd() +{ + DEV_BLOCK *block; + uint32_t block_num = 0; + uint32_t *p; + int my_errno; + int fd; + + block = new_block(dev); + fd = open("/dev/urandom", O_RDONLY); + if (fd) { + read(fd, block->buf, block->buf_len); + } else { + Pmsg0(0, "Cannot open /dev/urandom.\n"); + free_block(block); + return; + } + p = (uint32_t *)block->buf; + Pmsg1(0, "Begin writing Bacula blocks of %u bytes.\n", block->buf_len); + for ( ;; ) { + *p = block_num; + block->binbuf = block->buf_len; + block->bufp = block->buf + block->binbuf; + if (!write_block_to_dev(jcr, dev, block)) { + break; + } + if ((block_num++ % 100) == 0) { + printf("+"); + fflush(stdout); + } + } + my_errno = errno; + printf("\n"); + printf("Write failed at block %u.\n", block_num); + weofcmd(); + free_block(block); } + struct cmdstruct { char *key; void (*func)(); char *help; }; static struct cmdstruct commands[] = { {"bsf", bsfcmd, "backspace file"}, {"bsr", bsrcmd, "backspace record"}, + {"bfill", bfill_cmd, "fill tape using Bacula writes"}, {"cap", capcmd, "list device capabilities"}, {"clear", clearcmd, "clear tape errors"}, {"eod", eodcmd, "go to end of Bacula data for append"}, -- 2.39.5