2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * scan.c -- scanning routines for Bacula
31 * Kern Sibbald, MM separated from util.c MMIII
37 #include "findlib/find.h"
40 * Strip leading space from command line arguments
42 void strip_leading_space(char *str)
46 while (B_ISSPACE(*p)) {
55 * Strip any trailing junk from the command
57 void strip_trailing_junk(char *cmd)
62 * Strip trailing junk from command
64 p = cmd + strlen(cmd) - 1;
65 while ((p >= cmd) && (*p == '\n' || *p == '\r' || B_ISSPACE(*p))) {
71 * Strip any trailing newline characters from the string
73 void strip_trailing_newline(char *cmd)
77 p = cmd + strlen(cmd) - 1;
78 while ((p >= cmd) && (*p == '\n' || *p == '\r')) {
84 * Strip any trailing slashes from a directory path
86 void strip_trailing_slashes(char *dir)
91 * Strip trailing slashes
93 p = dir + strlen(dir) - 1;
94 while (p >= dir && IsPathSeparator(*p)) {
101 * Returns: 0 on failure (EOF)
103 * new address in passed parameter
105 bool skip_spaces(char **msg)
111 while (*p && B_ISSPACE(*p)) {
115 return *p ? true : false;
120 * Returns: 0 on failure (EOF)
122 * new address in passed parameter
124 bool skip_nonspaces(char **msg)
131 while (*p && !B_ISSPACE(*p)) {
135 return *p ? true : false;
139 * Folded search for string - case insensitive
141 int fstrsch(const char *a, const char *b) /* folded case search */
148 while (*s1) { /* do it the fast way */
149 if ((*s1++ | 0x20) != (*s2++ | 0x20))
150 return 0; /* failed */
152 while (*a) { /* do it over the correct slow way */
153 if (B_ISUPPER(c1 = *a)) {
154 c1 = tolower((int)c1);
156 if (B_ISUPPER(c2 = *b)) {
157 c2 = tolower((int)c2);
169 * Return next argument from command line. Note, this
170 * routine is destructive because it stored 0 at the end
172 * Called with pointer to pointer to command line. This
173 * pointer is updated to point to the remainder of the
176 * Returns pointer to next argument -- don't store the result
177 * in the pointer you passed as an argument ...
178 * The next argument is terminated by a space unless within
179 * quotes. Double quote characters (unless preceded by a \) are
183 char *next_arg(char **s)
186 bool in_quote = false;
188 /* skip past spaces to next arg */
189 for (p=*s; *p && B_ISSPACE(*p); ) {
192 Dmsg1(900, "Next arg=%s\n", p);
193 for (n = q = p; *p ; ) {
194 if (*p == '\\') { /* slash? */
195 p++; /* yes, skip it */
203 if (*p == '"') { /* start or end of quote */
205 in_quote = !in_quote; /* change state */
208 if (!in_quote && B_ISSPACE(*p)) { /* end of field */
216 Dmsg2(900, "End arg=%s next=%s\n", n, p);
221 * This routine parses the input command line.
222 * It makes a copy in args, then builds an
223 * argc, argk, argv list where:
225 * argc = count of arguments
226 * argk[i] = argument keyword (part preceding =)
227 * argv[i] = argument value (part after =)
229 * example: arg1 arg2=abc arg3=
239 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
240 char **argk, char **argv, int max_args)
244 parse_args_only(cmd, args, argc, argk, argv, max_args);
246 /* Separate keyword and value */
247 for (int i=0; i < *argc; i++) {
248 p = strchr(argk[i], '=');
250 *p++ = 0; /* terminate keyword and point to value */
252 argv[i] = p; /* save ptr to value or NULL */
255 for (int i=0; i < *argc; i++) {
256 Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
264 * This routine parses the input command line.
265 * It makes a copy in args, then builds an
266 * argc, argk, but no argv (values).
267 * This routine is useful for scanning command lines where the data
268 * is a filename and no keywords are expected. If we scan a filename
269 * for keywords, any = in the filename will be interpreted as the
270 * end of a keyword, and this is not good.
272 * argc = count of arguments
273 * argk[i] = argument keyword (part preceding =)
276 * example: arg1 arg2=abc arg3=
286 int parse_args_only(POOLMEM *cmd, POOLMEM **args, int *argc,
287 char **argk, char **argv, int max_args)
291 pm_strcpy(args, cmd);
292 strip_trailing_junk(*args);
296 * Pick up all arguments
298 while (*argc < max_args) {
302 argv[(*argc)++] = NULL;
311 * Given a full filename, split it into its path
312 * and filename parts. They are returned in pool memory
313 * in the arguments provided.
315 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
316 POOLMEM **file, int *fnl)
320 int len = slen = strlen(fname);
323 * Find path without the filename.
324 * I.e. everything after the last / is a "filename".
325 * OK, maybe it is a directory name, but we treat it like
326 * a filename. If we don't find a / then the whole name
327 * must be a path name (e.g. c:).
330 /* "strip" any trailing slashes */
331 while (slen > 1 && IsPathSeparator(*f)) {
335 /* Walk back to last slash -- begin of filename */
336 while (slen > 0 && !IsPathSeparator(*f)) {
340 if (IsPathSeparator(*f)) { /* did we find a slash? */
341 f++; /* yes, point to filename */
342 } else { /* no, whole thing must be path name */
345 Dmsg2(200, "after strip len=%d f=%s\n", len, f);
346 *fnl = fname - f + len;
348 *file = check_pool_memory_size(*file, *fnl+1);
349 memcpy(*file, f, *fnl); /* copy filename */
355 *path = check_pool_memory_size(*path, *pnl+1);
356 memcpy(*path, fname, *pnl);
360 Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
361 Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
365 * Extremely simple sscanf. Handles only %(u,d,ld,qd,qu,lu,lld,llu,c,nns)
367 const int BIG = 1000;
368 int bsscanf(const char *buf, const char *fmt, ...)
381 while (*fmt && !error) {
382 // Dmsg1(000, "fmt=%c\n", *fmt);
385 // Dmsg1(000, "Got %% nxt=%c\n", *fmt);
390 while (B_ISDIGIT(*buf)) {
391 value = B_TIMES10(value) + *buf++ - '0';
393 vp = (void *)va_arg(ap, void *);
394 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
396 *((int *)vp) = (int)value;
398 *((uint32_t *)vp) = (uint32_t)value;
399 // Dmsg0(000, "Store 32 bit int\n");
401 *((uint64_t *)vp) = (uint64_t)value;
402 // Dmsg0(000, "Store 64 bit int\n");
415 while (B_ISDIGIT(*buf)) {
416 value = B_TIMES10(value) + *buf++ - '0';
421 vp = (void *)va_arg(ap, void *);
422 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
424 *((int *)vp) = (int)value;
426 *((int32_t *)vp) = (int32_t)value;
427 // Dmsg0(000, "Store 32 bit int\n");
429 *((int64_t *)vp) = (int64_t)value;
430 // Dmsg0(000, "Store 64 bit int\n");
436 // Dmsg0(000, "got l\n");
442 if (*fmt == 'd' || *fmt == 'u') {
445 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
450 if (*fmt == 'd' || *fmt == 'u') {
453 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
457 // Dmsg1(000, "Store string max_len=%d\n", max_len);
458 cp = (char *)va_arg(ap, char *);
459 while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
467 cp = (char *)va_arg(ap, char *);
479 while (B_ISDIGIT(*fmt)) {
480 max_len = B_TIMES10(max_len) + *fmt++ - '0';
482 // Dmsg1(000, "Default max_len=%d\n", max_len);
486 // Dmsg1(000, "Default c=%c\n", *fmt);
488 break; /* error: unknown format */
492 /* White space eats zero or more whitespace */
493 } else if (B_ISSPACE(*fmt)) {
495 while (B_ISSPACE(*buf)) {
498 /* Plain text must match */
499 } else if (*buf++ != *fmt++) {
500 // Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
506 // Dmsg2(000, "Error=%d count=%d\n", error, count);
514 int main(int argc, char *argv[])
519 uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
522 char *helloreq= "Hello *UserAgent* calling\n";
523 char *hello = "Hello %127s calling\n";
525 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
526 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
527 "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
528 "StartBlock=%u EndBlock=%u\n";
529 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
530 " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
531 " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
532 " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
533 " VolReadTime=%" lld " VolWriteTime=%" lld;
535 "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";
536 struct VOLUME_CAT_INFO {
537 /* Media info for the current Volume */
538 uint32_t VolCatJobs; /* number of jobs on this Volume */
539 uint32_t VolCatFiles; /* Number of files */
540 uint32_t VolCatBlocks; /* Number of blocks */
541 uint64_t VolCatBytes; /* Number of bytes written */
542 uint32_t VolCatMounts; /* Number of mounts this volume */
543 uint32_t VolCatErrors; /* Number of errors this volume */
544 uint32_t VolCatWrites; /* Number of writes this volume */
545 uint32_t VolCatReads; /* Number of reads this volume */
546 uint64_t VolCatRBytes; /* Number of bytes read */
547 uint32_t VolCatRecycles; /* Number of recycles this volume */
548 int32_t Slot; /* Slot in changer */
549 bool InChanger; /* Set if vol in current magazine */
550 uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
551 uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
552 uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
553 uint64_t VolCatCapacityBytes; /* capacity estimate */
554 uint64_t VolReadTime; /* time spent reading */
555 uint64_t VolWriteTime; /* time spent writing this Volume */
556 char VolCatStatus[20]; /* Volume status */
557 char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
559 struct VOLUME_CAT_INFO vol;
562 bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
563 printf("%s %d %lld\n", buf, val32, val64);
566 cnt = bsscanf(catreq, Create_job_media, &Job,
567 &FirstIndex, &LastIndex, &StartFile, &EndFile,
568 &StartBlock, &EndBlock);
569 printf("cnt=%d Job=%s\n", cnt, Job);
570 cnt = bsscanf(helloreq, hello, &Job);
571 printf("cnt=%d Agent=%s\n", cnt, Job);
573 cnt = bsscanf(media, OK_media,
575 &vol.VolCatJobs, &vol.VolCatFiles,
576 &vol.VolCatBlocks, &vol.VolCatBytes,
577 &vol.VolCatMounts, &vol.VolCatErrors,
578 &vol.VolCatWrites, &vol.VolCatMaxBytes,
579 &vol.VolCatCapacityBytes, vol.VolCatStatus,
580 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
581 &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
582 printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);