]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/scan.c
kes Write new subroutine is_volume_purged() that explicitly checks
[bacula/bacula] / bacula / src / lib / scan.c
1 /*
2  *   scan.c -- scanning routines for Bacula
3  *
4  *    Kern Sibbald, MM  separated from util.c MMIII
5  *
6  *   Version $Id$
7  */
8 /*
9    Bacula® - The Network Backup Solution
10
11    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
12
13    The main author of Bacula is Kern Sibbald, with contributions from
14    many others, a complete list can be found in the file AUTHORS.
15    This program is Free Software; you can redistribute it and/or
16    modify it under the terms of version two of the GNU General Public
17    License as published by the Free Software Foundation plus additions
18    that are listed in the file LICENSE.
19
20    This program is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28    02110-1301, USA.
29
30    Bacula® is a registered trademark of John Walker.
31    The licensor of Bacula is the Free Software Foundation Europe
32    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33    Switzerland, email:ftf@fsfeurope.org.
34 */
35
36
37 #include "bacula.h"
38 #include "jcr.h"
39 #include "findlib/find.h"
40
41 /* Strip leading space from command line arguments */
42 void strip_leading_space(char *str)
43 {
44    char *p = str;
45    while (B_ISSPACE(*p)) {
46       p++;
47    }
48    if (p != str) {
49       strcpy(str, p);
50    }
51 }
52
53
54 /* Strip any trailing junk from the command */
55 void strip_trailing_junk(char *cmd)
56 {
57    char *p;
58    p = cmd + strlen(cmd) - 1;
59
60    /* strip trailing junk from command */
61    while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
62       *p-- = 0;
63 }
64
65 /* Strip any trailing newline characters from the string */
66 void strip_trailing_newline(char *cmd)
67 {
68    char *p;
69    p = cmd + strlen(cmd) - 1;
70
71    while ((p >= cmd) && (*p == '\n' || *p == '\r'))
72       *p-- = 0;
73 }
74
75 /* Strip any trailing slashes from a directory path */
76 void strip_trailing_slashes(char *dir)
77 {
78    char *p;
79    p = dir + strlen(dir) - 1;
80
81    /* strip trailing slashes */
82    while (p >= dir && IsPathSeparator(*p))
83       *p-- = 0;
84 }
85
86 /*
87  * Skip spaces
88  *  Returns: 0 on failure (EOF)
89  *           1 on success
90  *           new address in passed parameter
91  */
92 bool skip_spaces(char **msg)
93 {
94    char *p = *msg;
95    if (!p) {
96       return false;
97    }
98    while (*p && B_ISSPACE(*p)) {
99       p++;
100    }
101    *msg = p;
102    return *p ? true : false;
103 }
104
105 /*
106  * Skip nonspaces
107  *  Returns: 0 on failure (EOF)
108  *           1 on success
109  *           new address in passed parameter
110  */
111 bool skip_nonspaces(char **msg)
112 {
113    char *p = *msg;
114
115    if (!p) {
116       return false;
117    }
118    while (*p && !B_ISSPACE(*p)) {
119       p++;
120    }
121    *msg = p;
122    return *p ? true : false;
123 }
124
125 /* folded search for string - case insensitive */
126 int
127 fstrsch(const char *a, const char *b)   /* folded case search */
128 {
129    const char *s1,*s2;
130    char c1, c2;
131
132    s1=a;
133    s2=b;
134    while (*s1) {                      /* do it the fast way */
135       if ((*s1++ | 0x20) != (*s2++ | 0x20))
136          return 0;                    /* failed */
137    }
138    while (*a) {                       /* do it over the correct slow way */
139       if (B_ISUPPER(c1 = *a)) {
140          c1 = tolower((int)c1);
141       }
142       if (B_ISUPPER(c2 = *b)) {
143          c2 = tolower((int)c2);
144       }
145       if (c1 != c2) {
146          return 0;
147       }
148       a++;
149       b++;
150    }
151    return 1;
152 }
153
154
155 /*
156  * Return next argument from command line.  Note, this
157  *   routine is destructive because it stored 0 at the end
158  *   of each argument.
159  * Called with pointer to pointer to command line. This
160  *   pointer is updated to point to the remainder of the
161  *   command line.
162  * 
163  * Returns pointer to next argument -- don't store the result
164  *   in the pointer you passed as an argument ...
165  *   The next argument is terminated by a space unless within
166  *   quotes. Double quote characters (unless preceded by a \) are
167  *   stripped.
168  *   
169  */
170 char *next_arg(char **s)
171 {
172    char *p, *q, *n;
173    bool in_quote = false;
174
175    /* skip past spaces to next arg */
176    for (p=*s; *p && B_ISSPACE(*p); ) {
177       p++;
178    }
179    Dmsg1(900, "Next arg=%s\n", p);
180    for (n = q = p; *p ; ) {
181       if (*p == '\\') {                 /* slash? */
182          p++;                           /* yes, skip it */
183          if (*p) {
184             *q++ = *p++;
185          } else {
186             *q++ = *p;
187          }
188          continue;
189       }
190       if (*p == '"') {                  /* start or end of quote */
191          p++;
192          in_quote = !in_quote;          /* change state */
193          continue;
194       }
195       if (!in_quote && B_ISSPACE(*p)) { /* end of field */
196          p++;
197          break;
198       }
199       *q++ = *p++;
200    }
201    *q = 0;
202    *s = p;
203    Dmsg2(900, "End arg=%s next=%s\n", n, p);
204    return n;
205 }
206
207 /*
208  * This routine parses the input command line.
209  * It makes a copy in args, then builds an
210  *  argc, argk, argv list where:
211  *
212  *  argc = count of arguments
213  *  argk[i] = argument keyword (part preceding =)
214  *  argv[i] = argument value (part after =)
215  *
216  *  example:  arg1 arg2=abc arg3=
217  *
218  *  argc = c
219  *  argk[0] = arg1
220  *  argv[0] = NULL
221  *  argk[1] = arg2
222  *  argv[1] = abc
223  *  argk[2] = arg3
224  *  argv[2] =
225  */
226 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
227                char **argk, char **argv, int max_args)
228 {
229    char *p;
230
231    parse_args_only(cmd, args, argc, argk, argv, max_args);
232
233    /* Separate keyword and value */
234    for (int i=0; i < *argc; i++) {
235       p = strchr(argk[i], '=');
236       if (p) {
237          *p++ = 0;                    /* terminate keyword and point to value */
238          if (strlen(p) > MAX_NAME_LENGTH-1) {
239             p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */
240          }
241       }
242       argv[i] = p;                    /* save ptr to value or NULL */
243    }
244 #ifdef xxx_debug
245    for (int i=0; i < *argc; i++) {
246       Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
247    }
248 #endif
249    return 1;
250 }
251
252
253 /*
254  * This routine parses the input command line.
255  *   It makes a copy in args, then builds an
256  *   argc, argk, but no argv (values).
257  *   This routine is useful for scanning command lines where the data 
258  *   is a filename and no keywords are expected.  If we scan a filename
259  *   for keywords, any = in the filename will be interpreted as the
260  *   end of a keyword, and this is not good.
261  *
262  *  argc = count of arguments
263  *  argk[i] = argument keyword (part preceding =)
264  *  argv[i] = NULL                         
265  *
266  *  example:  arg1 arg2=abc arg3=
267  *
268  *  argc = c
269  *  argk[0] = arg1
270  *  argv[0] = NULL
271  *  argk[1] = arg2=abc
272  *  argv[1] = NULL
273  *  argk[2] = arg3
274  *  argv[2] =
275  */
276 int parse_args_only(POOLMEM *cmd, POOLMEM **args, int *argc,
277                     char **argk, char **argv, int max_args)
278 {
279    char *p, *n;
280
281    pm_strcpy(args, cmd);
282    strip_trailing_junk(*args);
283    p = *args;
284    *argc = 0;
285    /* Pick up all arguments */
286    while (*argc < max_args) {
287       n = next_arg(&p);
288       if (*n) {
289          argk[*argc] = n;
290          argv[(*argc)++] = NULL;
291       } else {
292          break;
293       }
294    }
295    return 1;
296 }
297
298
299 /*
300  * Given a full filename, split it into its path
301  *  and filename parts. They are returned in pool memory
302  *  in the arguments provided.
303  */
304 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
305         POOLMEM **file, int *fnl)
306 {
307    const char *f;
308    int slen;
309    int len = slen = strlen(fname);
310
311    /*
312     * Find path without the filename.
313     * I.e. everything after the last / is a "filename".
314     * OK, maybe it is a directory name, but we treat it like
315     * a filename. If we don't find a / then the whole name
316     * must be a path name (e.g. c:).
317     */
318    f = fname + len - 1;
319    /* "strip" any trailing slashes */
320    while (slen > 1 && IsPathSeparator(*f)) {
321       slen--;
322       f--;
323    }
324    /* Walk back to last slash -- begin of filename */
325    while (slen > 0 && !IsPathSeparator(*f)) {
326       slen--;
327       f--;
328    }
329    if (IsPathSeparator(*f)) {         /* did we find a slash? */
330       f++;                            /* yes, point to filename */
331    } else {                           /* no, whole thing must be path name */
332       f = fname;
333    }
334    Dmsg2(200, "after strip len=%d f=%s\n", len, f);
335    *fnl = fname - f + len;
336    if (*fnl > 0) {
337       *file = check_pool_memory_size(*file, *fnl+1);
338       memcpy(*file, f, *fnl);    /* copy filename */
339    }
340    (*file)[*fnl] = 0;
341
342    *pnl = f - fname;
343    if (*pnl > 0) {
344       *path = check_pool_memory_size(*path, *pnl+1);
345       memcpy(*path, fname, *pnl);
346    }
347    (*path)[*pnl] = 0;
348
349    Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
350    Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
351 }
352
353 /*
354  * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns)
355  */
356 const int BIG = 1000;
357 int bsscanf(const char *buf, const char *fmt, ...)
358 {
359    va_list ap;
360    int count = 0;
361    void *vp;
362    char *cp;
363    int l = 0;
364    int max_len = BIG;
365    uint64_t value;
366    bool error = false;
367
368    va_start(ap, fmt);
369    while (*fmt && !error) {
370 //    Dmsg1(000, "fmt=%c\n", *fmt);
371       if (*fmt == '%') {
372          fmt++;
373 //       Dmsg1(000, "Got %% nxt=%c\n", *fmt);
374 switch_top:
375          switch (*fmt++) {
376          case 'u':
377          case 'd':
378             value = 0;
379             while (B_ISDIGIT(*buf)) {
380                value = B_TIMES10(value) + *buf++ - '0';
381             }
382             vp = (void *)va_arg(ap, void *);
383 //          Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
384             if (l == 0) {
385                *((int *)vp) = (int)value;
386             } else if (l == 1) {
387                *((uint32_t *)vp) = (uint32_t)value;
388 //             Dmsg0(000, "Store 32 bit int\n");
389             } else {
390                *((uint64_t *)vp) = (uint64_t)value;
391 //             Dmsg0(000, "Store 64 bit int\n");
392             }
393             count++;
394             l = 0;
395             break;
396          case 'l':
397 //          Dmsg0(000, "got l\n");
398             l = 1;
399             if (*fmt == 'l') {
400                l++;
401                fmt++;
402             }
403             if (*fmt == 'd' || *fmt == 'u') {
404                goto switch_top;
405             }
406 //          Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
407             error = true;
408             break;
409          case 'q':
410             l = 2;
411             if (*fmt == 'd' || *fmt == 'u') {
412                goto switch_top;
413             }
414 //          Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
415             error = true;
416             break;
417          case 's':
418 //          Dmsg1(000, "Store string max_len=%d\n", max_len);
419             cp = (char *)va_arg(ap, char *);
420             while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
421                *cp++ = *buf++;
422             }
423             *cp = 0;
424             count++;
425             max_len = BIG;
426             break;
427          case 'c':
428             cp = (char *)va_arg(ap, char *);
429             *cp = *buf++;
430             count++;
431             break;
432          case '%':
433             if (*buf++ != '%') {
434                error = true;
435             }
436             break;
437          default:
438             fmt--;
439             max_len = 0;
440             while (B_ISDIGIT(*fmt)) {
441                max_len = B_TIMES10(max_len) + *fmt++ - '0';
442             }
443 //          Dmsg1(000, "Default max_len=%d\n", max_len);
444             if (*fmt == 's') {
445                goto switch_top;
446             }
447 //          Dmsg1(000, "Default c=%c\n", *fmt);
448             error = true;
449             break;                    /* error: unknown format */
450          }
451          continue;
452
453       /* White space eats zero or more whitespace */
454       } else if (B_ISSPACE(*fmt)) {
455          fmt++;
456          while (B_ISSPACE(*buf)) {
457             buf++;
458          }
459       /* Plain text must match */
460       } else if (*buf++ != *fmt++) {
461 //       Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
462          error = true;
463          break;
464       }
465    }
466    va_end(ap);
467 // Dmsg2(000, "Error=%d count=%d\n", error, count);
468    if (error) {
469       count = -1;
470    }
471    return count;
472 }
473
474 #ifdef TEST_PROGRAM
475 int main(int argc, char *argv[])
476 {
477    char buf[100];
478    uint32_t val32;
479    uint64_t val64;
480    uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
481    char Job[200];
482    int cnt;
483    char *helloreq= "Hello *UserAgent* calling\n";
484    char *hello = "Hello %127s calling\n";
485    char *catreq =
486 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
487 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
488   "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
489   "StartBlock=%u EndBlock=%u\n";
490 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
491    " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
492    " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
493    " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
494    " VolReadTime=%" lld " VolWriteTime=%" lld;
495    char *media =
496 "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";
497 struct VOLUME_CAT_INFO {
498    /* Media info for the current Volume */
499    uint32_t VolCatJobs;               /* number of jobs on this Volume */
500    uint32_t VolCatFiles;              /* Number of files */
501    uint32_t VolCatBlocks;             /* Number of blocks */
502    uint64_t VolCatBytes;              /* Number of bytes written */
503    uint32_t VolCatMounts;             /* Number of mounts this volume */
504    uint32_t VolCatErrors;             /* Number of errors this volume */
505    uint32_t VolCatWrites;             /* Number of writes this volume */
506    uint32_t VolCatReads;              /* Number of reads this volume */
507    uint64_t VolCatRBytes;             /* Number of bytes read */
508    uint32_t VolCatRecycles;           /* Number of recycles this volume */
509    int32_t  Slot;                     /* Slot in changer */
510    bool     InChanger;                /* Set if vol in current magazine */
511    uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
512    uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
513    uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
514    uint64_t VolCatCapacityBytes;      /* capacity estimate */
515    uint64_t VolReadTime;              /* time spent reading */
516    uint64_t VolWriteTime;             /* time spent writing this Volume */
517    char VolCatStatus[20];             /* Volume status */
518    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
519 };
520    struct VOLUME_CAT_INFO vol;
521
522 #ifdef xxx
523    bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
524    printf("%s %d %lld\n", buf, val32, val64);
525
526    *Job=0;
527    cnt = bsscanf(catreq, Create_job_media, &Job,
528       &FirstIndex, &LastIndex, &StartFile, &EndFile,
529       &StartBlock, &EndBlock);
530    printf("cnt=%d Job=%s\n", cnt, Job);
531    cnt = bsscanf(helloreq, hello, &Job);
532    printf("cnt=%d Agent=%s\n", cnt, Job);
533 #endif
534    cnt = bsscanf(media, OK_media,
535                vol.VolCatName,
536                &vol.VolCatJobs, &vol.VolCatFiles,
537                &vol.VolCatBlocks, &vol.VolCatBytes,
538                &vol.VolCatMounts, &vol.VolCatErrors,
539                &vol.VolCatWrites, &vol.VolCatMaxBytes,
540                &vol.VolCatCapacityBytes, vol.VolCatStatus,
541                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
542                &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
543    printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);
544
545 }
546
547 #endif