2 * util.c miscellaneous utility subroutines for Bacula
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 * Various Bacula Utility subroutines
38 /* Return true of buffer has all zero bytes */
39 int is_buf_zero(char *buf, int len)
43 int i, len64, done, rem;
49 /* Optimize by checking uint64_t for zero */
50 len64 = len / sizeof(uint64_t);
51 for (i=0; i < len64; i++) {
56 done = len64 * sizeof(uint64_t); /* bytes already checked */
59 for (i = 0; i < rem; i++) {
68 /* Convert a string in place to lower case */
73 *str = tolower((int)(*str));
78 /* Convert spaces to non-space character.
79 * This makes scanf of fields containing spaces easier.
82 bash_spaces(char *str)
91 /* Convert non-space characters (0x1) back into spaces */
93 unbash_spaces(char *str)
103 char *encode_time(time_t time, char *buf)
108 if (localtime_r(&time, &tm)) {
109 n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
110 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
111 tm.tm_hour, tm.tm_min, tm.tm_sec);
117 * Concatenate a string (str) onto a pool memory buffer pm
118 * Returns: length of concatenated string
120 int pm_strcat(POOLMEM **pm, const char *str)
122 int pmlen = strlen(*pm);
123 int len = strlen(str) + 1;
125 *pm = check_pool_memory_size(*pm, pmlen + len);
126 memcpy(*pm+pmlen, str, len);
127 return pmlen + len - 1;
132 * Copy a string (str) into a pool memory buffer pm
133 * Returns: length of string copied
135 int pm_strcpy(POOLMEM **pm, const char *str)
137 int len = strlen(str) + 1;
139 *pm = check_pool_memory_size(*pm, len);
140 memcpy(*pm, str, len);
146 * Convert a JobStatus code into a human readable form
148 void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
155 jobstat = _("Created");
158 jobstat = _("Running");
161 jobstat = _("Blocked");
167 case JS_ErrorTerminated:
168 jobstat = _("Error");
171 jobstat = _("Non-fatal error");
174 jobstat = _("Canceled");
177 jobstat = _("Verify differences");
180 jobstat = _("Waiting on FD");
183 jobstat = _("Wait on SD");
186 jobstat = _("Wait for new Volume");
189 jobstat = _("Waiting for mount");
191 case JS_WaitStoreRes:
192 jobstat = _("Waiting for Storage resource");
195 jobstat = _("Waiting for Job resource");
197 case JS_WaitClientRes:
198 jobstat = _("Waiting for Client resource");
201 jobstat = _("Waiting on Max Jobs");
203 case JS_WaitStartTime:
204 jobstat = _("Waiting for Start Time");
206 case JS_WaitPriority:
207 jobstat = _("Waiting on Priority");
211 if (JobStatus == 0) {
214 bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
219 bstrncpy(msg, jobstat, maxlen);
223 * Convert Job Termination Status into a string
225 char *job_status_to_str(int stat)
233 case JS_ErrorTerminated:
238 str = _("Fatal Error");
244 str = _("Differences");
247 str = _("Unknown term code");
255 * Convert Job Type into a string
257 char *job_type_to_str(int type)
275 str = _("Unknown Type");
282 * Convert Job Level into a string
284 char *job_level_to_str(int level)
295 str = _("Incremental");
298 str = _("Differential");
303 case L_VERIFY_CATALOG:
304 str = _("Verify Catalog");
307 str = _("Verify Init Catalog");
309 case L_VERIFY_VOLUME_TO_CATALOG:
310 str = _("Verify Volume to Catalog");
312 case L_VERIFY_DISK_TO_CATALOG:
313 str = _("Verify Disk to Catalog");
316 str = _("Verify Data");
322 str = _("Unknown Job Level");
329 /***********************************************************************
330 * Encode the mode bits into a 10 character string like LS does
331 ***********************************************************************/
333 char *encode_mode(mode_t mode, char *buf)
337 *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
338 S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-';
339 *cp++ = mode & S_IRUSR ? 'r' : '-';
340 *cp++ = mode & S_IWUSR ? 'w' : '-';
341 *cp++ = (mode & S_ISUID
342 ? (mode & S_IXUSR ? 's' : 'S')
343 : (mode & S_IXUSR ? 'x' : '-'));
344 *cp++ = mode & S_IRGRP ? 'r' : '-';
345 *cp++ = mode & S_IWGRP ? 'w' : '-';
346 *cp++ = (mode & S_ISGID
347 ? (mode & S_IXGRP ? 's' : 'S')
348 : (mode & S_IXGRP ? 'x' : '-'));
349 *cp++ = mode & S_IROTH ? 'r' : '-';
350 *cp++ = mode & S_IWOTH ? 'w' : '-';
351 *cp++ = (mode & S_ISVTX
352 ? (mode & S_IXOTH ? 't' : 'T')
353 : (mode & S_IXOTH ? 'x' : '-'));
359 int do_shell_expansion(char *name, int name_len)
361 static char meta[] = "~\\$[]*?`'<>\"";
366 char line[MAXSTRING];
369 /* Check if any meta characters are present */
371 for (i = 0; i < len; i++) {
372 if (strchr(name, meta[i])) {
378 cmd = get_pool_memory(PM_FNAME);
380 if ((shellcmd = getenv("SHELL")) == NULL) {
381 shellcmd = "/bin/sh";
383 pm_strcpy(&cmd, shellcmd);
384 pm_strcat(&cmd, " -c \"echo ");
385 pm_strcat(&cmd, name);
386 pm_strcat(&cmd, "\"");
387 Dmsg1(400, "Send: %s\n", cmd);
388 if ((bpipe = open_bpipe(cmd, 0, "r"))) {
390 fgets(line, sizeof(line), bpipe->rfd);
391 strip_trailing_junk(line);
392 stat = close_bpipe(bpipe);
393 Dmsg2(400, "stat=%d got: %s\n", stat, line);
395 stat = 1; /* error */
397 free_pool_memory(cmd);
399 bstrncpy(name, line, name_len);
406 /* MAKESESSIONKEY -- Generate session key with optional start
407 key. If mode is TRUE, the key will be
408 translated to a string, otherwise it is
409 returned as 16 binary bytes.
411 from SpeakFreely by John Walker */
413 void make_session_key(char *key, char *seed, int mode)
416 struct MD5Context md5c;
417 unsigned char md5key[16], md5key1[16];
422 bstrncat(s, seed, sizeof(s));
425 /* The following creates a seed for the session key generator
426 based on a collection of volatile and environment-specific
427 information unlikely to be vulnerable (as a whole) to an
428 exhaustive search attack. If one of these items isn't
429 available on your machine, replace it with something
430 equivalent or, if you like, just delete it. */
432 sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
433 sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
434 getcwd(s + strlen(s), 256);
435 sprintf(s + strlen(s), "%lu", (unsigned long)clock());
436 sprintf(s + strlen(s), "%lu", (unsigned long)time(NULL));
438 sysinfo(SI_HW_SERIAL,s + strlen(s), 12);
440 #ifdef HAVE_GETHOSTID
441 sprintf(s + strlen(s), "%lu", (unsigned long) gethostid());
443 #ifdef HAVE_GETDOMAINNAME
444 getdomainname(s + strlen(s), 256);
446 gethostname(s + strlen(s), 256);
447 sprintf(s + strlen(s), "%u", (unsigned)getuid());
448 sprintf(s + strlen(s), "%u", (unsigned)getgid());
450 MD5Update(&md5c, (unsigned char *)s, strlen(s));
451 MD5Final(md5key, &md5c);
452 sprintf(s + strlen(s), "%lu", (unsigned long)((time(NULL) + 65121) ^ 0x375F));
454 MD5Update(&md5c, (unsigned char *)s, strlen(s));
455 MD5Final(md5key1, &md5c);
456 #define nextrand (md5key[j] ^ md5key1[j])
458 for (j = k = 0; j < 16; j++) {
459 unsigned char rb = nextrand;
461 #define Rad16(x) ((x) + 'A')
462 key[k++] = Rad16((rb >> 4) & 0xF);
463 key[k++] = Rad16(rb & 0xF);
471 for (j = 0; j < 16; j++) {
481 * Edit job codes into main command line
484 * %d = Director's name
487 * %j = Unique Job name
489 * %n = Unadorned Job name
490 * %t = Job type (Backup, ...)
494 * omsg = edited output message
495 * imsg = input string containing edit codes (%x)
496 * to = recepients list
499 POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to)
504 char name[MAX_NAME_LENGTH];
508 Dmsg1(200, "edit_job_codes: %s\n", imsg);
509 for (p=imsg; *p; p++) {
516 str = jcr->client_name;
522 str = my_name; /* Director's name */
525 str = job_status_to_str(jcr->JobStatus);
528 bsnprintf(add, sizeof(add), "%d", jcr->JobId);
531 case 'j': /* Job name */
535 str = job_level_to_str(jcr->JobLevel);
538 bstrncpy(name, jcr->Job, sizeof(name));
539 /* There are three periods after the Job name */
540 for (i=0; i<3; i++) {
541 if ((q=strrchr(name, '.')) != NULL) {
551 str = job_type_to_str(jcr->JobType);
554 if (jcr->VolumeName && jcr->VolumeName[0]) {
555 str = jcr->VolumeName;
572 Dmsg1(1200, "add_str %s\n", str);
573 pm_strcat(&omsg, str);
574 Dmsg1(1200, "omsg=%s\n", omsg);
579 void set_working_directory(char *wd)
581 struct stat stat_buf;
584 Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n"));
586 if (stat(wd, &stat_buf) != 0) {
587 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
590 if (!S_ISDIR(stat_buf.st_mode)) {
591 Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
594 working_directory = wd; /* set global */