]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/scan.c
Replace explicit checks for "/" with calls to IsPathSeparator, strchr with first_path...
[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.
158  */
159 char *next_arg(char **s)
160 {
161    char *p, *q, *n;
162    bool in_quote = false;
163
164    /* skip past spaces to next arg */
165    for (p=*s; *p && B_ISSPACE(*p); ) {
166       p++;
167    }
168    Dmsg1(900, "Next arg=%s\n", p);
169    for (n = q = p; *p ; ) {
170       if (*p == '\\') {
171          p++;
172          if (*p) {
173             *q++ = *p++;
174          } else {
175             *q++ = *p;
176          }
177          continue;
178       }
179       if (*p == '"') {                  /* start or end of quote */
180          if (in_quote) {
181             p++;                        /* skip quote */
182             in_quote = false;
183             continue;
184          }
185          in_quote = true;
186          p++;
187          continue;
188       }
189       if (!in_quote && B_ISSPACE(*p)) {     /* end of field */
190          p++;
191          break;
192       }
193       *q++ = *p++;
194    }
195    *q = 0;
196    *s = p;
197    Dmsg2(900, "End arg=%s next=%s\n", n, p);
198    return n;
199 }
200
201 /*
202  * This routine parses the input command line.
203  * It makes a copy in args, then builds an
204  *  argc, argv like list where
205  *
206  *  argc = count of arguments
207  *  argk[i] = argument keyword (part preceding =)
208  *  argv[i] = argument value (part after =)
209  *
210  *  example:  arg1 arg2=abc arg3=
211  *
212  *  argc = c
213  *  argk[0] = arg1
214  *  argv[0] = NULL
215  *  argk[1] = arg2
216  *  argv[1] = abc
217  *  argk[2] = arg3
218  *  argv[2] =
219  */
220
221 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
222                char **argk, char **argv, int max_args)
223 {
224    char *p, *q, *n;
225
226    pm_strcpy(args, cmd);
227    strip_trailing_junk(*args);
228    p = *args;
229    *argc = 0;
230    /* Pick up all arguments */
231    while (*argc < max_args) {
232       n = next_arg(&p);
233       if (*n) {
234          argk[*argc] = n;
235          argv[(*argc)++] = NULL;
236       } else {
237          break;
238       }
239    }
240    /* Separate keyword and value */
241    for (int i=0; i < *argc; i++) {
242       p = strchr(argk[i], '=');
243       if (p) {
244          *p++ = 0;                    /* terminate keyword and point to value */
245          /* Unquote quoted values */
246          if (*p == '"') {
247             for (n = q = ++p; *p && *p != '"'; ) {
248                if (*p == '\\') {
249                   p++;
250                }
251                *q++ = *p++;
252             }
253             *q = 0;                   /* terminate string */
254             p = n;                    /* point to string */
255          }
256          if (strlen(p) > MAX_NAME_LENGTH-1) {
257             p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */
258          }
259       }
260       argv[i] = p;                    /* save ptr to value or NULL */
261    }
262 #ifdef xxxx
263    for (int i=0; i < *argc; i++) {
264       Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
265    }
266 #endif
267    return 1;
268 }
269
270 /*
271  * Given a full filename, split it into its path
272  *  and filename parts. They are returned in pool memory
273  *  in the arguments provided.
274  */
275 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
276         POOLMEM **file, int *fnl)
277 {
278    const char *f;
279    int slen;
280    int len = slen = strlen(fname);
281
282    /*
283     * Find path without the filename.
284     * I.e. everything after the last / is a "filename".
285     * OK, maybe it is a directory name, but we treat it like
286     * a filename. If we don't find a / then the whole name
287     * must be a path name (e.g. c:).
288     */
289    f = fname + len - 1;
290    /* "strip" any trailing slashes */
291    while (slen > 1 && IsPathSeparator(*f)) {
292       slen--;
293       f--;
294    }
295    /* Walk back to last slash -- begin of filename */
296    while (slen > 0 && !IsPathSeparator(*f)) {
297       slen--;
298       f--;
299    }
300    if (IsPathSeparator(*f)) {         /* did we find a slash? */
301       f++;                            /* yes, point to filename */
302    } else {                           /* no, whole thing must be path name */
303       f = fname;
304    }
305    Dmsg2(200, "after strip len=%d f=%s\n", len, f);
306    *fnl = fname - f + len;
307    if (*fnl > 0) {
308       *file = check_pool_memory_size(*file, *fnl+1);
309       memcpy(*file, f, *fnl);    /* copy filename */
310    }
311    (*file)[*fnl] = 0;
312
313    *pnl = f - fname;
314    if (*pnl > 0) {
315       *path = check_pool_memory_size(*path, *pnl+1);
316       memcpy(*path, fname, *pnl);
317    }
318    (*path)[*pnl] = 0;
319
320    Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
321    Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
322 }
323
324 /*
325  * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns)
326  */
327 const int BIG = 1000;
328 int bsscanf(const char *buf, const char *fmt, ...)
329 {
330    va_list ap;
331    int count = 0;
332    void *vp;
333    char *cp;
334    int l = 0;
335    int max_len = BIG;
336    uint64_t value;
337    bool error = false;
338
339    va_start(ap, fmt);
340    while (*fmt && !error) {
341 //    Dmsg1(000, "fmt=%c\n", *fmt);
342       if (*fmt == '%') {
343          fmt++;
344 //       Dmsg1(000, "Got %% nxt=%c\n", *fmt);
345 switch_top:
346          switch (*fmt++) {
347          case 'u':
348          case 'd':
349             value = 0;
350             while (B_ISDIGIT(*buf)) {
351                value = B_TIMES10(value) + *buf++ - '0';
352             }
353             vp = (void *)va_arg(ap, void *);
354 //          Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
355             if (l == 0) {
356                *((int *)vp) = (int)value;
357             } else if (l == 1) {
358                *((uint32_t *)vp) = (uint32_t)value;
359 //             Dmsg0(000, "Store 32 bit int\n");
360             } else {
361                *((uint64_t *)vp) = (uint64_t)value;
362 //             Dmsg0(000, "Store 64 bit int\n");
363             }
364             count++;
365             l = 0;
366             break;
367          case 'l':
368 //          Dmsg0(000, "got l\n");
369             l = 1;
370             if (*fmt == 'l') {
371                l++;
372                fmt++;
373             }
374             if (*fmt == 'd' || *fmt == 'u') {
375                goto switch_top;
376             }
377 //          Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
378             error = true;
379             break;
380          case 'q':
381             l = 2;
382             if (*fmt == 'd' || *fmt == 'u') {
383                goto switch_top;
384             }
385 //          Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
386             error = true;
387             break;
388          case 's':
389 //          Dmsg1(000, "Store string max_len=%d\n", max_len);
390             cp = (char *)va_arg(ap, char *);
391             while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
392                *cp++ = *buf++;
393             }
394             *cp = 0;
395             count++;
396             max_len = BIG;
397             break;
398          case 'c':
399             cp = (char *)va_arg(ap, char *);
400             *cp = *buf++;
401             count++;
402             break;
403          case '%':
404             if (*buf++ != '%') {
405                error = true;
406             }
407             break;
408          default:
409             fmt--;
410             max_len = 0;
411             while (B_ISDIGIT(*fmt)) {
412                max_len = B_TIMES10(max_len) + *fmt++ - '0';
413             }
414 //          Dmsg1(000, "Default max_len=%d\n", max_len);
415             if (*fmt == 's') {
416                goto switch_top;
417             }
418 //          Dmsg1(000, "Default c=%c\n", *fmt);
419             error = true;
420             break;                    /* error: unknown format */
421          }
422          continue;
423
424       /* White space eats zero or more whitespace */
425       } else if (B_ISSPACE(*fmt)) {
426          fmt++;
427          while (B_ISSPACE(*buf)) {
428             buf++;
429          }
430       /* Plain text must match */
431       } else if (*buf++ != *fmt++) {
432 //       Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
433          error = true;
434          break;
435       }
436    }
437    va_end(ap);
438 // Dmsg2(000, "Error=%d count=%d\n", error, count);
439    if (error) {
440       count = -1;
441    }
442    return count;
443 }
444
445 #ifdef TEST_PROGRAM
446 int main(int argc, char *argv[])
447 {
448    char buf[100];
449    uint32_t val32;
450    uint64_t val64;
451    uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
452    char Job[200];
453    int cnt;
454    char *helloreq= "Hello *UserAgent* calling\n";
455    char *hello = "Hello %127s calling\n";
456    char *catreq =
457 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
458 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
459   "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
460   "StartBlock=%u EndBlock=%u\n";
461 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
462    " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
463    " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
464    " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
465    " VolReadTime=%" lld " VolWriteTime=%" lld;
466    char *media =
467 "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";
468 struct VOLUME_CAT_INFO {
469    /* Media info for the current Volume */
470    uint32_t VolCatJobs;               /* number of jobs on this Volume */
471    uint32_t VolCatFiles;              /* Number of files */
472    uint32_t VolCatBlocks;             /* Number of blocks */
473    uint64_t VolCatBytes;              /* Number of bytes written */
474    uint32_t VolCatMounts;             /* Number of mounts this volume */
475    uint32_t VolCatErrors;             /* Number of errors this volume */
476    uint32_t VolCatWrites;             /* Number of writes this volume */
477    uint32_t VolCatReads;              /* Number of reads this volume */
478    uint64_t VolCatRBytes;             /* Number of bytes read */
479    uint32_t VolCatRecycles;           /* Number of recycles this volume */
480    int32_t  Slot;                     /* Slot in changer */
481    bool     InChanger;                /* Set if vol in current magazine */
482    uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
483    uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
484    uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
485    uint64_t VolCatCapacityBytes;      /* capacity estimate */
486    uint64_t VolReadTime;              /* time spent reading */
487    uint64_t VolWriteTime;             /* time spent writing this Volume */
488    char VolCatStatus[20];             /* Volume status */
489    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
490 };
491    struct VOLUME_CAT_INFO vol;
492
493 #ifdef xxx
494    bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
495    printf("%s %d %lld\n", buf, val32, val64);
496
497    *Job=0;
498    cnt = bsscanf(catreq, Create_job_media, &Job,
499       &FirstIndex, &LastIndex, &StartFile, &EndFile,
500       &StartBlock, &EndBlock);
501    printf("cnt=%d Job=%s\n", cnt, Job);
502    cnt = bsscanf(helloreq, hello, &Job);
503    printf("cnt=%d Agent=%s\n", cnt, Job);
504 #endif
505    cnt = bsscanf(media, OK_media,
506                vol.VolCatName,
507                &vol.VolCatJobs, &vol.VolCatFiles,
508                &vol.VolCatBlocks, &vol.VolCatBytes,
509                &vol.VolCatMounts, &vol.VolCatErrors,
510                &vol.VolCatWrites, &vol.VolCatMaxBytes,
511                &vol.VolCatCapacityBytes, vol.VolCatStatus,
512                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
513                &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
514    printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);
515
516 }
517
518 #endif