2 * scan.c -- scanning routines for Bacula
4 * Kern Sibbald, MM separated from util.c MMIII
10 Copyright (C) 2000-2004 Kern Sibbald and John Walker
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of
15 the License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public
23 License along with this program; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31 #include "findlib/find.h"
34 /* Strip any trailing junk from the command */
35 void strip_trailing_junk(char *cmd)
38 p = cmd + strlen(cmd) - 1;
40 /* strip trailing junk from command */
41 while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
45 /* Strip any trailing slashes from a directory path */
46 void strip_trailing_slashes(char *dir)
49 p = dir + strlen(dir) - 1;
51 /* strip trailing slashes */
52 while ((p >= dir) && (*p == '/'))
58 * Returns: 0 on failure (EOF)
60 * new address in passed parameter
62 bool skip_spaces(char **msg)
68 while (*p && B_ISSPACE(*p)) {
72 return *p ? true : false;
77 * Returns: 0 on failure (EOF)
79 * new address in passed parameter
81 bool skip_nonspaces(char **msg)
88 while (*p && !B_ISSPACE(*p)) {
92 return *p ? true : false;
95 /* folded search for string - case insensitive */
97 fstrsch(const char *a, const char *b) /* folded case search */
104 while (*s1) { /* do it the fast way */
105 if ((*s1++ | 0x20) != (*s2++ | 0x20))
106 return 0; /* failed */
108 while (*a) { /* do it over the correct slow way */
109 if (B_ISUPPER(c1 = *a)) {
110 c1 = tolower((int)c1);
112 if (B_ISUPPER(c2 = *b)) {
113 c2 = tolower((int)c2);
126 * Return next argument from command line. Note, this
127 * routine is destructive.
129 char *next_arg(char **s)
132 bool in_quote = false;
134 /* skip past spaces to next arg */
135 for (p=*s; *p && B_ISSPACE(*p); ) {
138 Dmsg1(400, "Next arg=%s\n", p);
139 for (n = q = p; *p ; ) {
149 if (*p == '"') { /* start or end of quote */
151 p++; /* skip quote */
159 if (!in_quote && B_ISSPACE(*p)) { /* end of field */
167 Dmsg2(400, "End arg=%s next=%s\n", n, p);
172 * This routine parses the input command line.
173 * It makes a copy in args, then builds an
174 * argc, argv like list where
176 * argc = count of arguments
177 * argk[i] = argument keyword (part preceding =)
178 * argv[i] = argument value (part after =)
180 * example: arg1 arg2=abc arg3=
191 int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
192 char **argk, char **argv, int max_args)
196 pm_strcpy(args, cmd);
197 strip_trailing_junk(*args);
200 /* Pick up all arguments */
201 while (*argc < max_args) {
205 argv[(*argc)++] = NULL;
210 /* Separate keyword and value */
211 for (int i=0; i < *argc; i++) {
212 p = strchr(argk[i], '=');
214 *p++ = 0; /* terminate keyword and point to value */
215 /* Unquote quoted values */
217 for (n = q = ++p; *p && *p != '"'; ) {
223 *q = 0; /* terminate string */
224 p = n; /* point to string */
226 if (strlen(p) > MAX_NAME_LENGTH-1) {
227 p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */
230 argv[i] = p; /* save ptr to value or NULL */
233 for (int i=0; i < *argc; i++) {
234 Pmsg3(000, "Arg %d: kw=%s val=%s\n", i, argk[i], argv[i]?argv[i]:"NULL");
241 * Given a full filename, split it into its path
242 * and filename parts. They are returned in pool memory
243 * in the arguments provided.
245 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
246 POOLMEM **file, int *fnl)
250 int len = slen = strlen(fname);
253 * Find path without the filename.
254 * I.e. everything after the last / is a "filename".
255 * OK, maybe it is a directory name, but we treat it like
256 * a filename. If we don't find a / then the whole name
257 * must be a path name (e.g. c:).
261 /* "strip" any trailing slashes */
262 while (slen > 1 && *f == '/') {
266 /* Walk back to last slash -- begin of filename */
267 while (slen > 0 && *f != '/') {
271 if (*f == '/') { /* did we find a slash? */
272 f++; /* yes, point to filename */
273 } else { /* no, whole thing must be path name */
276 Dmsg2(200, "after strip len=%d f=%s\n", len, f);
277 *fnl = fname - f + len;
279 *file = check_pool_memory_size(*file, *fnl+1);
280 memcpy(*file, f, *fnl); /* copy filename */
286 *path = check_pool_memory_size(*path, *pnl+1);
287 memcpy(*path, fname, *pnl);
291 Dmsg2(200, "pnl=%d fnl=%d\n", *pnl, *fnl);
292 Dmsg3(200, "split fname=%s path=%s file=%s\n", fname, *path, *file);
296 * Extremely simple sscanf. Handles only %(u,d,ld,lu,lld,llu,c,nns)
298 const int BIG = 1000;
299 int bsscanf(const char *buf, const char *fmt, ...)
311 while (*fmt && !error) {
312 // Dmsg1(000, "fmt=%c\n", *fmt);
315 // Dmsg1(000, "Got %% nxt=%c\n", *fmt);
321 while (B_ISDIGIT(*buf)) {
322 value = B_TIMES10(value) + *buf++ - '0';
324 vp = (void *)va_arg(ap, void *);
325 // Dmsg2(000, "val=%lld at 0x%lx\n", value, (long unsigned)vp);
327 *((uint32_t *)vp) = (uint32_t)value;
328 // Dmsg0(000, "Store 32 bit int\n");
330 *((uint64_t *)vp) = (uint64_t)value;
331 // Dmsg0(000, "Store 64 bit int\n");
337 // Dmsg0(000, "got l\n");
343 if (*fmt == 'd' || *fmt == 'u') {
346 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
351 if (*fmt == 'd' || *fmt == 'u') {
354 // Dmsg1(000, "fmt=%c !=d,u\n", *fmt);
358 // Dmsg1(000, "Store string max_len=%d\n", max_len);
359 cp = (char *)va_arg(ap, char *);
360 while (*buf && !B_ISSPACE(*buf) && max_len-- > 0) {
368 cp = (char *)va_arg(ap, char *);
380 while (B_ISDIGIT(*fmt)) {
381 max_len = B_TIMES10(max_len) + *fmt++ - '0';
383 // Dmsg1(000, "Default max_len=%d\n", max_len);
387 // Dmsg1(000, "Default c=%c\n", *fmt);
389 break; /* error: unknown format */
393 /* White space eats zero or more whitespace */
394 } else if (B_ISSPACE(*fmt)) {
396 while (B_ISSPACE(*buf)) {
399 /* Plain text must match */
400 } else if (*buf++ != *fmt++) {
401 // Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
406 // Dmsg2(000, "Error=%d count=%d\n", error, count);
414 int main(int argc, char *argv[])
419 uint32_t FirstIndex, LastIndex, StartFile, EndFile, StartBlock, EndBlock;
422 char *helloreq= "Hello *UserAgent* calling\n";
423 char *hello = "Hello %127s calling\n";
425 "CatReq Job=NightlySave.2004-06-11_19.11.32 CreateJobMedia FirstIndex=1 LastIndex=114 StartFile=0 EndFile=0 StartBlock=208 EndBlock=2903248";
426 static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
427 "FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
428 "StartBlock=%u EndBlock=%u\n";
429 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
430 " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
431 " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
432 " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
433 " VolReadTime=%" lld " VolWriteTime=%" lld;
435 "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";
436 struct VOLUME_CAT_INFO {
437 /* Media info for the current Volume */
438 uint32_t VolCatJobs; /* number of jobs on this Volume */
439 uint32_t VolCatFiles; /* Number of files */
440 uint32_t VolCatBlocks; /* Number of blocks */
441 uint64_t VolCatBytes; /* Number of bytes written */
442 uint32_t VolCatMounts; /* Number of mounts this volume */
443 uint32_t VolCatErrors; /* Number of errors this volume */
444 uint32_t VolCatWrites; /* Number of writes this volume */
445 uint32_t VolCatReads; /* Number of reads this volume */
446 uint64_t VolCatRBytes; /* Number of bytes read */
447 uint32_t VolCatRecycles; /* Number of recycles this volume */
448 int32_t Slot; /* Slot in changer */
449 bool InChanger; /* Set if vol in current magazine */
450 uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
451 uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
452 uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
453 uint64_t VolCatCapacityBytes; /* capacity estimate */
454 uint64_t VolReadTime; /* time spent reading */
455 uint64_t VolWriteTime; /* time spent writing this Volume */
456 char VolCatStatus[20]; /* Volume status */
457 char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
459 struct VOLUME_CAT_INFO vol;
462 bsscanf("Hello_world 123 1234", "%120s %ld %lld", buf, &val32, &val64);
463 printf("%s %d %lld\n", buf, val32, val64);
466 cnt = bsscanf(catreq, Create_job_media, &Job,
467 &FirstIndex, &LastIndex, &StartFile, &EndFile,
468 &StartBlock, &EndBlock);
469 printf("cnt=%d Job=%s\n", cnt, Job);
470 cnt = bsscanf(helloreq, hello, &Job);
471 printf("cnt=%d Agent=%s\n", cnt, Job);
473 cnt = bsscanf(media, OK_media,
475 &vol.VolCatJobs, &vol.VolCatFiles,
476 &vol.VolCatBlocks, &vol.VolCatBytes,
477 &vol.VolCatMounts, &vol.VolCatErrors,
478 &vol.VolCatWrites, &vol.VolCatMaxBytes,
479 &vol.VolCatCapacityBytes, vol.VolCatStatus,
480 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
481 &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime);
482 printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName);