2 * util.c miscellaneous utility subroutines for Bacula
9 Bacula® - The Network Backup Solution
11 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13 The main author of Bacula is Kern Sibbald, with contributions from
14 many others, a complete list can be found in the file AUTHORS.
15 This program is Free Software; you can redistribute it and/or
16 modify it under the terms of version two of the GNU General Public
17 License as published by the Free Software Foundation plus additions
18 that are listed in the file LICENSE.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 Bacula® is a registered trademark of John Walker.
31 The licensor of Bacula is the Free Software Foundation Europe
32 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33 Switzerland, email:ftf@fsfeurope.org.
38 #include "findlib/find.h"
41 * Various Bacula Utility subroutines
45 /* Return true of buffer has all zero bytes */
46 int 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 */
80 *str = tolower((int)(*str));
85 /* Convert spaces to non-space character.
86 * This makes scanf of fields containing spaces easier.
89 bash_spaces(char *str)
98 /* Convert spaces to non-space character.
99 * This makes scanf of fields containing spaces easier.
102 bash_spaces(POOL_MEM &pm)
104 char *str = pm.c_str();
113 /* Convert non-space characters (0x1) back into spaces */
115 unbash_spaces(char *str)
124 /* Convert non-space characters (0x1) back into spaces */
126 unbash_spaces(POOL_MEM &pm)
128 char *str = pm.c_str();
136 char *encode_time(time_t time, char *buf)
141 #if defined(HAVE_WIN32)
143 * Avoid a seg fault in Microsoft's CRT localtime_r(),
144 * which incorrectly references a NULL returned from gmtime() if
145 * time is negative before or after the timezone adjustment.
149 if ((gtm = gmtime(&time)) == NULL) {
153 if (gtm->tm_year == 1970 && gtm->tm_mon == 1 && gtm->tm_mday < 3) {
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)
307 str = _("System or Console");
313 str = _("Unknown Type");
320 * Convert Job Level into a string
322 const char *job_level_to_str(int level)
333 str = _("Incremental");
336 str = _("Differential");
341 case L_VERIFY_CATALOG:
342 str = _("Verify Catalog");
345 str = _("Verify Init Catalog");
347 case L_VERIFY_VOLUME_TO_CATALOG:
348 str = _("Verify Volume to Catalog");
350 case L_VERIFY_DISK_TO_CATALOG:
351 str = _("Verify Disk to Catalog");
354 str = _("Verify Data");
360 str = _("Unknown Job Level");
367 /***********************************************************************
368 * Encode the mode bits into a 10 character string like LS does
369 ***********************************************************************/
371 char *encode_mode(mode_t mode, char *buf)
375 *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
376 S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-';
377 *cp++ = mode & S_IRUSR ? 'r' : '-';
378 *cp++ = mode & S_IWUSR ? 'w' : '-';
379 *cp++ = (mode & S_ISUID
380 ? (mode & S_IXUSR ? 's' : 'S')
381 : (mode & S_IXUSR ? 'x' : '-'));
382 *cp++ = mode & S_IRGRP ? 'r' : '-';
383 *cp++ = mode & S_IWGRP ? 'w' : '-';
384 *cp++ = (mode & S_ISGID
385 ? (mode & S_IXGRP ? 's' : 'S')
386 : (mode & S_IXGRP ? 'x' : '-'));
387 *cp++ = mode & S_IROTH ? 'r' : '-';
388 *cp++ = mode & S_IWOTH ? 'w' : '-';
389 *cp++ = (mode & S_ISVTX
390 ? (mode & S_IXOTH ? 't' : 'T')
391 : (mode & S_IXOTH ? 'x' : '-'));
396 #if defined(HAVE_WIN32)
397 int do_shell_expansion(char *name, int name_len)
399 char *src = bstrdup(name);
401 ExpandEnvironmentStrings(src, name, name_len);
408 int do_shell_expansion(char *name, int name_len)
410 static char meta[] = "~\\$[]*?`'<>\"";
415 char line[MAXSTRING];
416 const char *shellcmd;
418 /* Check if any meta characters are present */
420 for (i = 0; i < len; i++) {
421 if (strchr(name, meta[i])) {
427 cmd = get_pool_memory(PM_FNAME);
429 if ((shellcmd = getenv("SHELL")) == NULL) {
430 shellcmd = "/bin/sh";
432 pm_strcpy(&cmd, shellcmd);
433 pm_strcat(&cmd, " -c \"echo ");
434 pm_strcat(&cmd, name);
435 pm_strcat(&cmd, "\"");
436 Dmsg1(400, "Send: %s\n", cmd);
437 if ((bpipe = open_bpipe(cmd, 0, "r"))) {
439 fgets(line, sizeof(line), bpipe->rfd);
440 strip_trailing_junk(line);
441 stat = close_bpipe(bpipe);
442 Dmsg2(400, "stat=%d got: %s\n", stat, line);
444 stat = 1; /* error */
446 free_pool_memory(cmd);
448 bstrncpy(name, line, name_len);
456 /* MAKESESSIONKEY -- Generate session key with optional start
457 key. If mode is TRUE, the key will be
458 translated to a string, otherwise it is
459 returned as 16 binary bytes.
461 from SpeakFreely by John Walker */
463 void make_session_key(char *key, char *seed, int mode)
466 struct MD5Context md5c;
467 unsigned char md5key[16], md5key1[16];
472 bstrncat(s, seed, sizeof(s));
475 /* The following creates a seed for the session key generator
476 based on a collection of volatile and environment-specific
477 information unlikely to be vulnerable (as a whole) to an
478 exhaustive search attack. If one of these items isn't
479 available on your machine, replace it with something
480 equivalent or, if you like, just delete it. */
482 #if defined(HAVE_WIN32)
490 sprintf(s + strlen(s), "%lu", (unsigned long)GetCurrentProcessId());
491 (void)getcwd(s + strlen(s), 256);
492 sprintf(s + strlen(s), "%lu", (unsigned long)GetTickCount());
493 QueryPerformanceCounter(&li);
494 sprintf(s + strlen(s), "%lu", (unsigned long)li.LowPart);
495 GetSystemTimeAsFileTime(&ft);
496 sprintf(s + strlen(s), "%lu", (unsigned long)ft.dwLowDateTime);
497 sprintf(s + strlen(s), "%lu", (unsigned long)ft.dwHighDateTime);
499 GetComputerName(s + strlen(s), &length);
501 GetUserName(s + strlen(s), &length);
504 sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
505 sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
506 (void)getcwd(s + strlen(s), 256);
507 sprintf(s + strlen(s), "%lu", (unsigned long)clock());
508 sprintf(s + strlen(s), "%lu", (unsigned long)time(NULL));
510 sysinfo(SI_HW_SERIAL,s + strlen(s), 12);
512 #if defined(HAVE_GETHOSTID)
513 sprintf(s + strlen(s), "%lu", (unsigned long) gethostid());
515 gethostname(s + strlen(s), 256);
516 sprintf(s + strlen(s), "%u", (unsigned)getuid());
517 sprintf(s + strlen(s), "%u", (unsigned)getgid());
520 MD5Update(&md5c, (unsigned char *)s, strlen(s));
521 MD5Final(md5key, &md5c);
522 sprintf(s + strlen(s), "%lu", (unsigned long)((time(NULL) + 65121) ^ 0x375F));
524 MD5Update(&md5c, (unsigned char *)s, strlen(s));
525 MD5Final(md5key1, &md5c);
526 #define nextrand (md5key[j] ^ md5key1[j])
528 for (j = k = 0; j < 16; j++) {
529 unsigned char rb = nextrand;
531 #define Rad16(x) ((x) + 'A')
532 key[k++] = Rad16((rb >> 4) & 0xF);
533 key[k++] = Rad16(rb & 0xF);
541 for (j = 0; j < 16; j++) {
551 * Edit job codes into main command line
554 * %d = Director's name
559 * %n = Unadorned Job name
561 * %t = Job type (Backup, ...)
565 * omsg = edited output message
566 * imsg = input string containing edit codes (%x)
567 * to = recepients list
570 POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to)
575 char name[MAX_NAME_LENGTH];
579 Dmsg1(200, "edit_job_codes: %s\n", imsg);
580 for (p=imsg; *p; p++) {
588 str = jcr->client_name;
594 str = my_name; /* Director's name */
598 str = job_status_to_str(jcr->JobStatus);
605 bsnprintf(add, sizeof(add), "%d", jcr->JobId);
611 case 'j': /* Job name */
620 str = job_level_to_str(jcr->JobLevel);
627 bstrncpy(name, jcr->Job, sizeof(name));
628 /* There are three periods after the Job name */
629 for (i=0; i<3; i++) {
630 if ((q=strrchr(name, '.')) != NULL) {
642 case 's': /* since time */
643 if (jcr && jcr->stime) {
651 str = job_type_to_str(jcr->JobType);
658 if (jcr->VolumeName && jcr->VolumeName[0]) {
659 str = jcr->VolumeName;
679 Dmsg1(1200, "add_str %s\n", str);
680 pm_strcat(&omsg, str);
681 Dmsg1(1200, "omsg=%s\n", omsg);
686 void set_working_directory(char *wd)
688 struct stat stat_buf;
691 Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n"));
693 if (stat(wd, &stat_buf) != 0) {
694 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
697 if (!S_ISDIR(stat_buf.st_mode)) {
698 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
701 working_directory = wd; /* set global */
704 const char *last_path_separator(const char *str)
707 for (const char *p = &str[strlen(str) - 1]; p >= str; p--) {
708 if (IsPathSeparator(*p)) {