X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fscan.c;h=d8dfab383562fc8ad7b989abe46776f4a42d6524;hb=f5e7d95ce741ea5c296d605b2f411805a65462d6;hp=70d567fc33fc691c7086253fb5f008fa17f0e893;hpb=66696d1cadedbb362c392dadce9a8ce275dd5d80;p=bacula%2Fbacula diff --git a/bacula/src/lib/scan.c b/bacula/src/lib/scan.c index 70d567fc33..d8dfab3835 100644 --- a/bacula/src/lib/scan.c +++ b/bacula/src/lib/scan.c @@ -1,63 +1,106 @@ /* - * scan.c -- scanning routines for Bacula - * - * Kern Sibbald, MM separated from util.c MMIII - * - * Version $Id$ - */ + Bacula® - The Network Backup Solution -/* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2011 Free Software Foundation Europe e.V. - 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. + 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 + 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. +*/ +/* + * scan.c -- scanning routines for Bacula + * + * Kern Sibbald, MM separated from util.c MMIII + * */ #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; -/* Strip any trailing junk from the command */ + while (B_ISSPACE(*p)) { + p++; + } + if (p != str) { + strcpy(str, p); + } +} + +/* + * Strip any trailing junk from the command + */ void strip_trailing_junk(char *cmd) { char *p; + + /* + * Strip trailing junk from command + */ p = cmd + strlen(cmd) - 1; + while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) { + *p-- = 0; + } +} + +/* + * Strip any trailing newline characters from the string + */ +void strip_trailing_newline(char *cmd) +{ + char *p; - /* strip trailing junk from command */ - while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) + p = cmd + strlen(cmd) - 1; + while ((p >= cmd) && (*p == '\n' || *p == '\r')) { *p-- = 0; + } } -/* Strip any trailing slashes from a directory path */ +/* + * Strip any trailing slashes from a directory path + */ void strip_trailing_slashes(char *dir) { char *p; - p = dir + strlen(dir) - 1; - /* strip trailing slashes */ - while ((p >= dir) && (*p == '/')) + /* + * Strip trailing slashes + */ + p = dir + strlen(dir) - 1; + while (p >= dir && IsPathSeparator(*p)) { *p-- = 0; + } } /* * Skip spaces * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * 1 on success + * new address in passed parameter */ bool skip_spaces(char **msg) { @@ -75,8 +118,8 @@ bool skip_spaces(char **msg) /* * Skip nonspaces * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * 1 on success + * new address in passed parameter */ bool skip_nonspaces(char **msg) { @@ -92,28 +135,29 @@ bool skip_nonspaces(char **msg) return *p ? true : false; } -/* folded search for string - case insensitive */ -int -fstrsch(const char *a, const char *b) /* folded case search */ +/* + * Folded search for string - case insensitive + */ +int 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++; @@ -121,10 +165,20 @@ fstrsch(const char *a, const char *b) /* folded case search */ return 1; } - /* * 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) { @@ -135,43 +189,38 @@ char *next_arg(char **s) 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 =) @@ -187,49 +236,22 @@ char *next_arg(char **s) * argk[2] = arg3 * argv[2] = */ - int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, - char **argk, char **argv, int max_args) + char **argk, char **argv, int max_args) { - char *p, *q, *n; + char *p; + + parse_args_only(cmd, args, argc, argk, argv, max_args); - pm_strcpy(args, cmd); - strip_trailing_junk(*args); - p = *args; - *argc = 0; - /* Pick up all arguments */ - while (*argc < max_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 */ - } + *p++ = 0; /* terminate keyword and point to value */ } - argv[i] = p; /* save ptr to value or NULL */ + argv[i] = p; /* save ptr to value or NULL */ } -#ifdef xxxx +#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"); } @@ -237,13 +259,61 @@ int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, return 1; } + +/* + * 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, *n; + + pm_strcpy(args, cmd); + strip_trailing_junk(*args); + p = *args; + *argc = 0; + /* + * Pick up all arguments + */ + while (*argc < max_args) { + n = next_arg(&p); + if (*n) { + argk[*argc] = n; + argv[(*argc)++] = NULL; + } else { + break; + } + } + 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; @@ -258,25 +328,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 +362,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, ...) @@ -305,100 +375,131 @@ int bsscanf(const char *buf, const char *fmt, ...) int max_len = BIG; uint64_t value; bool error = false; + bool negative; va_start(ap, 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++) { - case 'u': - case 'd': - value = 0; - while (B_ISDIGIT(*buf)) { - value = B_TIMES10(value) + *buf++ - '0'; - } - vp = (void *)va_arg(ap, void *); + switch (*fmt++) { + case 'u': + value = 0; + while (B_ISDIGIT(*buf)) { + value = B_TIMES10(value) + *buf++ - '0'; + } + vp = (void *)va_arg(ap, void *); +// Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp); + 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; +// Dmsg0(000, "Store 64 bit int\n"); + } + count++; + l = 0; + break; + case 'd': + value = 0; + if (*buf == '-') { + negative = true; + buf++; + } else { + negative = false; + } + while (B_ISDIGIT(*buf)) { + value = B_TIMES10(value) + *buf++ - '0'; + } + if (negative) { + value = -value; + } + 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) { + *((int32_t *)vp) = (int32_t)value; // Dmsg0(000, "Store 32 bit int\n"); - } else { - *((uint64_t *)vp) = (uint64_t)value; + } else { + *((int64_t *)vp) = (int64_t)value; // Dmsg0(000, "Store 64 bit int\n"); - } - count++; - l = 0; - break; - case 'l': + } + count++; + l = 0; + break; + case 'l': // Dmsg0(000, "got l\n"); - l = 1; - if (*fmt == 'l') { - l++; - fmt++; - } - if (*fmt == 'd' || *fmt == 'u') { - goto switch_top; - } + l = 1; + if (*fmt == 'l') { + l++; + fmt++; + } + if (*fmt == 'd' || *fmt == 'u') { + goto switch_top; + } // Dmsg1(000, "fmt=%c !=d,u\n", *fmt); - error = true; - break; - case 'q': - l = 2; - if (*fmt == 'd' || *fmt == 'u') { - goto switch_top; - } + error = true; + break; + case 'q': + l = 2; + if (*fmt == 'd' || *fmt == 'u') { + goto switch_top; + } // Dmsg1(000, "fmt=%c !=d,u\n", *fmt); - error = true; - break; - case 's': + 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; - case 'c': - 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)) { - max_len = B_TIMES10(max_len) + *fmt++ - '0'; - } + 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; + case '%': + if (*buf++ != '%') { + 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; - } + if (*fmt == 's') { + 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); @@ -434,25 +535,25 @@ 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; @@ -470,14 +571,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); }