2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2006 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 two of the GNU 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 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 John Walker.
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 * util.c miscellaneous utility subroutines for Bacula
38 #include "findlib/find.h"
41 * Various Bacula Utility subroutines
45 /* Return true of buffer has all zero bytes */
46 bool is_buf_zero(char *buf, int len)
50 int i, len64, done, rem;
56 /* Optimize by checking uint64_t for zero */
57 len64 = len / sizeof(uint64_t);
58 for (i=0; i < len64; i++) {
63 done = len64 * sizeof(uint64_t); /* bytes already checked */
66 for (i = 0; i < rem; i++) {
75 /* Convert a string in place to lower case */
79 if (B_ISUPPER(*str)) {
80 *str = tolower((int)(*str));
86 /* Convert spaces to non-space character.
87 * This makes scanf of fields containing spaces easier.
90 bash_spaces(char *str)
99 /* Convert spaces to non-space character.
100 * This makes scanf of fields containing spaces easier.
103 bash_spaces(POOL_MEM &pm)
105 char *str = pm.c_str();
114 /* Convert non-space characters (0x1) back into spaces */
116 unbash_spaces(char *str)
125 /* Convert non-space characters (0x1) back into spaces */
127 unbash_spaces(POOL_MEM &pm)
129 char *str = pm.c_str();
137 char *encode_time(time_t time, char *buf)
142 #if defined(HAVE_WIN32)
144 * Avoid a seg fault in Microsoft's CRT localtime_r(),
145 * which incorrectly references a NULL returned from gmtime() if
146 * time is negative before or after the timezone adjustment.
150 if ((gtm = gmtime(&time)) == NULL) {
154 if (gtm->tm_year == 1970 && gtm->tm_mon == 1 && gtm->tm_mday < 3) {
159 if (localtime_r(&time, &tm)) {
160 n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
161 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
162 tm.tm_hour, tm.tm_min, tm.tm_sec);
170 * Convert a JobStatus code into a human readable form
172 void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
179 jobstat = _("Created");
182 jobstat = _("Running");
185 jobstat = _("Blocked");
191 case JS_ErrorTerminated:
192 jobstat = _("Error");
195 jobstat = _("Non-fatal error");
198 jobstat = _("Canceled");
201 jobstat = _("Verify differences");
204 jobstat = _("Waiting on FD");
207 jobstat = _("Wait on SD");
210 jobstat = _("Wait for new Volume");
213 jobstat = _("Waiting for mount");
215 case JS_WaitStoreRes:
216 jobstat = _("Waiting for Storage resource");
219 jobstat = _("Waiting for Job resource");
221 case JS_WaitClientRes:
222 jobstat = _("Waiting for Client resource");
225 jobstat = _("Waiting on Max Jobs");
227 case JS_WaitStartTime:
228 jobstat = _("Waiting for Start Time");
230 case JS_WaitPriority:
231 jobstat = _("Waiting on Priority");
233 case JS_AttrDespooling:
234 jobstat = _("SD despooling Attributes");
236 case JS_AttrInserting:
237 jobstat = _("Dir inserting Attributes");
241 if (JobStatus == 0) {
244 bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
249 bstrncpy(msg, jobstat, maxlen);
253 * Convert Job Termination Status into a string
255 const char *job_status_to_str(int stat)
263 case JS_ErrorTerminated:
268 str = _("Fatal Error");
274 str = _("Differences");
277 str = _("Unknown term code");
285 * Convert Job Type into a string
287 const char *job_type_to_str(int type)
314 str = _("System or Console");
320 str = _("Unknown Type");
327 * Convert Job Level into a string
329 const char *job_level_to_str(int level)
340 str = _("Incremental");
343 str = _("Differential");
348 case L_VERIFY_CATALOG:
349 str = _("Verify Catalog");
352 str = _("Verify Init Catalog");
354 case L_VERIFY_VOLUME_TO_CATALOG:
355 str = _("Verify Volume to Catalog");
357 case L_VERIFY_DISK_TO_CATALOG:
358 str = _("Verify Disk to Catalog");
361 str = _("Verify Data");
367 str = _("Unknown Job Level");
374 /***********************************************************************
375 * Encode the mode bits into a 10 character string like LS does
376 ***********************************************************************/
378 char *encode_mode(mode_t mode, char *buf)
382 *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
383 S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-';
384 *cp++ = mode & S_IRUSR ? 'r' : '-';
385 *cp++ = mode & S_IWUSR ? 'w' : '-';
386 *cp++ = (mode & S_ISUID
387 ? (mode & S_IXUSR ? 's' : 'S')
388 : (mode & S_IXUSR ? 'x' : '-'));
389 *cp++ = mode & S_IRGRP ? 'r' : '-';
390 *cp++ = mode & S_IWGRP ? 'w' : '-';
391 *cp++ = (mode & S_ISGID
392 ? (mode & S_IXGRP ? 's' : 'S')
393 : (mode & S_IXGRP ? 'x' : '-'));
394 *cp++ = mode & S_IROTH ? 'r' : '-';
395 *cp++ = mode & S_IWOTH ? 'w' : '-';
396 *cp++ = (mode & S_ISVTX
397 ? (mode & S_IXOTH ? 't' : 'T')
398 : (mode & S_IXOTH ? 'x' : '-'));
403 #if defined(HAVE_WIN32)
404 int do_shell_expansion(char *name, int name_len)
406 char *src = bstrdup(name);
408 ExpandEnvironmentStrings(src, name, name_len);
415 int do_shell_expansion(char *name, int name_len)
417 static char meta[] = "~\\$[]*?`'<>\"";
422 char line[MAXSTRING];
423 const char *shellcmd;
425 /* Check if any meta characters are present */
427 for (i = 0; i < len; i++) {
428 if (strchr(name, meta[i])) {
434 cmd = get_pool_memory(PM_FNAME);
436 if ((shellcmd = getenv("SHELL")) == NULL) {
437 shellcmd = "/bin/sh";
439 pm_strcpy(&cmd, shellcmd);
440 pm_strcat(&cmd, " -c \"echo ");
441 pm_strcat(&cmd, name);
442 pm_strcat(&cmd, "\"");
443 Dmsg1(400, "Send: %s\n", cmd);
444 if ((bpipe = open_bpipe(cmd, 0, "r"))) {
446 fgets(line, sizeof(line), bpipe->rfd);
447 strip_trailing_junk(line);
448 stat = close_bpipe(bpipe);
449 Dmsg2(400, "stat=%d got: %s\n", stat, line);
451 stat = 1; /* error */
453 free_pool_memory(cmd);
455 bstrncpy(name, line, name_len);
463 /* MAKESESSIONKEY -- Generate session key with optional start
464 key. If mode is TRUE, the key will be
465 translated to a string, otherwise it is
466 returned as 16 binary bytes.
468 from SpeakFreely by John Walker */
470 void make_session_key(char *key, char *seed, int mode)
473 struct MD5Context md5c;
474 unsigned char md5key[16], md5key1[16];
479 bstrncat(s, seed, sizeof(s));
482 /* The following creates a seed for the session key generator
483 based on a collection of volatile and environment-specific
484 information unlikely to be vulnerable (as a whole) to an
485 exhaustive search attack. If one of these items isn't
486 available on your machine, replace it with something
487 equivalent or, if you like, just delete it. */
489 #if defined(HAVE_WIN32)
497 sprintf(s + strlen(s), "%lu", (unsigned long)GetCurrentProcessId());
498 (void)getcwd(s + strlen(s), 256);
499 sprintf(s + strlen(s), "%lu", (unsigned long)GetTickCount());
500 QueryPerformanceCounter(&li);
501 sprintf(s + strlen(s), "%lu", (unsigned long)li.LowPart);
502 GetSystemTimeAsFileTime(&ft);
503 sprintf(s + strlen(s), "%lu", (unsigned long)ft.dwLowDateTime);
504 sprintf(s + strlen(s), "%lu", (unsigned long)ft.dwHighDateTime);
506 GetComputerName(s + strlen(s), &length);
508 GetUserName(s + strlen(s), &length);
511 sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
512 sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
513 (void)getcwd(s + strlen(s), 256);
514 sprintf(s + strlen(s), "%lu", (unsigned long)clock());
515 sprintf(s + strlen(s), "%lu", (unsigned long)time(NULL));
517 sysinfo(SI_HW_SERIAL,s + strlen(s), 12);
519 #if defined(HAVE_GETHOSTID)
520 sprintf(s + strlen(s), "%lu", (unsigned long) gethostid());
522 gethostname(s + strlen(s), 256);
523 sprintf(s + strlen(s), "%u", (unsigned)getuid());
524 sprintf(s + strlen(s), "%u", (unsigned)getgid());
527 MD5Update(&md5c, (unsigned char *)s, strlen(s));
528 MD5Final(md5key, &md5c);
529 sprintf(s + strlen(s), "%lu", (unsigned long)((time(NULL) + 65121) ^ 0x375F));
531 MD5Update(&md5c, (unsigned char *)s, strlen(s));
532 MD5Final(md5key1, &md5c);
533 #define nextrand (md5key[j] ^ md5key1[j])
535 for (j = k = 0; j < 16; j++) {
536 unsigned char rb = nextrand;
538 #define Rad16(x) ((x) + 'A')
539 key[k++] = Rad16((rb >> 4) & 0xF);
540 key[k++] = Rad16(rb & 0xF);
548 for (j = 0; j < 16; j++) {
558 * Edit job codes into main command line
561 * %d = Director's name
566 * %n = Unadorned Job name
568 * %t = Job type (Backup, ...)
572 * omsg = edited output message
573 * imsg = input string containing edit codes (%x)
574 * to = recepients list
577 POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to)
582 char name[MAX_NAME_LENGTH];
586 Dmsg1(200, "edit_job_codes: %s\n", imsg);
587 for (p=imsg; *p; p++) {
595 str = jcr->client_name;
601 str = my_name; /* Director's name */
605 str = job_status_to_str(jcr->JobStatus);
612 bsnprintf(add, sizeof(add), "%d", jcr->JobId);
618 case 'j': /* Job name */
627 str = job_level_to_str(jcr->JobLevel);
634 bstrncpy(name, jcr->Job, sizeof(name));
635 /* There are three periods after the Job name */
636 for (i=0; i<3; i++) {
637 if ((q=strrchr(name, '.')) != NULL) {
649 case 's': /* since time */
650 if (jcr && jcr->stime) {
658 str = job_type_to_str(jcr->JobType);
665 if (jcr->VolumeName && jcr->VolumeName[0]) {
666 str = jcr->VolumeName;
686 Dmsg1(1200, "add_str %s\n", str);
687 pm_strcat(&omsg, str);
688 Dmsg1(1200, "omsg=%s\n", omsg);
693 void set_working_directory(char *wd)
695 struct stat stat_buf;
698 Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n"));
700 if (stat(wd, &stat_buf) != 0) {
701 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
704 if (!S_ISDIR(stat_buf.st_mode)) {
705 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
708 working_directory = wd; /* set global */
711 const char *last_path_separator(const char *str)
714 for (const char *p = &str[strlen(str) - 1]; p >= str; p--) {
715 if (IsPathSeparator(*p)) {