2 * util.c miscellaneous utility subroutines for Bacula
9 Copyright (C) 2000-2006 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.
25 #include "findlib/find.h"
28 * Various Bacula Utility subroutines
32 /* Return true of buffer has all zero bytes */
33 int is_buf_zero(char *buf, int len)
37 int i, len64, done, rem;
43 /* Optimize by checking uint64_t for zero */
44 len64 = len / sizeof(uint64_t);
45 for (i=0; i < len64; i++) {
50 done = len64 * sizeof(uint64_t); /* bytes already checked */
53 for (i = 0; i < rem; i++) {
62 /* Convert a string in place to lower case */
67 *str = tolower((int)(*str));
72 /* Convert spaces to non-space character.
73 * This makes scanf of fields containing spaces easier.
76 bash_spaces(char *str)
85 /* Convert spaces to non-space character.
86 * This makes scanf of fields containing spaces easier.
89 bash_spaces(POOL_MEM &pm)
91 char *str = pm.c_str();
100 /* Convert non-space characters (0x1) back into spaces */
102 unbash_spaces(char *str)
111 /* Convert non-space characters (0x1) back into spaces */
113 unbash_spaces(POOL_MEM &pm)
115 char *str = pm.c_str();
123 #if HAVE_WIN32 && !HAVE_CONSOLE && !HAVE_WXCONSOLE
124 extern long _timezone;
125 extern int _daylight;
126 extern long _dstbias;
127 extern "C" void __tzset(void);
128 extern "C" int _isindst(struct tm *);
131 char *encode_time(time_t time, char *buf)
136 #if HAVE_WIN32 && !HAVE_CONSOLE && !HAVE_WXCONSOLE
138 * Gross kludge to avoid a seg fault in Microsoft's CRT localtime_r(),
139 * which incorrectly references a NULL returned from gmtime() if
140 * the time (adjusted for the current timezone) is invalid.
141 * This could happen if you have a bad date/time, or perhaps if you
142 * moved a file from one timezone to another?
147 gtime = time - _timezone;
148 if (!(gtm = gmtime(>ime))) {
151 if (_daylight && _isindst(gtm)) {
153 if (!gmtime(>ime)) {
158 if (localtime_r(&time, &tm)) {
159 n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
160 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
161 tm.tm_hour, tm.tm_min, tm.tm_sec);
169 * Convert a JobStatus code into a human readable form
171 void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
178 jobstat = _("Created");
181 jobstat = _("Running");
184 jobstat = _("Blocked");
190 case JS_ErrorTerminated:
191 jobstat = _("Error");
194 jobstat = _("Non-fatal error");
197 jobstat = _("Canceled");
200 jobstat = _("Verify differences");
203 jobstat = _("Waiting on FD");
206 jobstat = _("Wait on SD");
209 jobstat = _("Wait for new Volume");
212 jobstat = _("Waiting for mount");
214 case JS_WaitStoreRes:
215 jobstat = _("Waiting for Storage resource");
218 jobstat = _("Waiting for Job resource");
220 case JS_WaitClientRes:
221 jobstat = _("Waiting for Client resource");
224 jobstat = _("Waiting on Max Jobs");
226 case JS_WaitStartTime:
227 jobstat = _("Waiting for Start Time");
229 case JS_WaitPriority:
230 jobstat = _("Waiting on Priority");
234 if (JobStatus == 0) {
237 bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
242 bstrncpy(msg, jobstat, maxlen);
246 * Convert Job Termination Status into a string
248 const char *job_status_to_str(int stat)
256 case JS_ErrorTerminated:
261 str = _("Fatal Error");
267 str = _("Differences");
270 str = _("Unknown term code");
278 * Convert Job Type into a string
280 const char *job_type_to_str(int type)
304 str = _("Unknown Type");
311 * Convert Job Level into a string
313 const char *job_level_to_str(int level)
324 str = _("Incremental");
327 str = _("Differential");
332 case L_VERIFY_CATALOG:
333 str = _("Verify Catalog");
336 str = _("Verify Init Catalog");
338 case L_VERIFY_VOLUME_TO_CATALOG:
339 str = _("Verify Volume to Catalog");
341 case L_VERIFY_DISK_TO_CATALOG:
342 str = _("Verify Disk to Catalog");
345 str = _("Verify Data");
351 str = _("Unknown Job Level");
358 /***********************************************************************
359 * Encode the mode bits into a 10 character string like LS does
360 ***********************************************************************/
362 char *encode_mode(mode_t mode, char *buf)
366 *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
367 S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-';
368 *cp++ = mode & S_IRUSR ? 'r' : '-';
369 *cp++ = mode & S_IWUSR ? 'w' : '-';
370 *cp++ = (mode & S_ISUID
371 ? (mode & S_IXUSR ? 's' : 'S')
372 : (mode & S_IXUSR ? 'x' : '-'));
373 *cp++ = mode & S_IRGRP ? 'r' : '-';
374 *cp++ = mode & S_IWGRP ? 'w' : '-';
375 *cp++ = (mode & S_ISGID
376 ? (mode & S_IXGRP ? 's' : 'S')
377 : (mode & S_IXGRP ? 'x' : '-'));
378 *cp++ = mode & S_IROTH ? 'r' : '-';
379 *cp++ = mode & S_IWOTH ? 'w' : '-';
380 *cp++ = (mode & S_ISVTX
381 ? (mode & S_IXOTH ? 't' : 'T')
382 : (mode & S_IXOTH ? 'x' : '-'));
388 int do_shell_expansion(char *name, int name_len)
390 static char meta[] = "~\\$[]*?`'<>\"";
395 char line[MAXSTRING];
396 const char *shellcmd;
398 /* Check if any meta characters are present */
400 for (i = 0; i < len; i++) {
401 if (strchr(name, meta[i])) {
407 cmd = get_pool_memory(PM_FNAME);
409 if ((shellcmd = getenv("SHELL")) == NULL) {
410 shellcmd = "/bin/sh";
412 pm_strcpy(&cmd, shellcmd);
413 pm_strcat(&cmd, " -c \"echo ");
414 pm_strcat(&cmd, name);
415 pm_strcat(&cmd, "\"");
416 Dmsg1(400, "Send: %s\n", cmd);
417 if ((bpipe = open_bpipe(cmd, 0, "r"))) {
419 fgets(line, sizeof(line), bpipe->rfd);
420 strip_trailing_junk(line);
421 stat = close_bpipe(bpipe);
422 Dmsg2(400, "stat=%d got: %s\n", stat, line);
424 stat = 1; /* error */
426 free_pool_memory(cmd);
428 bstrncpy(name, line, name_len);
435 /* MAKESESSIONKEY -- Generate session key with optional start
436 key. If mode is TRUE, the key will be
437 translated to a string, otherwise it is
438 returned as 16 binary bytes.
440 from SpeakFreely by John Walker */
442 void make_session_key(char *key, char *seed, int mode)
445 struct MD5Context md5c;
446 unsigned char md5key[16], md5key1[16];
451 bstrncat(s, seed, sizeof(s));
454 /* The following creates a seed for the session key generator
455 based on a collection of volatile and environment-specific
456 information unlikely to be vulnerable (as a whole) to an
457 exhaustive search attack. If one of these items isn't
458 available on your machine, replace it with something
459 equivalent or, if you like, just delete it. */
461 sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
462 sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
463 (void)getcwd(s + strlen(s), 256);
464 sprintf(s + strlen(s), "%lu", (unsigned long)clock());
465 sprintf(s + strlen(s), "%lu", (unsigned long)time(NULL));
467 sysinfo(SI_HW_SERIAL,s + strlen(s), 12);
469 #ifdef HAVE_GETHOSTID
470 sprintf(s + strlen(s), "%lu", (unsigned long) gethostid());
472 gethostname(s + strlen(s), 256);
473 sprintf(s + strlen(s), "%u", (unsigned)getuid());
474 sprintf(s + strlen(s), "%u", (unsigned)getgid());
476 MD5Update(&md5c, (unsigned char *)s, strlen(s));
477 MD5Final(md5key, &md5c);
478 sprintf(s + strlen(s), "%lu", (unsigned long)((time(NULL) + 65121) ^ 0x375F));
480 MD5Update(&md5c, (unsigned char *)s, strlen(s));
481 MD5Final(md5key1, &md5c);
482 #define nextrand (md5key[j] ^ md5key1[j])
484 for (j = k = 0; j < 16; j++) {
485 unsigned char rb = nextrand;
487 #define Rad16(x) ((x) + 'A')
488 key[k++] = Rad16((rb >> 4) & 0xF);
489 key[k++] = Rad16(rb & 0xF);
497 for (j = 0; j < 16; j++) {
507 * Edit job codes into main command line
510 * %d = Director's name
515 * %n = Unadorned Job name
517 * %t = Job type (Backup, ...)
521 * omsg = edited output message
522 * imsg = input string containing edit codes (%x)
523 * to = recepients list
526 POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to)
531 char name[MAX_NAME_LENGTH];
535 Dmsg1(200, "edit_job_codes: %s\n", imsg);
536 for (p=imsg; *p; p++) {
544 str = jcr->client_name;
550 str = my_name; /* Director's name */
554 str = job_status_to_str(jcr->JobStatus);
561 bsnprintf(add, sizeof(add), "%d", jcr->JobId);
567 case 'j': /* Job name */
576 str = job_level_to_str(jcr->JobLevel);
583 bstrncpy(name, jcr->Job, sizeof(name));
584 /* There are three periods after the Job name */
585 for (i=0; i<3; i++) {
586 if ((q=strrchr(name, '.')) != NULL) {
598 case 's': /* since time */
599 if (jcr && jcr->stime) {
607 str = job_type_to_str(jcr->JobType);
614 if (jcr->VolumeName && jcr->VolumeName[0]) {
615 str = jcr->VolumeName;
635 Dmsg1(1200, "add_str %s\n", str);
636 pm_strcat(&omsg, str);
637 Dmsg1(1200, "omsg=%s\n", omsg);
642 void set_working_directory(char *wd)
644 struct stat stat_buf;
647 Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n"));
649 if (stat(wd, &stat_buf) != 0) {
650 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
653 if (!S_ISDIR(stat_buf.st_mode)) {
654 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
657 working_directory = wd; /* set global */