X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fscan.c;h=aacad954bd4b1ffdf2e859b4b85edcf76a9c9e56;hb=4d90a54f244499151f1c2451d420c624524a3ba9;hp=ef338a9a1bbee88ee07bc313232cfee4960b4d33;hpb=a20ea21baab734ce78a53c7a8373ea8a4564f857;p=bacula%2Fbacula diff --git a/bacula/src/lib/scan.c b/bacula/src/lib/scan.c index ef338a9a1b..aacad954bd 100644 --- a/bacula/src/lib/scan.c +++ b/bacula/src/lib/scan.c @@ -1,35 +1,55 @@ /* * scan.c -- scanning routines for Bacula - * - * Kern Sibbald, MM separated from util.c MMIII + * + * Kern Sibbald, MM separated from util.c MMIII * * Version $Id$ */ - /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Bacula® - The Network Backup Solution - 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. + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + 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. + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ - */ #include "bacula.h" #include "jcr.h" #include "findlib/find.h" +/* Strip leading space from command line arguments */ +void strip_leading_space(char *str) +{ + char *p = str; + while (B_ISSPACE(*p)) { + p++; + } + if (p != str) { + strcpy(str, p); + } +} + /* Strip any trailing junk from the command */ void strip_trailing_junk(char *cmd) @@ -42,6 +62,16 @@ void strip_trailing_junk(char *cmd) *p-- = 0; } +/* Strip any trailing newline characters from the string */ +void strip_trailing_newline(char *cmd) +{ + char *p; + p = cmd + strlen(cmd) - 1; + + while ((p >= cmd) && (*p == '\n' || *p == '\r')) + *p-- = 0; +} + /* Strip any trailing slashes from a directory path */ void strip_trailing_slashes(char *dir) { @@ -49,15 +79,15 @@ void strip_trailing_slashes(char *dir) p = dir + strlen(dir) - 1; /* strip trailing slashes */ - while ((p >= dir) && (*p == '/')) + while (p >= dir && IsPathSeparator(*p)) *p-- = 0; } /* * Skip spaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * Returns: 0 on failure (EOF) + * 1 on success + * new address in passed parameter */ bool skip_spaces(char **msg) { @@ -74,9 +104,9 @@ bool skip_spaces(char **msg) /* * Skip nonspaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * Returns: 0 on failure (EOF) + * 1 on success + * new address in passed parameter */ bool skip_nonspaces(char **msg) { @@ -94,26 +124,26 @@ bool skip_nonspaces(char **msg) /* folded search for string - case insensitive */ int -fstrsch(const char *a, const char *b) /* folded case search */ +fstrsch(const char *a, const char *b) /* folded case search */ { const char *s1,*s2; char c1, c2; s1=a; s2=b; - while (*s1) { /* do it the fast way */ + while (*s1) { /* do it the fast way */ if ((*s1++ | 0x20) != (*s2++ | 0x20)) - return 0; /* failed */ + return 0; /* failed */ } - while (*a) { /* do it over the correct slow way */ + while (*a) { /* do it over the correct slow way */ if (B_ISUPPER(c1 = *a)) { - c1 = tolower((int)c1); + c1 = tolower((int)c1); } if (B_ISUPPER(c2 = *b)) { - c2 = tolower((int)c2); + c2 = tolower((int)c2); } if (c1 != c2) { - return 0; + return 0; } a++; b++; @@ -122,9 +152,20 @@ fstrsch(const char *a, const char *b) /* folded case search */ } -/* +/* * Return next argument from command line. Note, this - * routine is destructive. + * routine is destructive because it stored 0 at the end + * of each argument. + * Called with pointer to pointer to command line. This + * pointer is updated to point to the remainder of the + * command line. + * + * Returns pointer to next argument -- don't store the result + * in the pointer you passed as an argument ... + * The next argument is terminated by a space unless within + * quotes. Double quote characters (unless preceded by a \) are + * stripped. + * */ char *next_arg(char **s) { @@ -134,45 +175,40 @@ char *next_arg(char **s) /* skip past spaces to next arg */ for (p=*s; *p && B_ISSPACE(*p); ) { p++; - } - Dmsg1(400, "Next arg=%s\n", p); + } + Dmsg1(900, "Next arg=%s\n", p); for (n = q = p; *p ; ) { - if (*p == '\\') { - p++; - if (*p) { - *q++ = *p++; - } else { - *q++ = *p; - } - continue; + if (*p == '\\') { /* slash? */ + p++; /* yes, skip it */ + if (*p) { + *q++ = *p++; + } else { + *q++ = *p; + } + continue; } if (*p == '"') { /* start or end of quote */ - if (in_quote) { - p++; /* skip quote */ - in_quote = false; - continue; - } - in_quote = true; - p++; - continue; + p++; + in_quote = !in_quote; /* change state */ + continue; } - if (!in_quote && B_ISSPACE(*p)) { /* end of field */ - p++; - break; + if (!in_quote && B_ISSPACE(*p)) { /* end of field */ + p++; + break; } *q++ = *p++; } *q = 0; *s = p; - Dmsg2(400, "End arg=%s next=%s\n", n, p); + Dmsg2(900, "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, argk, argv list where: + * * argc = count of arguments * argk[i] = argument keyword (part preceding =) * argv[i] = argument value (part after =) @@ -185,13 +221,59 @@ char *next_arg(char **s) * argk[1] = arg2 * argv[1] = abc * argk[2] = arg3 - * argv[2] = + * argv[2] = */ +int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, + char **argk, char **argv, int max_args) +{ + char *p; + + parse_args_only(cmd, args, argc, argk, argv, max_args); + + /* 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 */ + } + argv[i] = p; /* save ptr to value or NULL */ + } +#ifdef xxx_debug + for (int i=0; i < *argc; i++) { + Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL"); + } +#endif + return 1; +} -int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, - char **argk, char **argv, int max_args) + +/* + * This routine parses the input command line. + * It makes a copy in args, then builds an + * argc, argk, but no argv (values). + * This routine is useful for scanning command lines where the data + * is a filename and no keywords are expected. If we scan a filename + * for keywords, any = in the filename will be interpreted as the + * end of a keyword, and this is not good. + * + * argc = count of arguments + * argk[i] = argument keyword (part preceding =) + * argv[i] = NULL + * + * example: arg1 arg2=abc arg3= + * + * argc = c + * argk[0] = arg1 + * argv[0] = NULL + * argk[1] = arg2=abc + * argv[1] = NULL + * argk[2] = arg3 + * argv[2] = + */ +int parse_args_only(POOLMEM *cmd, POOLMEM **args, int *argc, + char **argk, char **argv, int max_args) { - char *p, *q, *n; + char *p, *n; pm_strcpy(args, cmd); strip_trailing_junk(*args); @@ -199,58 +281,32 @@ int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, *argc = 0; /* Pick up all arguments */ while (*argc < max_args) { - n = next_arg(&p); + n = next_arg(&p); if (*n) { - argk[*argc] = n; - argv[(*argc)++] = NULL; + 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 */ - } + break; } - argv[i] = p; /* save ptr to value or NULL */ - } -#ifdef xxxx - for (int i=0; i < *argc; i++) { - Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL"); } -#endif return 1; } + /* * Given a full filename, split it into its path * and filename parts. They are returned in pool memory * in the arguments provided. */ void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl, - POOLMEM **file, int *fnl) + POOLMEM **file, int *fnl) { const char *f; int slen; int len = slen = strlen(fname); /* - * Find path without the filename. + * Find path without the filename. * I.e. everything after the last / is a "filename". * OK, maybe it is a directory name, but we treat it like * a filename. If we don't find a / then the whole name @@ -258,25 +314,25 @@ void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl, */ f = fname + len - 1; /* "strip" any trailing slashes */ - while (slen > 1 && *f == '/') { + while (slen > 1 && IsPathSeparator(*f)) { slen--; f--; } /* Walk back to last slash -- begin of filename */ - while (slen > 0 && *f != '/') { + while (slen > 0 && !IsPathSeparator(*f)) { slen--; f--; } - if (*f == '/') { /* did we find a slash? */ - f++; /* yes, point to filename */ - } else { /* no, whole thing must be path name */ + if (IsPathSeparator(*f)) { /* did we find a slash? */ + f++; /* yes, point to filename */ + } else { /* no, whole thing must be path name */ f = fname; } Dmsg2(200, "after strip len=%d f=%s\n", len, f); *fnl = fname - f + len; if (*fnl > 0) { *file = check_pool_memory_size(*file, *fnl+1); - memcpy(*file, f, *fnl); /* copy filename */ + memcpy(*file, f, *fnl); /* copy filename */ } (*file)[*fnl] = 0; @@ -292,7 +348,7 @@ void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl, } /* - * Extremely simple sscanf. Handles only %(u,d,ld,lu,lld,llu,c,nns) + * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns) */ const int BIG = 1000; int bsscanf(const char *buf, const char *fmt, ...) @@ -310,95 +366,98 @@ int bsscanf(const char *buf, const char *fmt, ...) while (*fmt && !error) { // Dmsg1(000, "fmt=%c\n", *fmt); if (*fmt == '%') { - fmt++; + fmt++; // Dmsg1(000, "Got %% nxt=%c\n", *fmt); switch_top: - switch (*fmt++) { + switch (*fmt++) { case 'u': case 'd': - value = 0; - while (B_ISDIGIT(*buf)) { + value = 0; + while (B_ISDIGIT(*buf)) { value = B_TIMES10(value) + *buf++ - '0'; - } - vp = (void *)va_arg(ap, void *); + } + vp = (void *)va_arg(ap, void *); // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp); - if (l < 2) { - *((uint32_t *)vp) = (uint32_t)value; + if (l == 0) { + *((int *)vp) = (int)value; + } else if (l == 1) { + *((uint32_t *)vp) = (uint32_t)value; // Dmsg0(000, "Store 32 bit int\n"); - } else { - *((uint64_t *)vp) = (uint64_t)value; + } else { + *((uint64_t *)vp) = (uint64_t)value; // Dmsg0(000, "Store 64 bit int\n"); - } - count++; - l = 0; - break; + } + count++; + l = 0; + break; case 'l': // Dmsg0(000, "got l\n"); - l = 1; + l = 1; if (*fmt == 'l') { - l++; - fmt++; - } + l++; + fmt++; + } if (*fmt == 'd' || *fmt == 'u') { - goto switch_top; - } + goto switch_top; + } // Dmsg1(000, "fmt=%c !=d,u\n", *fmt); - error = true; - break; + error = true; + break; case 'q': - l = 2; + l = 2; if (*fmt == 'd' || *fmt == 'u') { - goto switch_top; - } + goto switch_top; + } // Dmsg1(000, "fmt=%c !=d,u\n", *fmt); - error = true; - break; + error = true; + break; case 's': // Dmsg1(000, "Store string max_len=%d\n", max_len); - cp = (char *)va_arg(ap, char *); - while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) { - *cp++ = *buf++; - } - *cp = 0; - count++; - max_len = BIG; - break; + cp = (char *)va_arg(ap, char *); + while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) { + *cp++ = *buf++; + } + *cp = 0; + count++; + max_len = BIG; + break; case 'c': - cp = (char *)va_arg(ap, char *); - *cp = *buf++; - count++; - break; + cp = (char *)va_arg(ap, char *); + *cp = *buf++; + count++; + break; case '%': if (*buf++ != '%') { - error = true; - } - break; - default: - fmt--; - max_len = 0; - while (B_ISDIGIT(*fmt)) { + error = true; + } + break; + default: + fmt--; + max_len = 0; + while (B_ISDIGIT(*fmt)) { max_len = B_TIMES10(max_len) + *fmt++ - '0'; - } + } // Dmsg1(000, "Default max_len=%d\n", max_len); if (*fmt == 's') { - goto switch_top; - } + goto switch_top; + } // Dmsg1(000, "Default c=%c\n", *fmt); - error = true; - break; /* error: unknown format */ - } - continue; + error = true; + break; /* error: unknown format */ + } + continue; /* White space eats zero or more whitespace */ } else if (B_ISSPACE(*fmt)) { - fmt++; - while (B_ISSPACE(*buf)) { - buf++; - } + fmt++; + while (B_ISSPACE(*buf)) { + buf++; + } /* Plain text must match */ } else if (*buf++ != *fmt++) { // Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt); - error = true; + error = true; + break; } } va_end(ap); @@ -420,7 +479,7 @@ int main(int argc, char *argv[]) int cnt; char *helloreq= "Hello *UserAgent* calling\n"; char *hello = "Hello %127s calling\n"; - char *catreq = + char *catreq = "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248"; static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia " "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u " @@ -434,27 +493,27 @@ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u" "1000 OK VolName=TestVolume001 VolJobs=0 VolFiles=0 VolBlocks=0 VolBytes=1 VolMounts=0 VolErrors=0 VolWrites=0 MaxVolBytes=0 VolCapacityBytes=0 VolStatus=Append Slot=0 MaxVolJobs=0 MaxVolFiles=0 InChanger=1 VolReadTime=0 VolWriteTime=0"; struct VOLUME_CAT_INFO { /* Media info for the current Volume */ - uint32_t VolCatJobs; /* number of jobs on this Volume */ - uint32_t VolCatFiles; /* Number of files */ - uint32_t VolCatBlocks; /* Number of blocks */ - uint64_t VolCatBytes; /* Number of bytes written */ - uint32_t VolCatMounts; /* Number of mounts this volume */ - uint32_t VolCatErrors; /* Number of errors this volume */ - uint32_t VolCatWrites; /* Number of writes this volume */ - uint32_t VolCatReads; /* Number of reads this volume */ - uint64_t VolCatRBytes; /* Number of bytes read */ - uint32_t VolCatRecycles; /* Number of recycles this volume */ - int32_t Slot; /* Slot in changer */ - bool InChanger; /* Set if vol in current magazine */ - uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ - uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ - uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ + uint32_t VolCatJobs; /* number of jobs on this Volume */ + uint32_t VolCatFiles; /* Number of files */ + uint32_t VolCatBlocks; /* Number of blocks */ + uint64_t VolCatBytes; /* Number of bytes written */ + uint32_t VolCatMounts; /* Number of mounts this volume */ + uint32_t VolCatErrors; /* Number of errors this volume */ + uint32_t VolCatWrites; /* Number of writes this volume */ + uint32_t VolCatReads; /* Number of reads this volume */ + uint64_t VolCatRBytes; /* Number of bytes read */ + uint32_t VolCatRecycles; /* Number of recycles this volume */ + int32_t Slot; /* Slot in changer */ + bool InChanger; /* Set if vol in current magazine */ + uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ + uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ + uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ uint64_t VolCatCapacityBytes; /* capacity estimate */ - uint64_t VolReadTime; /* time spent reading */ - uint64_t VolWriteTime; /* time spent writing this Volume */ - char VolCatStatus[20]; /* Volume status */ + uint64_t VolReadTime; /* time spent reading */ + uint64_t VolWriteTime; /* time spent writing this Volume */ + char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ -}; +}; struct VOLUME_CAT_INFO vol; #ifdef xxx @@ -470,14 +529,14 @@ struct VOLUME_CAT_INFO { printf("cnt=%d Agent=%s\n", cnt, Job); #endif cnt = bsscanf(media, OK_media, - vol.VolCatName, - &vol.VolCatJobs, &vol.VolCatFiles, - &vol.VolCatBlocks, &vol.VolCatBytes, - &vol.VolCatMounts, &vol.VolCatErrors, - &vol.VolCatWrites, &vol.VolCatMaxBytes, - &vol.VolCatCapacityBytes, vol.VolCatStatus, - &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, - &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime); + vol.VolCatName, + &vol.VolCatJobs, &vol.VolCatFiles, + &vol.VolCatBlocks, &vol.VolCatBytes, + &vol.VolCatMounts, &vol.VolCatErrors, + &vol.VolCatWrites, &vol.VolCatMaxBytes, + &vol.VolCatCapacityBytes, vol.VolCatStatus, + &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, + &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime); printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName); }