2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * scan.c -- scanning routines for Bacula
23 * Kern Sibbald, MM separated from util.c MMIII
30 #include "findlib/find.h"
32 /* Strip leading space from command line arguments */
33 void strip_leading_space(char *str)
36 while (B_ISSPACE(*p)) {
45 /* Strip any trailing junk from the command */
46 void strip_trailing_junk(char *cmd)
50 /* strip trailing junk from command */
51 p = cmd - 1 + strlen(cmd);
52 while ((p >= cmd) && (B_ISSPACE(*p) || *p == '\n' || *p == '\r')) {
57 /* Strip any trailing newline characters from the string */
58 void strip_trailing_newline(char *cmd)
61 p = cmd - 1 + strlen(cmd);
62 while ((p >= cmd) && (*p == '\n' || *p == '\r')) *p-- = 0;
65 /* Strip any trailing slashes from a directory path */
66 void strip_trailing_slashes(char *dir)
70 /* strip trailing slashes */
71 p = dir -1 + strlen(dir);
72 while (p >= dir && IsPathSeparator(*p)) *p-- = 0;
77 * Returns: 0 on failure (EOF)
79 * new address in passed parameter
81 bool skip_spaces(char **msg)
87 while (*p && B_ISSPACE(*p)) {
91 return *p ? true : false;
96 * Returns: 0 on failure (EOF)
98 * new address in passed parameter
100 bool skip_nonspaces(char **msg)
107 while (*p && !B_ISSPACE(*p)) {
111 return *p ? true : false;
114 /* folded search for string - case insensitive */
116 fstrsch(const char *a, const char *b) /* folded case search */
123 while (*s1) { /* do it the fast way */
124 if ((*s1++ | 0x20) != (*s2++ | 0x20))
125 return 0; /* failed */
127 while (*a) { /* do it over the correct slow way */
128 if (B_ISUPPER(c1 = *a)) {
129 c1 = tolower((int)c1);
131 if (B_ISUPPER(c2 = *b)) {
132 c2 = tolower((int)c2);
145 * Return next argument from command line. Note, this
146 * routine is destructive because it stored 0 at the end
148 * Called with pointer to pointer to command line. This
149 * pointer is updated to point to the remainder of the
152 * Returns pointer to next argument -- don't store the result
153 * in the pointer you passed as an argument ...
154 * The next argument is terminated by a space unless within
155 * quotes. Double quote characters (unless preceded by a \) are
159 char *next_arg(char **s)
162 bool in_quote = false;
164 /* skip past spaces to next arg */
165 for (p=*s; *p && B_ISSPACE(*p); ) {
168 Dmsg1(900, "Next arg=%s\n", p);
169 for (n = q = p; *p ; ) {
170 if (*p == '\\') { /* slash? */
171 p++; /* yes, skip it */
179 if (*p == '"') { /* start or end of quote */
181 in_quote = !in_quote; /* change state */
184 if (!in_quote && B_ISSPACE(*p)) { /* end of field */
192 Dmsg2(900, "End arg=%s next=%s\n", n, p);
197 * This routine parses the input command line.
198 * It makes a copy in args, then builds an
199 * argc, argk, argv list where:
201 * argc = count of arguments
202 * argk[i] = argument keyword (part preceding =)
203 * argv[i] = argument value (part after =)
205 * example: arg1 arg2=abc arg3=
215 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
216 char **argk, char **argv, int max_args)
220 parse_args_only(cmd, args, argc, argk, argv, max_args);
222 /* Separate keyword and value */
223 for (int i=0; i < *argc; i++) {
224 p = strchr(argk[i], '=');
226 *p++ = 0; /* terminate keyword and point to value */
228 argv[i] = p; /* save ptr to value or NULL */
231 for (int i=0; i < *argc; i++) {
232 Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
240 * This routine parses the input command line.
241 * It makes a copy in args, then builds an
242 * argc, argk, but no argv (values).
243 * This routine is useful for scanning command lines where the data
244 * is a filename and no keywords are expected. If we scan a filename
245 * for keywords, any = in the filename will be interpreted as the
246 * end of a keyword, and this is not good.
248 * argc = count of arguments
249 * argk[i] = argument keyword (part preceding =)
252 * example: arg1 arg2=abc arg3=
262 int parse_args_only(POOLMEM *cmd, POOLMEM **args, int *argc,
263 char **argk, char **argv, int max_args)
267 pm_strcpy(args, cmd);
268 strip_trailing_junk(*args);
271 /* Pick up all arguments */
272 while (*argc < max_args) {
276 argv[(*argc)++] = NULL;
286 * Given a full filename, split it into its path
287 * and filename parts. They are returned in pool memory
288 * in the arguments provided.
290 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
291 POOLMEM **file, int *fnl)
295 int len = slen = strlen(fname);
298 * Find path without the filename.
299 * I.e. everything after the last / is a "filename".
300 * OK, maybe it is a directory name, but we treat it like
301 * a filename. If we don't find a / then the whole name
302 * must be a path name (e.g. c:).
305 /* "strip" any trailing slashes */
306 while (slen > 1 && IsPathSeparator(*f)) {
310 /* Walk back to last slash -- begin of filename */
311 while (slen > 0 && !IsPathSeparator(*f)) {
315 if (IsPathSeparator(*f)) { /* did we find a slash? */
316 f++; /* yes, point to filename */
317 } else { /* no, whole thing must be path name */
320 Dmsg2(200, "after strip len=%d f=%s\n", len, f);
321 *fnl = fname - f + len;
323 *file = check_pool_memory_size(*file, *fnl+1);
324 memcpy(*file, f, *fnl); /* copy filename */
330 *path = check_pool_memory_size(*path, *pnl+1);
331 memcpy(*path, fname, *pnl);
335 Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
336 Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
340 * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns)
342 * Note, BIG is the default maximum length when no length
343 * has been specified for %s. If it is not big enough, then
344 * simply add a length such as %10000s.
346 const int BIG = 1000;
347 int bsscanf(const char *buf, const char *fmt, ...)
360 while (*fmt && !error) {
361 // Dmsg1(000, "fmt=%c\n", *fmt);
364 // Dmsg1(000, "Got %% nxt=%c\n", *fmt);
369 while (B_ISDIGIT(*buf)) {
370 value = B_TIMES10(value) + *buf++ - '0';
372 vp = (void *)va_arg(ap, void *);
373 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
375 *((int *)vp) = (int)value;
377 *((uint32_t *)vp) = (uint32_t)value;
378 // Dmsg0(000, "Store 32 bit int\n");
380 *((uint64_t *)vp) = (uint64_t)value;
381 // Dmsg0(000, "Store 64 bit int\n");
394 while (B_ISDIGIT(*buf)) {
395 value = B_TIMES10(value) + *buf++ - '0';
400 vp = (void *)va_arg(ap, void *);
401 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
403 *((int *)vp) = (int)value;
405 *((int32_t *)vp) = (int32_t)value;
406 // Dmsg0(000, "Store 32 bit int\n");
408 *((int64_t *)vp) = (int64_t)value;
409 // Dmsg0(000, "Store 64 bit int\n");
415 // Dmsg0(000, "got l\n");
421 if (*fmt == 'd' || *fmt == 'u') {
424 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
429 if (*fmt == 'd' || *fmt == 'u') {
432 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
436 // Dmsg1(000, "Store string max_len=%d\n", max_len);
437 cp = (char *)va_arg(ap, char *);
438 while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
446 cp = (char *)va_arg(ap, char *);
458 while (B_ISDIGIT(*fmt)) {
459 max_len = B_TIMES10(max_len) + *fmt++ - '0';
461 // Dmsg1(000, "Default max_len=%d\n", max_len);
465 // Dmsg1(000, "Default c=%c\n", *fmt);
467 break; /* error: unknown format */
471 /* White space eats zero or more whitespace */
472 } else if (B_ISSPACE(*fmt)) {
474 while (B_ISSPACE(*buf)) {
477 /* Plain text must match */
478 } else if (*buf++ != *fmt++) {
479 // Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
485 // Dmsg2(000, "Error=%d count=%d\n", error, count);
493 int main(int argc, char *argv[])
498 uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
501 char *helloreq= "Hello *UserAgent* calling\n";
502 char *hello = "Hello %127s calling\n";
504 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
505 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
506 "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
507 "StartBlock=%u EndBlock=%u\n";
508 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
509 " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
510 " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
511 " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
512 " VolReadTime=%" lld " VolWriteTime=%" lld;
514 "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";
515 struct VOLUME_CAT_INFO {
516 /* Media info for the current Volume */
517 uint32_t VolCatJobs; /* number of jobs on this Volume */
518 uint32_t VolCatFiles; /* Number of files */
519 uint32_t VolCatBlocks; /* Number of blocks */
520 uint64_t VolCatBytes; /* Number of bytes written */
521 uint32_t VolCatMounts; /* Number of mounts this volume */
522 uint32_t VolCatErrors; /* Number of errors this volume */
523 uint32_t VolCatWrites; /* Number of writes this volume */
524 uint32_t VolCatReads; /* Number of reads this volume */
525 uint64_t VolCatRBytes; /* Number of bytes read */
526 uint32_t VolCatRecycles; /* Number of recycles this volume */
527 int32_t Slot; /* Slot in changer */
528 bool InChanger; /* Set if vol in current magazine */
529 uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
530 uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
531 uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
532 uint64_t VolCatCapacityBytes; /* capacity estimate */
533 uint64_t VolReadTime; /* time spent reading */
534 uint64_t VolWriteTime; /* time spent writing this Volume */
535 char VolCatStatus[20]; /* Volume status */
536 char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
538 struct VOLUME_CAT_INFO vol;
541 bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
542 printf("%s %d %lld\n", buf, val32, val64);
545 cnt = bsscanf(catreq, Create_job_media, &Job,
546 &FirstIndex, &LastIndex, &StartFile, &EndFile,
547 &StartBlock, &EndBlock);
548 printf("cnt=%d Job=%s\n", cnt, Job);
549 cnt = bsscanf(helloreq, hello, &Job);
550 printf("cnt=%d Agent=%s\n", cnt, Job);
552 cnt = bsscanf(media, OK_media,
554 &vol.VolCatJobs, &vol.VolCatFiles,
555 &vol.VolCatBlocks, &vol.VolCatBytes,
556 &vol.VolCatMounts, &vol.VolCatErrors,
557 &vol.VolCatWrites, &vol.VolCatMaxBytes,
558 &vol.VolCatCapacityBytes, vol.VolCatStatus,
559 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
560 &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
561 printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);