2 * scan.c -- scanning routines for Bacula
4 * Kern Sibbald, MM separated from util.c MMIII
9 Copyright (C) 2000-2005 Kern Sibbald
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 version 2 as amended with additional clauses defined in the
14 file LICENSE in the main source directory.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 the file LICENSE for additional details.
26 #include "findlib/find.h"
28 /* Strip leading space from command line arguments */
29 void strip_leading_space(char *str)
32 while (B_ISSPACE(*p)) {
41 /* Strip any trailing junk from the command */
42 void strip_trailing_junk(char *cmd)
45 p = cmd + strlen(cmd) - 1;
47 /* strip trailing junk from command */
48 while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
52 /* Strip any trailing slashes from a directory path */
53 void strip_trailing_slashes(char *dir)
56 p = dir + strlen(dir) - 1;
58 /* strip trailing slashes */
59 while ((p >= dir) && (*p == '/'))
65 * Returns: 0 on failure (EOF)
67 * new address in passed parameter
69 bool skip_spaces(char **msg)
75 while (*p && B_ISSPACE(*p)) {
79 return *p ? true : false;
84 * Returns: 0 on failure (EOF)
86 * new address in passed parameter
88 bool skip_nonspaces(char **msg)
95 while (*p && !B_ISSPACE(*p)) {
99 return *p ? true : false;
102 /* folded search for string - case insensitive */
104 fstrsch(const char *a, const char *b) /* folded case search */
111 while (*s1) { /* do it the fast way */
112 if ((*s1++ | 0x20) != (*s2++ | 0x20))
113 return 0; /* failed */
115 while (*a) { /* do it over the correct slow way */
116 if (B_ISUPPER(c1 = *a)) {
117 c1 = tolower((int)c1);
119 if (B_ISUPPER(c2 = *b)) {
120 c2 = tolower((int)c2);
133 * Return next argument from command line. Note, this
134 * routine is destructive.
136 char *next_arg(char **s)
139 bool in_quote = false;
141 /* skip past spaces to next arg */
142 for (p=*s; *p && B_ISSPACE(*p); ) {
145 Dmsg1(900, "Next arg=%s\n", p);
146 for (n = q = p; *p ; ) {
156 if (*p == '"') { /* start or end of quote */
158 p++; /* skip quote */
166 if (!in_quote && B_ISSPACE(*p)) { /* end of field */
174 Dmsg2(900, "End arg=%s next=%s\n", n, p);
179 * This routine parses the input command line.
180 * It makes a copy in args, then builds an
181 * argc, argv like list where
183 * argc = count of arguments
184 * argk[i] = argument keyword (part preceding =)
185 * argv[i] = argument value (part after =)
187 * example: arg1 arg2=abc arg3=
198 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
199 char **argk, char **argv, int max_args)
203 pm_strcpy(args, cmd);
204 strip_trailing_junk(*args);
207 /* Pick up all arguments */
208 while (*argc < max_args) {
212 argv[(*argc)++] = NULL;
217 /* Separate keyword and value */
218 for (int i=0; i < *argc; i++) {
219 p = strchr(argk[i], '=');
221 *p++ = 0; /* terminate keyword and point to value */
222 /* Unquote quoted values */
224 for (n = q = ++p; *p && *p != '"'; ) {
230 *q = 0; /* terminate string */
231 p = n; /* point to string */
233 if (strlen(p) > MAX_NAME_LENGTH-1) {
234 p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */
237 argv[i] = p; /* save ptr to value or NULL */
240 for (int i=0; i < *argc; i++) {
241 Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
248 * Given a full filename, split it into its path
249 * and filename parts. They are returned in pool memory
250 * in the arguments provided.
252 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
253 POOLMEM **file, int *fnl)
257 int len = slen = strlen(fname);
260 * Find path without the filename.
261 * I.e. everything after the last / is a "filename".
262 * OK, maybe it is a directory name, but we treat it like
263 * a filename. If we don't find a / then the whole name
264 * must be a path name (e.g. c:).
267 /* "strip" any trailing slashes */
268 while (slen > 1 && *f == '/') {
272 /* Walk back to last slash -- begin of filename */
273 while (slen > 0 && *f != '/') {
277 if (*f == '/') { /* did we find a slash? */
278 f++; /* yes, point to filename */
279 } else { /* no, whole thing must be path name */
282 Dmsg2(200, "after strip len=%d f=%s\n", len, f);
283 *fnl = fname - f + len;
285 *file = check_pool_memory_size(*file, *fnl+1);
286 memcpy(*file, f, *fnl); /* copy filename */
292 *path = check_pool_memory_size(*path, *pnl+1);
293 memcpy(*path, fname, *pnl);
297 Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
298 Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
302 * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns)
304 const int BIG = 1000;
305 int bsscanf(const char *buf, const char *fmt, ...)
317 while (*fmt && !error) {
318 // Dmsg1(000, "fmt=%c\n", *fmt);
321 // Dmsg1(000, "Got %% nxt=%c\n", *fmt);
327 while (B_ISDIGIT(*buf)) {
328 value = B_TIMES10(value) + *buf++ - '0';
330 vp = (void *)va_arg(ap, void *);
331 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
333 *((uint32_t *)vp) = (uint32_t)value;
334 // Dmsg0(000, "Store 32 bit int\n");
336 *((uint64_t *)vp) = (uint64_t)value;
337 // Dmsg0(000, "Store 64 bit int\n");
343 // Dmsg0(000, "got l\n");
349 if (*fmt == 'd' || *fmt == 'u') {
352 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
357 if (*fmt == 'd' || *fmt == 'u') {
360 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
364 // Dmsg1(000, "Store string max_len=%d\n", max_len);
365 cp = (char *)va_arg(ap, char *);
366 while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
374 cp = (char *)va_arg(ap, char *);
386 while (B_ISDIGIT(*fmt)) {
387 max_len = B_TIMES10(max_len) + *fmt++ - '0';
389 // Dmsg1(000, "Default max_len=%d\n", max_len);
393 // Dmsg1(000, "Default c=%c\n", *fmt);
395 break; /* error: unknown format */
399 /* White space eats zero or more whitespace */
400 } else if (B_ISSPACE(*fmt)) {
402 while (B_ISSPACE(*buf)) {
405 /* Plain text must match */
406 } else if (*buf++ != *fmt++) {
407 // Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
413 // Dmsg2(000, "Error=%d count=%d\n", error, count);
421 int main(int argc, char *argv[])
426 uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
429 char *helloreq= "Hello *UserAgent* calling\n";
430 char *hello = "Hello %127s calling\n";
432 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
433 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
434 "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
435 "StartBlock=%u EndBlock=%u\n";
436 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
437 " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
438 " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
439 " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
440 " VolReadTime=%" lld " VolWriteTime=%" lld;
442 "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";
443 struct VOLUME_CAT_INFO {
444 /* Media info for the current Volume */
445 uint32_t VolCatJobs; /* number of jobs on this Volume */
446 uint32_t VolCatFiles; /* Number of files */
447 uint32_t VolCatBlocks; /* Number of blocks */
448 uint64_t VolCatBytes; /* Number of bytes written */
449 uint32_t VolCatMounts; /* Number of mounts this volume */
450 uint32_t VolCatErrors; /* Number of errors this volume */
451 uint32_t VolCatWrites; /* Number of writes this volume */
452 uint32_t VolCatReads; /* Number of reads this volume */
453 uint64_t VolCatRBytes; /* Number of bytes read */
454 uint32_t VolCatRecycles; /* Number of recycles this volume */
455 int32_t Slot; /* Slot in changer */
456 bool InChanger; /* Set if vol in current magazine */
457 uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
458 uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
459 uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
460 uint64_t VolCatCapacityBytes; /* capacity estimate */
461 uint64_t VolReadTime; /* time spent reading */
462 uint64_t VolWriteTime; /* time spent writing this Volume */
463 char VolCatStatus[20]; /* Volume status */
464 char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
466 struct VOLUME_CAT_INFO vol;
469 bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
470 printf("%s %d %lld\n", buf, val32, val64);
473 cnt = bsscanf(catreq, Create_job_media, &Job,
474 &FirstIndex, &LastIndex, &StartFile, &EndFile,
475 &StartBlock, &EndBlock);
476 printf("cnt=%d Job=%s\n", cnt, Job);
477 cnt = bsscanf(helloreq, hello, &Job);
478 printf("cnt=%d Agent=%s\n", cnt, Job);
480 cnt = bsscanf(media, OK_media,
482 &vol.VolCatJobs, &vol.VolCatFiles,
483 &vol.VolCatBlocks, &vol.VolCatBytes,
484 &vol.VolCatMounts, &vol.VolCatErrors,
485 &vol.VolCatWrites, &vol.VolCatMaxBytes,
486 &vol.VolCatCapacityBytes, vol.VolCatStatus,
487 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
488 &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
489 printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);