From: Kern Sibbald Date: Sat, 12 Apr 2003 21:01:19 +0000 (+0000) Subject: BFILE I/O, new console @ commands, regression, file mode restore fixes X-Git-Tag: Release-1.30~31 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=253f7da0668e69f8a37b49245f99195881120f41;p=bacula%2Fbacula BFILE I/O, new console @ commands, regression, file mode restore fixes git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@436 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index 3d3bcadc0a..a332332d08 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -75,6 +75,9 @@ /* Maximum Name length including EOS */ #define MAX_NAME_LENGTH 128 +/* Maximume number of user entered command args */ +#define MAX_CMD_ARGS 30 + /* All tape operations MUST be a multiple of this */ #define TAPE_BSIZE 1024 #if !defined(DEV_BSIZE) && defined(BSIZE) diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 69597b46ea..8b00944f95 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -45,13 +45,29 @@ extern int rl_catch_signals; /* Forward referenced functions */ static void terminate_console(int sig); int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec); +static int do_outputcmd(FILE *input, BSOCK *UA_sock); +static void sendit(char *fmt, ...); /* Static variables */ static char *configfile = NULL; static BSOCK *UA_sock = NULL; static DIRRES *dir; static FILE *output = stdout; +int tee = 0; /* output to output and stdout */ static int stop = FALSE; +static int argc; +static POOLMEM *args; +static char *argk[MAX_CMD_ARGS]; +static char *argv[MAX_CMD_ARGS]; + +/* Command prototypes */ +static int versioncmd(FILE *input, BSOCK *UA_sock); +static int inputcmd(FILE *input, BSOCK *UA_sock); +static int outputcmd(FILE *input, BSOCK *UA_sock); +static int teecmd(FILE *input, BSOCK *UA_sock); +static int quitcmd(FILE *input, BSOCK *UA_sock); +static int timecmd(FILE *input, BSOCK *UA_sock); +static int sleepcmd(FILE *input, BSOCK *UA_sock); #define CONFIG_FILE "./console.conf" /* default configuration file */ @@ -92,6 +108,56 @@ void got_tin(int sig) // printf("Got tin\n"); } +struct cmdstruct { char *key; int (*func)(FILE *input, BSOCK *UA_sock); char *help; }; +static struct cmdstruct commands[] = { + { N_("input"), inputcmd, _("input from file")}, + { N_("output"), outputcmd, _("output to file")}, + { N_("quit"), quitcmd, _("quit")}, + { N_("tee"), teecmd, _("output to file and terminal")}, + { N_("sleep"), sleepcmd, _("sleep specified time")}, + { N_("time"), timecmd, _("print current time")}, + { N_("version"), versioncmd, _("print Console's version")}, + { N_("exit"), quitcmd, _("exit = quit")}, + }; +#define comsize (sizeof(commands)/sizeof(struct cmdstruct)) + +static int do_a_command(FILE *input, BSOCK *UA_sock) +{ + unsigned int i; + int stat; + int found; + int len; + char *cmd; + + found = 0; + stat = 1; + + Dmsg1(120, "Command: %s\n", UA_sock->msg); + if (argc == 0) { + return 1; + } + + cmd = argk[0]+1; + if (*cmd == '#') { /* comment */ + return 1; + } + len = strlen(cmd); + for (i=0; imsg, _(": is an illegal command\n")); + UA_sock->msglen = strlen(UA_sock->msg); + fputs(UA_sock->msg, output); + fflush(output); + } + return stat; +} + static void read_and_process_input(FILE *input, BSOCK *UA_sock) { @@ -125,6 +191,14 @@ static void read_and_process_input(FILE *input, BSOCK *UA_sock) bnet_fsend(UA_sock, ".messages"); } else { at_prompt = FALSE; + /* @ => internal command for us */ + if (UA_sock->msg[0] == '@') { + parse_command_args(UA_sock->msg, args, &argc, argk, argv); + if (!do_a_command(input, UA_sock)) { + break; + } + continue; + } if (!bnet_send(UA_sock)) { /* send command */ break; /* error */ } @@ -135,16 +209,16 @@ static void read_and_process_input(FILE *input, BSOCK *UA_sock) while ((stat = bnet_recv(UA_sock)) >= 0) { if (at_prompt) { if (!stop) { - putc('\n', output); + sendit("\n"); } at_prompt = FALSE; } if (!stop) { - fputs(UA_sock->msg, output); + sendit("%s", UA_sock->msg); } } if (!stop) { - fflush(output); + fflush(stdout); } if (is_bnet_stop(UA_sock)) { break; /* error or term */ @@ -174,6 +248,7 @@ int main(int argc, char *argv[]) my_name_is(argc, argv, "console"); init_msg(NULL, NULL); working_directory = "/tmp"; + args = get_pool_memory(PM_FNAME); while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) { switch (ch) { @@ -248,7 +323,7 @@ Without that I don't how to speak to the Director :-(\n", configfile); if (ndir > 1) { UA_sock = init_bsock(NULL, 0, "", "", 0); try_again: - fprintf(output, "Available Directors:\n"); + sendit("Available Directors:\n"); LockRes(); ndir = 0; for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) { @@ -261,7 +336,7 @@ try_again: } item = atoi(UA_sock->msg); if (item < 0 || item > ndir) { - fprintf(output, "You must enter a number between 1 and %d\n", ndir); + sendit("You must enter a number between 1 and %d\n", ndir); goto try_again; } LockRes(); @@ -278,7 +353,7 @@ try_again: } - Dmsg2(-1, "Connecting to Director %s:%d\n", dir->address,dir->DIRport); + sendit("Connecting to Director %s:%d\n", dir->address,dir->DIRport); UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, NULL, dir->DIRport, 0); if (UA_sock == NULL) { @@ -315,6 +390,7 @@ static void terminate_console(int sig) exit(1); } already_here = TRUE; + free_pool_memory(args); exit(0); } @@ -389,8 +465,10 @@ get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec) { int len; if (!stop) { - fputs(prompt, output); - fflush(output); + if (output == stdout || tee) { + fputs(prompt, stdout); + fflush(stdout); + } } again: switch (wait_for_data(fileno(input), sec)) { @@ -414,3 +492,114 @@ again: } #endif + +static int versioncmd(FILE *input, BSOCK *UA_sock) +{ + sendit("Version: " VERSION " (" BDATE ")\n"); + return 1; +} + +static int inputcmd(FILE *input, BSOCK *UA_sock) +{ + FILE *fd; + + if (argc > 2) { + sendit("Too many arguments.\n"); + return 0; + } + if (argc == 1) { + sendit("First argument must be a filename.\n"); + return 0; + } + fd = fopen(argk[1], "r"); + if (!fd) { + sendit("Cannot open file. ERR=%s\n", strerror(errno)); + return 0; + } + read_and_process_input(fd, UA_sock); + fclose(fd); + return 1; +} + +static int teecmd(FILE *input, BSOCK *UA_sock) +{ + tee = 1; + return do_outputcmd(input, UA_sock); +} + +static int outputcmd(FILE *input, BSOCK *UA_sock) +{ + tee = 0; + return do_outputcmd(input, UA_sock); +} + + +static int do_outputcmd(FILE *input, BSOCK *UA_sock) +{ + FILE *fd; + char *mode = "a+"; + + if (argc > 3) { + sendit("Too many arguments.\n"); + return 1; + } + if (argc == 1) { + if (output != stdout) { + fclose(output); + output = stdout; + tee = 0; + } + return 1; + } + if (argc == 3) { + mode = argk[2]; + } + fd = fopen(argk[1], mode); + if (!fd) { + sendit("Cannot open file. ERR=%s\n", strerror(errno)); + return 1; + } + output = fd; + return 1; +} + +static int quitcmd(FILE *input, BSOCK *UA_sock) +{ + return 0; +} + +static int sleepcmd(FILE *input, BSOCK *UA_sock) +{ + if (argc > 1) { + sleep(atoi(argk[1])); + } + return 1; +} + + +static int timecmd(FILE *input, BSOCK *UA_sock) +{ + char sdt[50]; + time_t ttime = time(NULL); + struct tm tm; + localtime_r(&ttime, &tm); + strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm); + sendit(sdt); + sendit("\n"); + return 1; +} + +static void sendit(char *fmt,...) +{ + char buf[3000]; + va_list arg_ptr; + + va_start(arg_ptr, fmt); + bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr); + va_end(arg_ptr); + fputs(buf, output); + if (tee) { + fputs(buf, stdout); + } + fflush(stdout); +} diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in index 034a5b9d89..9eface5fd8 100644 --- a/bacula/src/dird/bacula-dir.conf.in +++ b/bacula/src/dird/bacula-dir.conf.in @@ -24,14 +24,16 @@ Director { # define myself Messages = Standard } +# # Define the main nightly save backup job +# By default, this job will back up to disk in /tmp Job { Name = "NightlySave" Type = Backup Client=@hostname@-fd FileSet="Full Set" Schedule = "WeeklyCycle" - Storage = DLTDrive + Storage = File Messages = Standard Pool = Default Write Bootstrap = "@working_dir@/NightlySave.bsr" @@ -44,7 +46,7 @@ Job { Client=@hostname@-fd FileSet="Catalog" Schedule = "WeeklyCycleAfterBackup" - Storage = DLTDrive + Storage = File Messages = Standard Pool = Default # This creates an ASCII copy of the catalog @@ -60,7 +62,7 @@ Job { Type = Restore Client=@hostname@-fd FileSet="Full Set" - Storage = DLTDrive + Storage = File Messages = Standard Pool = Default Where = /tmp/bacula-restores @@ -75,16 +77,23 @@ FileSet { # Put your list of files here, one per line or include an # external list with: # -# @file-name +# argk[0]); - for (i=0; iargk[0], _(commands[i].key), len) == 0) { stat = (*commands[i].func)(ua, cmd); /* go execute command */ found = 1; break; } + } if (!found) { - strcat(ua->UA_sock->msg, _(": is an illegal command\n")); + pm_strcat(&ua->UA_sock->msg, _(": is an illegal command\n")); ua->UA_sock->msglen = strlen(ua->UA_sock->msg); bnet_send(ua->UA_sock); } @@ -1383,6 +1386,32 @@ int quitcmd(UAContext *ua, char *cmd) return 1; } +/* + * Wait until no job is running + */ +int waitcmd(UAContext *ua, char *cmd) +{ + usleep(300000); + for (int running=1; running; ) { + running = 0; + lock_jcr_chain(); + for (JCR *jcr=NULL; (jcr=get_next_jcr(jcr)); ) { + if (jcr->JobId != 0 && jcr->JobStatus != JS_Created) { + running = 1; + free_locked_jcr(jcr); + break; + } + free_locked_jcr(jcr); + } + unlock_jcr_chain(); + if (running) { + sleep(1); + } + } + return 1; +} + + static int helpcmd(UAContext *ua, char *cmd) { unsigned int i; diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index 68bb7db56d..13d7d3f6fd 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -71,118 +71,7 @@ int get_cmd(UAContext *ua, char *prompt) return 1; } -/* - * Return next argument from command line. Note, this - * routine is destructive. - */ -char *next_arg(char **s) +void parse_ua_args(UAContext *ua) { - char *p, *q, *n; - int in_quote = 0; - - /* skip past spaces to next arg */ - for (p=*s; *p && *p == ' '; ) { - p++; - } - Dmsg1(400, "Next arg=%s\n", p); - for (n = q = p; *p ; ) { - if (*p == '\\') { - p++; - if (*p) { - *q++ = *p++; - } else { - *q++ = *p; - } - continue; - } - if (*p == '"') { /* start or end of quote */ - if (in_quote) { - p++; /* skip quote */ - in_quote = 0; - continue; - } - in_quote = 1; - p++; - continue; - } - if (!in_quote && *p == ' ') { /* end of field */ - p++; - break; - } - *q++ = *p++; - } - *q = 0; - *s = p; - Dmsg2(400, "End arg=%s next=%s\n", n, p); - return n; -} - -/* - * This routine parses the input command line. - * It makes a copy in args, then builds an - * argc, argv like list where - * - * argc = count of arguments - * argk[i] = argument keyword (part preceding =) - * argv[i] = argument value (part after =) - * - * example: arg1 arg2=abc arg3= - * - * argc = c - * argk[0] = arg1 - * argv[0] = NULL - * argk[1] = arg2 - * argv[1] = abc - * argk[2] = arg3 - * argv[2] = - */ - -void parse_command_args(UAContext *ua) -{ - char *p, *q, *n; - int i, len; - - len = strlen(ua->cmd) + 1; - ua->args = check_pool_memory_size(ua->args, len); - bstrncpy(ua->args, ua->cmd, len); - strip_trailing_junk(ua->args); - ua->argc = 0; - p = ua->args; - /* Pick up all arguments */ - while (ua->argc < MAX_ARGS) { - n = next_arg(&p); - if (*n) { - ua->argk[ua->argc++] = n; - } else { - break; - } - } - /* Separate keyword and value */ - for (i=0; iargc; i++) { - p = strchr(ua->argk[i], '='); - if (p) { - *p++ = 0; /* terminate keyword and point to value */ - /* Unquote quoted values */ - if (*p == '"') { - for (n = q = ++p; *p && *p != '"'; ) { - if (*p == '\\') { - p++; - } - *q++ = *p++; - } - *q = 0; /* terminate string */ - p = n; /* point to string */ - } - if (strlen(p) > MAX_NAME_LENGTH-1) { - p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */ - } - } - ua->argv[i] = p; /* save ptr to value or NULL */ - } -#ifdef xxxx - for (i=0; iargc; i++) { - Dmsg3(000, "Arg %d: kw=%s val=%s\n", i, - ua->argk[i], ua->argv[i]?ua->argv[i]:"NULL"); - } -#endif + return parse_command_args(ua->cmd, ua->args, &ua->argc, ua->argk, ua->argv); } diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 77e91858f7..3a280fc135 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -271,7 +271,7 @@ int restorecmd(UAContext *ua, char *cmd) Dmsg1(400, "Submitting: %s\n", ua->cmd); - parse_command_args(ua); + parse_ua_args(ua); runcmd(ua, ua->cmd); bsendmsg(ua, _("Restore command done.\n")); @@ -577,7 +577,7 @@ static void user_select_files(TREE_CTX *tree) if (!get_cmd(tree->ua, "$ ")) { break; } - parse_command_args(tree->ua); + parse_ua_args(tree->ua); if (tree->ua->argc == 0) { return; } diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index 40378b8b0f..7e710d39d7 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -127,7 +127,7 @@ static void *handle_UA_client_request(void *arg) if (stat >= 0) { ua.cmd = check_pool_memory_size(ua.cmd, ua.UA_sock->msglen+1); bstrncpy(ua.cmd, ua.UA_sock->msg, ua.UA_sock->msglen+1); - parse_command_args(&ua); + parse_ua_args(&ua); if (ua.argc > 0 && ua.argk[0][0] == '.') { do_a_dot_command(&ua, ua.cmd); } else { diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 480fac4b90..6983dfaa0a 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -184,7 +184,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) } else { tid = NULL; } - if ((ff_pkt->fid = open(ff_pkt->fname, O_RDONLY | O_BINARY)) < 0) { + if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { ff_pkt->ff_errno = errno; Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno)); stop_thread_timer(tid); @@ -192,7 +192,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) } stop_thread_timer(tid); } else { - ff_pkt->fid = -1; + binit(&ff_pkt->bfd); } Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname); @@ -212,8 +212,8 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) */ #ifndef NO_FD_SEND_TEST if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) { - if (ff_pkt->fid >= 0) { - close(ff_pkt->fid); + if (is_bopen(&ff_pkt->bfd)) { + bclose(&ff_pkt->bfd); } set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; @@ -248,8 +248,8 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) Dmsg2(100, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg); if (!stat) { - if (ff_pkt->fid >= 0) { - close(ff_pkt->fid); + if (is_bopen(&ff_pkt->bfd)) { + bclose(&ff_pkt->bfd); } set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; @@ -261,7 +261,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) * If the file has data, read it and send to the Storage daemon * */ - if (ff_pkt->fid >= 0) { + if (is_bopen(&ff_pkt->bfd)) { uint64_t fileAddr = 0; /* file address */ char *rbuf, *wbuf; int rsize = jcr->buf_size; /* read buffer size */ @@ -306,7 +306,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) * */ if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) { - close(ff_pkt->fid); + bclose(&ff_pkt->bfd); set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } @@ -331,7 +331,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) /* * Read the file data */ - while ((sd->msglen=read(ff_pkt->fid, rbuf, rsize)) > 0) { + while ((sd->msglen=bread(&ff_pkt->bfd, rbuf, rsize)) > 0) { int sparseBlock = 0; /* Check for sparse blocks */ @@ -372,7 +372,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat); sd->msg = msgsave; sd->msglen = 0; - close(ff_pkt->fid); + bclose(&ff_pkt->bfd); set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } @@ -393,7 +393,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) if (!bnet_send(sd)) { sd->msg = msgsave; /* restore read buffer */ sd->msglen = 0; - close(ff_pkt->fid); + bclose(&ff_pkt->bfd); set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } @@ -410,7 +410,7 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) ff_pkt->fname, strerror(errno)); } - close(ff_pkt->fid); /* close file */ + bclose(&ff_pkt->bfd); /* close file */ #ifndef NO_FD_SEND_TEST if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */ set_jcr_job_status(jcr, JS_ErrorTerminated); diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 1d06cad6e2..e90e56dc13 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -161,7 +161,6 @@ void *handle_client_request(void *dirp) jcr->last_fname = get_pool_memory(PM_FNAME); jcr->last_fname[0] = 0; jcr->client_name = get_memory(strlen(my_name) + 1); - jcr->prefix_links = 1; /* default to prefix links */ pm_strcpy(&jcr->client_name, my_name); dir->jcr = (void *)jcr; diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 864c3bd36f..da0f6c136f 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -55,7 +55,7 @@ void do_restore(JCR *jcr) uint32_t record_file_index; struct stat statp; int extract = FALSE; - int ofd = -1; + BFILE bfd; int type, stat; uint32_t total = 0; /* Job total but only 32 bits for debug */ char *wbuf; /* write buffer */ @@ -64,6 +64,7 @@ void do_restore(JCR *jcr) wherelen = strlen(jcr->where); + binit(&bfd); sd = jcr->store_bsock; set_jcr_job_status(jcr, JS_Running); @@ -127,11 +128,11 @@ void do_restore(JCR *jcr) * close the output file. */ if (extract) { - if (ofd < 0) { + if (!is_bopen(&bfd)) { Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open\n")); } set_attributes(jcr, fname, ofile, lname, type, stream, - &statp, attribsEx, &ofd); + &statp, attribsEx, &bfd); extract = FALSE; Dmsg0(30, "Stop extracting.\n"); } @@ -235,12 +236,15 @@ void do_restore(JCR *jcr) } strcat(ofile, fn); /* copy rest of name */ /* - * Fixup link name -- add where only if requested - * and if it is an absolute path + * Fixup link name -- if it is an absolute path */ if (type == FT_LNKSAVED || type == FT_LNK) { int add_link; - if (jcr->prefix_links && lp[0] == '/') { /* if absolute path */ + /* Always add prefix to hard links (FT_LNKSAVED) and + * on user request to soft links + */ + if (lp[0] == '/' && + (type == FT_LNKSAVED || jcr->prefix_links)) { strcpy(lname, jcr->where); add_link = 1; } else { @@ -264,7 +268,7 @@ void do_restore(JCR *jcr) extract = FALSE; stat = create_file(jcr, fname, ofile, lname, type, - stream, &statp, attribsEx, &ofd, jcr->replace); + stream, &statp, attribsEx, &bfd, jcr->replace); switch (stat) { case CF_ERROR: case CF_SKIP: @@ -274,11 +278,18 @@ void do_restore(JCR *jcr) P(jcr->mutex); pm_strcpy(&jcr->last_fname, ofile); V(jcr->mutex); - /* Fall-through wanted */ + jcr->JobFiles++; + fileAddr = 0; + print_ls_output(jcr, ofile, lname, type, &statp); + /* Set attributes after file extracted */ + break; case CF_CREATED: jcr->JobFiles++; fileAddr = 0; print_ls_output(jcr, ofile, lname, type, &statp); + /* set attributes now because file will not be extracted */ + set_attributes(jcr, fname, ofile, lname, type, stream, + &statp, attribsEx, &bfd); break; } @@ -298,7 +309,7 @@ void do_restore(JCR *jcr) unser_uint64(faddr); if (fileAddr != faddr) { fileAddr = faddr; - if (lseek(ofd, (off_t)fileAddr, SEEK_SET) < 0) { + if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) { Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), edit_uint64(fileAddr, ec1), ofile, strerror(errno)); goto bail_out; @@ -309,7 +320,7 @@ void do_restore(JCR *jcr) wsize = sd->msglen; } Dmsg2(30, "Write %u bytes, total before write=%u\n", wsize, total); - if ((uint32_t)write(ofd, wbuf, wsize) != wsize) { + if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) { Dmsg0(0, "===Write error===\n"); Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), ofile, strerror(errno)); goto bail_out; @@ -336,7 +347,7 @@ void do_restore(JCR *jcr) unser_uint64(faddr); if (fileAddr != faddr) { fileAddr = faddr; - if (lseek(ofd, (off_t)fileAddr, SEEK_SET) < 0) { + if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) { Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), edit_uint64(fileAddr, ec1), ofile, strerror(errno)); goto bail_out; @@ -355,7 +366,7 @@ void do_restore(JCR *jcr) } Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); - if ((uLong)write(ofd, jcr->compress_buf, compress_len) != compress_len) { + if ((uLong)bwrite(&bfd, jcr->compress_buf, compress_len) != compress_len) { Dmsg0(0, "===Write error===\n"); Jmsg2(jcr, M_ERROR, 0, "Write error on %s: %s\n", ofile, strerror(errno)); goto bail_out; @@ -373,11 +384,11 @@ void do_restore(JCR *jcr) /* If extracting, wierd stream (not 1 or 2), close output file anyway */ } else if (extract) { Dmsg1(30, "Found wierd stream %d\n", stream); - if (ofd < 0) { - Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open\n")); + if (!is_bopen(&bfd)) { + Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open but is not.\n")); } set_attributes(jcr, fname, ofile, lname, type, stream, - &statp, attribsEx, &ofd); + &statp, attribsEx, &bfd); extract = FALSE; } else if (!(stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE)) { Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg); @@ -387,9 +398,9 @@ void do_restore(JCR *jcr) /* If output file is still open, it was the last one in the * archive since we just hit an end of file, so close the file. */ - if (ofd >= 0) { + if (is_bopen(&bfd)) { set_attributes(jcr, fname, ofile, lname, type, stream, - &statp, attribsEx, &ofd); + &statp, attribsEx, &bfd); } set_jcr_job_status(jcr, JS_Terminated); goto ok_out; diff --git a/bacula/src/filed/verify.c b/bacula/src/filed/verify.c index 0af6a2bd4b..e996fc6fa5 100644 --- a/bacula/src/filed/verify.c +++ b/bacula/src/filed/verify.c @@ -67,7 +67,8 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) { char attribs[MAXSTRING]; int32_t n; - int fid, stat; + int stat; + BFILE bfd; struct MD5Context md5c; struct SHA1Context sha1c; unsigned char signature[25]; /* large enough for either */ @@ -140,13 +141,13 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->statp.st_size > 0) || ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) { - if ((fid = open(ff_pkt->fname, O_RDONLY | O_BINARY)) < 0) { + if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0)) < 0) { ff_pkt->ff_errno = errno; Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno)); return 1; } } else { - fid = -1; + binit(&bfd); } encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI); @@ -182,17 +183,17 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); if (!stat) { Jmsg(jcr, M_ERROR, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir)); - if (fid >= 0) { - close(fid); + if (is_bopen(&bfd)) { + bclose(&bfd); } return 0; } /* If file opened, compute MD5 */ - if (fid >= 0 && ff_pkt->flags & FO_MD5) { + if (is_bopen(&bfd) && ff_pkt->flags & FO_MD5) { char MD5buf[40]; /* 24 should do */ MD5Init(&md5c); - while ((n=read(fid, jcr->big_buf, jcr->buf_size)) > 0) { + while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { MD5Update(&md5c, ((unsigned char *) jcr->big_buf), n); jcr->JobBytes += n; } @@ -207,10 +208,10 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_SIGNATURE, MD5buf, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg); - } else if (fid >= 0 && ff_pkt->flags & FO_SHA1) { + } else if (is_bopen(&bfd) && ff_pkt->flags & FO_SHA1) { char SHA1buf[40]; /* 24 should do */ SHA1Init(&sha1c); - while ((n=read(fid, jcr->big_buf, jcr->buf_size)) > 0) { + while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { SHA1Update(&sha1c, ((unsigned char *) jcr->big_buf), n); jcr->JobBytes += n; } @@ -226,8 +227,8 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) SHA1buf, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg); } - if (fid >= 0) { - close(fid); + if (is_bopen(&bfd)) { + bclose(&bfd); } return 1; } diff --git a/bacula/src/findlib/Makefile.in b/bacula/src/findlib/Makefile.in index 56e9307fd2..9a8386b96f 100644 --- a/bacula/src/findlib/Makefile.in +++ b/bacula/src/findlib/Makefile.in @@ -21,9 +21,9 @@ dummy: # LIBSRCS = find.c match.c find_one.c attibs.c create_file.c \ - makepath.c save-cwd.c + bfile.c makepath.c save-cwd.c LIBOBJS = find.o match.o find_one.o attribs.o create_file.o \ - makepath.o save-cwd.o + bfile.o makepath.o save-cwd.o .SUFFIXES: .c .o .PHONY: diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index 346f4d43e4..13674ca23c 100755 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -39,7 +39,7 @@ static int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, int type, int stream, struct stat *statp, - char *attribsEx, int *ofd); + char *attribsEx, BFILE *ofd); void unix_name_to_win32(POOLMEM **win32_name, char *name); extern "C" HANDLE get_osfhandle(int fd); void win_error(void *jcr, char *prefix, POOLMEM *ofile); @@ -182,7 +182,7 @@ decode_stat(char *buf, struct stat *statp, uint32_t *LinkFI) */ int set_attributes(void *jcr, char *fname, char *ofile, char *lname, int type, int stream, struct stat *statp, - char *attribsEx, int *ofd) + char *attribsEx, BFILE *ofd) { struct utimbuf ut; mode_t old_mask; @@ -201,16 +201,20 @@ int set_attributes(void *jcr, char *fname, char *ofile, char *lname, #endif old_mask = umask(0); - if (*ofd != -1) { - close(*ofd); /* first close file */ - *ofd = -1; + if (is_bopen(ofd)) { + bclose(ofd); /* first close file */ } ut.actime = statp->st_atime; ut.modtime = statp->st_mtime; /* ***FIXME**** optimize -- don't do if already correct */ + /* + * For link, change owner of link using lchown, but don't + * try to do a chmod as that will update the file behind it. + */ if (type == FT_LNK) { + /* Change owner of link, not of real file */ if (lchown(ofile, statp->st_uid, statp->st_gid) < 0) { Jmsg2(jcr, M_WARNING, 0, "Unable to set file owner %s: ERR=%s\n", ofile, strerror(errno)); @@ -222,29 +226,29 @@ int set_attributes(void *jcr, char *fname, char *ofile, char *lname, ofile, strerror(errno)); stat = 0; } - } - if (chmod(ofile, statp->st_mode) < 0) { - Jmsg2(jcr, M_WARNING, 0, "Unable to set file modes %s: ERR=%s\n", - ofile, strerror(errno)); - stat = 0; - } + if (chmod(ofile, statp->st_mode) < 0) { + Jmsg2(jcr, M_WARNING, 0, "Unable to set file modes %s: ERR=%s\n", + ofile, strerror(errno)); + stat = 0; + } - /* FreeBSD user flags */ + /* FreeBSD user flags */ #ifdef HAVE_CHFLAGS - if (chflags(ofile, statp->st_flags) < 0) { - Jmsg2(jcr, M_WARNING, 0, "Unable to set file flags %s: ERR=%s\n", - ofile, strerror(errno)); - stat = 0; - } + if (chflags(ofile, statp->st_flags) < 0) { + Jmsg2(jcr, M_WARNING, 0, "Unable to set file flags %s: ERR=%s\n", + ofile, strerror(errno)); + stat = 0; + } #endif - /* - * Reset file times. - */ - if (utime(ofile, &ut) < 0) { - Jmsg2(jcr, M_ERROR, 0, "Unable to set file times %s: ERR=%s\n", - ofile, strerror(errno)); - stat = 0; + /* + * Reset file times. + */ + if (utime(ofile, &ut) < 0) { + Jmsg2(jcr, M_ERROR, 0, "Unable to set file times %s: ERR=%s\n", + ofile, strerror(errno)); + stat = 0; + } } umask(old_mask); return stat; @@ -347,20 +351,19 @@ int encode_attribsEx(void *jcr, char *attribsEx, FF_PKT *ff_pkt) static int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, int type, int stream, struct stat *statp, - char *attribsEx, int *ofd) + char *attribsEx, BFILE *ofd) { char *p = attribsEx; int64_t val; WIN32_FILE_ATTRIBUTE_DATA atts; ULARGE_INTEGER li; - int fid, stat; + int stat; POOLMEM *win32_ofile; if (!p || !*p) { /* we should have attributes */ - Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", ofile, *ofd); - if (*ofd != -1) { - close(*ofd); - *ofd = -1; + Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", ofile, ofd->fid); + if (is_bopen(ofd)) { + bclose(ofd); } return 0; } else { @@ -397,25 +400,21 @@ int set_win32_attributes(void *jcr, char *fname, char *ofile, char *lname, win32_ofile = get_pool_memory(PM_FNAME); unix_name_to_win32(&win32_ofile, ofile); - if (*ofd == -1) { + if (!is_bopen(ofd)) { Dmsg1(100, "File not open: %s\n", ofile); - fid = open(ofile, O_RDWR|O_BINARY); /* attempt to open the file */ - if (fid >= 0) { - *ofd = fid; - } + bopen(ofd, ofile, O_RDWR|O_BINARY, 0); /* attempt to open the file */ } - if (*ofd != -1) { + if (is_open(ofd)) { Dmsg1(100, "SetFileTime %s\n", ofile); - stat = SetFileTime(get_osfhandle(*ofd), + stat = SetFileTime(get_osfhandle(ofd->fid), &atts.ftCreationTime, &atts.ftLastAccessTime, &atts.ftLastWriteTime); if (stat != 1) { win_error(jcr, "SetFileTime:", win32_ofile); } - close(*ofd); - *ofd = -1; + bclose(ofd); } Dmsg1(100, "SetFileAtts %s\n", ofile); diff --git a/bacula/src/findlib/bfile.c b/bacula/src/findlib/bfile.c new file mode 100644 index 0000000000..74618d13fd --- /dev/null +++ b/bacula/src/findlib/bfile.c @@ -0,0 +1,70 @@ +/* + * Bacula low level File I/O routines. This routine simulates + * open(), read(), write(), and close(), but using native routines. + * I.e. on Windows, we use Windows APIs. + * + * Kern Sibbald, April MMIII + * + * Version $Id$ + * + */ +/* + Copyright (C) 2000-2003 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "find.h" + + +void binit(BFILE *bfd) +{ + bfd->fid = -1; +} + +int bopen(BFILE *bfd, const char *pathname, int flags, mode_t mode) +{ + return bfd->fid = open(pathname, flags, mode); +} + +int bclose(BFILE *bfd) +{ + int stat = close(bfd->fid); + bfd->fid = -1; + return stat; +} + +ssize_t bread(BFILE *bfd, void *buf, size_t count) +{ + return read(bfd->fid, buf, count); +} + +ssize_t bwrite(BFILE *bfd, void *buf, size_t count) +{ + return write(bfd->fid, buf, count); +} + +int is_bopen(BFILE *bfd) +{ + return bfd->fid >= 0; +} + +off_t blseek(BFILE *bfd, off_t offset, int whence) +{ + return lseek(bfd->fid, offset, whence); +} diff --git a/bacula/src/findlib/create_file.c b/bacula/src/findlib/create_file.c index 8c503d14a7..2169ad0343 100644 --- a/bacula/src/findlib/create_file.c +++ b/bacula/src/findlib/create_file.c @@ -60,7 +60,7 @@ */ int create_file(void *jcr, char *fname, char *ofile, char *lname, int type, int stream, struct stat *statp, - char *attribsEx, int *ofd, int replace) + char *attribsEx, BFILE *ofd, int replace) { int new_mode, parent_mode, mode; uid_t uid; @@ -69,7 +69,7 @@ int create_file(void *jcr, char *fname, char *ofile, char *lname, int fnl, pnl; char *f, *p, savechr; - *ofd = -1; + binit(ofd); new_mode = statp->st_mode; Dmsg2(300, "newmode=%x file=%s\n", new_mode, ofile); parent_mode = S_IWUSR | S_IXUSR | new_mode; @@ -108,7 +108,7 @@ int create_file(void *jcr, char *fname, char *ofile, char *lname, ofile, lname, strerror(errno)); return CF_ERROR; } - break; + return CF_CREATED; case FT_REGE: /* empty file */ case FT_REG: /* regular file */ /* Separate pathname and filename */ @@ -162,7 +162,7 @@ int create_file(void *jcr, char *fname, char *ofile, char *lname, mode |= O_CTG; /* set contiguous bit if needed */ } Dmsg1(50, "Create file: %s\n", ofile); - if ((*ofd = open(ofile, mode, S_IRUSR | S_IWUSR)) < 0) { + if ((bopen(ofd, ofile, mode, S_IRUSR | S_IWUSR)) < 0) { Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, strerror(errno)); return CF_ERROR; } @@ -208,7 +208,7 @@ int create_file(void *jcr, char *fname, char *ofile, char *lname, } else { tid = NULL; } - if ((*ofd = open(ofile, mode)) < 0) { + if ((bopen(ofd, ofile, mode, 0)) < 0) { Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, strerror(errno)); stop_thread_timer(tid); return CF_ERROR; diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 4318f9ed24..8800e49827 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -120,12 +120,16 @@ struct s_excluded_file { char fname[1]; }; +typedef struct s_bfile { + int fid; /* file id on Unix */ +} BFILE; + /* * Definition of the find_files packet passed as the * first argument to the find_files callback subroutine. */ -typedef struct ff { +typedef struct s_ff { char *fname; /* filename */ char *link; /* link if file linked */ POOLMEM *sys_fname; /* system filename */ @@ -134,10 +138,10 @@ typedef struct ff { uint32_t LinkFI; /* FileIndex of main hard linked file */ struct f_link *linked; /* Set if we are hard linked */ int type; /* FT_ type from above */ - int fid; /* file id if opened */ int flags; /* control flags */ int ff_errno; /* errno */ int incremental; /* do incremental save */ + BFILE bfd; /* Bacula file descriptor */ time_t save_time; /* start of incremental time */ int mtime_only; /* incremental on mtime_only */ int dereference; /* follow links */ @@ -152,6 +156,7 @@ typedef struct ff { struct f_link *linklist; /* hard linked files */ } FF_PKT; + #include "protos.h" #endif /* __FILES_H */ diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index 770f97ea4b..da28b45323 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -24,17 +24,17 @@ */ /* from attribs.c */ -void encode_stat (char *buf, struct stat *statp, uint32_t LinkFI); -void decode_stat (char *buf, struct stat *statp, uint32_t *LinkFI); -int encode_attribsEx (void *jcr, char *attribsEx, FF_PKT *ff_pkt); +void encode_stat (char *buf, struct stat *statp, uint32_t LinkFI); +void decode_stat (char *buf, struct stat *statp, uint32_t *LinkFI); +int encode_attribsEx (void *jcr, char *attribsEx, FF_PKT *ff_pkt); int set_attributes(void *jcr, char *fname, char *ofile, char *lname, - int type, int stream, struct stat *statp, - char *attribsEx, int *ofd); + int type, int stream, struct stat *statp, + char *attribsEx, BFILE *ofd); /* from create_file.c */ int create_file(void *jcr, char *fname, char *ofile, char *lname, - int type, int stream, struct stat *statp, - char *attribsEx, int *ofd, int replace); + int type, int stream, struct stat *statp, + char *attribsEx, BFILE *ofd, int replace); /* From find.c */ FF_PKT *init_find_files(); @@ -50,15 +50,25 @@ void add_fname_to_exclude_list(FF_PKT *ff, char *fname); int file_is_excluded(FF_PKT *ff, char *file); int file_is_included(FF_PKT *ff, char *file); struct s_included_file *get_next_included_file(FF_PKT *ff, - struct s_included_file *inc); + struct s_included_file *inc); /* From find_one.c */ int find_one_file(JCR *jcr, FF_PKT *ff, int handle_file(FF_PKT *ff_pkt, void *hpkt), - void *pkt, char *p, dev_t parent_device, int top_level); + void *pkt, char *p, dev_t parent_device, int top_level); int term_find_one(FF_PKT *ff); /* from makepath.c */ int make_path(void *jcr, const char *argpath, int mode, - int parent_mode, uid_t owner, gid_t group, - int preserve_existing, char *verbose_fmt_string); + int parent_mode, uid_t owner, gid_t group, + int preserve_existing, char *verbose_fmt_string); + +/* from file_io.c */ +ssize_t bread(BFILE *bfd, void *buf, size_t count); +int bopen(BFILE *bfd, const char *pathname, int flags, mode_t mode); +int bclose(BFILE *bfd); +ssize_t bread(BFILE *bfd, void *buf, size_t count); +ssize_t bwrite(BFILE *bfd, void *buf, size_t count); +off_t blseek(BFILE *bfd, off_t offset, int whence); +int is_bopen(BFILE *bfd); +void binit(BFILE *bfd); diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index a021e1905e..68e9e67050 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -679,7 +679,7 @@ parse_config(char *cf) if (i >= 0) { Dmsg2(150, "level=%d id=%s\n", level, lc->str); Dmsg1(150, "Keyword = %s\n", lc->str); - scan_err1(lc, "Keyword %s not permitted in this resource", lc->str); + scan_err1(lc, "Keyword \"%s\" not permitted in this resource", lc->str); /* NOT REACHED */ } break; @@ -705,6 +705,9 @@ parse_config(char *cf) /* NOT REACHED */ } } + if (state != p_none) { + scan_err0(lc, "End of conf file reached with unclosed resource."); + } if (debug_level > 50 && pass == 2) { int i; for (i=r_first; i<=r_last; i++) { diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 350c9e6df4..3b195b034b 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -153,6 +153,9 @@ BPIPE * open_bpipe(char *prog, int wait, char *mode); int close_wpipe(BPIPE *bpipe); int close_bpipe(BPIPE *bpipe); POOLMEM *edit_job_codes(void *jcr, char *omsg, char *imsg, char *to); +void parse_command_args(POOLMEM *cmd, POOLMEM *args, int *argc, + char **argk, char **argv); +char *next_arg(char **s); /* watchdog.c */ diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index a38eff903c..a1230d9123 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -644,3 +644,120 @@ POOLMEM *edit_job_codes(void *mjcr, char *omsg, char *imsg, char *to) } return omsg; } + +/* + * Return next argument from command line. Note, this + * routine is destructive. + */ +char *next_arg(char **s) +{ + char *p, *q, *n; + int in_quote = 0; + + /* skip past spaces to next arg */ + for (p=*s; *p && *p == ' '; ) { + p++; + } + Dmsg1(400, "Next arg=%s\n", p); + for (n = q = p; *p ; ) { + if (*p == '\\') { + p++; + if (*p) { + *q++ = *p++; + } else { + *q++ = *p; + } + continue; + } + if (*p == '"') { /* start or end of quote */ + if (in_quote) { + p++; /* skip quote */ + in_quote = 0; + continue; + } + in_quote = 1; + p++; + continue; + } + if (!in_quote && *p == ' ') { /* end of field */ + p++; + break; + } + *q++ = *p++; + } + *q = 0; + *s = p; + Dmsg2(400, "End arg=%s next=%s\n", n, p); + return n; +} + +/* + * This routine parses the input command line. + * It makes a copy in args, then builds an + * argc, argv like list where + * + * argc = count of arguments + * argk[i] = argument keyword (part preceding =) + * argv[i] = argument value (part after =) + * + * example: arg1 arg2=abc arg3= + * + * argc = c + * argk[0] = arg1 + * argv[0] = NULL + * argk[1] = arg2 + * argv[1] = abc + * argk[2] = arg3 + * argv[2] = + */ + +void parse_command_args(POOLMEM *cmd, POOLMEM *args, int *argc, + char **argk, char **argv) +{ + char *p, *q, *n; + int len; + + len = strlen(cmd) + 1; + args = check_pool_memory_size(args, len); + bstrncpy(args, cmd, len); + strip_trailing_junk(args); + *argc = 0; + p = args; + /* Pick up all arguments */ + while (*argc < MAX_CMD_ARGS) { + n = next_arg(&p); + if (*n) { + argk[*argc] = n; + argv[(*argc)++] = NULL; + } else { + break; + } + } + /* Separate keyword and value */ + for (int i=0; i < *argc; i++) { + p = strchr(argk[i], '='); + if (p) { + *p++ = 0; /* terminate keyword and point to value */ + /* Unquote quoted values */ + if (*p == '"') { + for (n = q = ++p; *p && *p != '"'; ) { + if (*p == '\\') { + p++; + } + *q++ = *p++; + } + *q = 0; /* terminate string */ + p = n; /* point to string */ + } + if (strlen(p) > MAX_NAME_LENGTH-1) { + p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */ + } + } + argv[i] = p; /* save ptr to value or NULL */ + } +#ifdef xxxx + for (i=0; i= 0) { + if (is_bopen(&bfd)) { set_attributes(jcr, fname, ofile, lname, type, stream, &statp, - attribsEx, &ofd); + attribsEx, &bfd); } release_device(jcr, dev); @@ -256,12 +257,12 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) * close the output file. */ if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR, 0, "Logic error output file should be open\n"); + if (!is_bopen(&bfd)) { + Emsg0(M_ERROR, 0, "Logic error output file should be open but is not.\n"); } extract = FALSE; set_attributes(jcr, fname, ofile, lname, type, stream, &statp, - attribsEx, &ofd); + attribsEx, &bfd); } if (sizeof_pool_memory(fname) < rec->data_len) { @@ -354,8 +355,10 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) strcat(ofile, "/"); } strcat(ofile, fn); /* copy rest of name */ - /* Fixup link name */ - if (type == FT_LNK || type == FT_LNKSAVED) { + /* Fixup link name for hard links, but not for + * soft links + */ + if (type == FT_LNKSAVED) { if (lp[0] == '/') { /* if absolute path */ strcpy(lname, where); } @@ -371,15 +374,20 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) extract = FALSE; stat = create_file(jcr, fname, ofile, lname, type, stream, - &statp, attribsEx, &ofd, REPLACE_ALWAYS); + &statp, attribsEx, &bfd, REPLACE_ALWAYS); switch (stat) { case CF_ERROR: case CF_SKIP: break; case CF_EXTRACT: extract = TRUE; - /* Fall-through wanted */ + print_ls_output(ofile, lname, type, &statp); + num_files++; + fileAddr = 0; + break; case CF_CREATED: + set_attributes(jcr, fname, ofile, lname, type, stream, &statp, + attribsEx, &bfd); print_ls_output(ofile, lname, type, &statp); num_files++; fileAddr = 0; @@ -399,7 +407,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) unser_uint64(faddr); if (fileAddr != faddr) { fileAddr = faddr; - if (lseek(ofd, (off_t)fileAddr, SEEK_SET) < 0) { + if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) { Emsg2(M_ERROR_TERM, 0, _("Seek error on %s: %s\n"), ofile, strerror(errno)); } } @@ -409,7 +417,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } total += wsize; Dmsg2(8, "Write %u bytes, total=%u\n", wsize, total); - if ((uint32_t)write(ofd, wbuf, wsize) != wsize) { + if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) { Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), ofile, strerror(errno)); } fileAddr += wsize; @@ -430,7 +438,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) unser_uint64(faddr); if (fileAddr != faddr) { fileAddr = faddr; - if (lseek(ofd, (off_t)fileAddr, SEEK_SET) < 0) { + if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) { Emsg2(M_ERROR, 0, _("Seek error on %s: %s\n"), ofile, strerror(errno)); } } @@ -445,7 +453,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); - if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) { + if ((uLongf)bwrite(&bfd, compress_buf, (size_t)compress_len) != compress_len) { Pmsg0(0, "===Write error===\n"); Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), ofile, strerror(errno)); } @@ -463,12 +471,12 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) /* If extracting, wierd stream (not 1 or 2), close output file anyway */ } else if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR, 0, "Logic error output file should be open\n"); + if (!is_bopen(&bfd)) { + Emsg0(M_ERROR, 0, "Logic error output file should be open but is not.\n"); } extract = FALSE; set_attributes(jcr, fname, ofile, lname, type, stream, &statp, - attribsEx, &ofd); + attribsEx, &bfd); } else if (rec->Stream == STREAM_PROGRAM_NAMES || rec->Stream == STREAM_PROGRAM_DATA) { if (!prog_name_msg) { Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n"); diff --git a/bacula/src/version.h b/bacula/src/version.h index 2b1eb3cc19..bb796f578d 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.30" #define VSTRING "1" -#define BDATE "10 April 2003" -#define LSMDATE "10Apr03" +#define BDATE "12 April 2003" +#define LSMDATE "12Apr03" /* Debug flags */ #define DEBUG 1