X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Futil.c;h=0ef5a59c29f8f552ebf47d0005448416694a388d;hb=28b98a207e5834c4066b6565c4210220957452e4;hp=ab82295e9217bb97759e668082ced9e16b229d3e;hpb=1ef84681d13d0c355d6ae78579d2afe1c8d8d0e2;p=bacula%2Fbacula diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index ab82295e92..0ef5a59c29 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -2,6 +2,8 @@ * util.c miscellaneous utility subroutines for Bacula * * Kern Sibbald, MM + * + * Version $Id$ */ /* @@ -25,6 +27,7 @@ */ #include "bacula.h" +#include "jcr.h" #include "findlib/find.h" /* @@ -32,49 +35,37 @@ * */ -/* - * Edit a number with commas, the supplied buffer - * must be at least 27 bytes long. - */ -char *edit_uint_with_commas(uint64_t val, char *buf) -{ - sprintf(buf, "%" lld, val); - return add_commas(buf, buf); -} - -char *add_commas(char *val, char *buf) +/* Return true of buffer has all zero bytes */ +int is_buf_zero(char *buf, int len) { - int len, nc; - char *p, *q; - int i; + uint64_t *ip = (uint64_t *)buf; + char *p; + int i, len64, done, rem; - if (val != buf) { - strcpy(buf, val); - } - len = strlen(buf); - if (len < 1) { - len = 1; + /* Optimize by checking uint64_t for zero */ + len64 = len >> sizeof(uint64_t); + for (i=0; i < len64; i++) { + if (ip[i] != 0) { + return 0; + } } - nc = (len - 1) / 3; - p = buf+len; - q = p + nc; - *q-- = *p--; - for ( ; nc; nc--) { - for (i=0; i < 3; i++) { - *q-- = *p--; + done = len64 << sizeof(uint64_t); /* bytes already checked */ + p = buf + done; + rem = len - done; + for (i = 0; i < rem; i++) { + if (p[i] != 0) { + return 0; } - *q-- = ','; - } - return buf; + } + return 1; } /* Convert a string in place to lower case */ -void -lcase(char *str) +void lcase(char *str) { while (*str) { - if (ISUPPER(*str)) + if (B_ISUPPER(*str)) *str = tolower((int)(*str)); str++; } @@ -104,110 +95,179 @@ unbash_spaces(char *str) } } -/* Strip any trailing junk from the command */ -void strip_trailing_junk(char *cmd) + +char *encode_time(time_t time, char *buf) { - char *p; - p = cmd + strlen(cmd) - 1; + struct tm tm; + int n = 0; - /* strip trailing junk from command */ - while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) - *p-- = 0; + if (localtime_r(&time, &tm)) { + n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + } + return buf+n; } -/* Strip any trailing slashes from a directory path */ -void strip_trailing_slashes(char *dir) +/* + * Concatenate a string (str) onto a pool memory buffer pm + */ +void pm_strcat(POOLMEM **pm, char *str) { - char *p; - p = dir + strlen(dir) - 1; + int pmlen = strlen(*pm); + int len = strlen(str) + 1; - /* strip trailing slashes */ - while ((p >= dir) && (*p == '/')) - *p-- = 0; + *pm = check_pool_memory_size(*pm, pmlen + len); + memcpy(*pm+pmlen, str, len); } + /* - * Skip spaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * Copy a string (str) into a pool memory buffer pm */ -int skip_spaces(char **msg) +void pm_strcpy(POOLMEM **pm, char *str) { - char *p = *msg; - if (!p) { - return 0; - } - while (*p && *p == ' ') { - p++; - } - *msg = p; - return *p ? 1 : 0; + int len = strlen(str) + 1; + + *pm = check_pool_memory_size(*pm, len); + memcpy(*pm, str, len); } + /* - * Skip nonspaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter + * Convert a JobStatus code into a human readable form */ -int skip_nonspaces(char **msg) +void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen) { - char *p = *msg; + char *termstat, jstat[2]; - if (!p) { - return 0; - } - while (*p && *p != ' ') { - p++; + switch (JobStatus) { + case JS_Terminated: + termstat = _("OK"); + break; + case JS_FatalError: + case JS_ErrorTerminated: + termstat = _("Error"); + break; + case JS_Error: + termstat = _("Non-fatal error"); + break; + case JS_Canceled: + termstat = _("Canceled"); + break; + case JS_Differences: + termstat = _("Verify differences"); + break; + default: + jstat[0] = last_job.JobStatus; + jstat[1] = 0; + termstat = jstat; + break; } - *msg = p; - return *p ? 1 : 0; + bstrncpy(msg, termstat, maxlen); } -/* folded search for string - case insensitive */ -int -fstrsch(char *a, char *b) /* folded case search */ +/* + * Convert Job Termination Status into a string + */ +char *job_status_to_str(int stat) { - register char *s1,*s2; - register char c1, c2; - - s1=a; - s2=b; - while (*s1) { /* do it the fast way */ - if ((*s1++ | 0x20) != (*s2++ | 0x20)) - return 0; /* failed */ - } - while (*a) { /* do it over the correct slow way */ - if (ISUPPER(c1 = *a)) { - c1 = tolower((int)c1); - } - if (ISUPPER(c2 = *b)) { - c2 = tolower((int)c2); - } - if (c1 != c2) { - return 0; - } - a++; - b++; + char *str; + + switch (stat) { + case JS_Terminated: + str = _("OK"); + break; + case JS_ErrorTerminated: + case JS_Error: + str = _("Error"); + break; + case JS_FatalError: + str = _("Fatal Error"); + break; + case JS_Canceled: + str = _("Canceled"); + break; + case JS_Differences: + str = _("Differences"); + break; + default: + str = _("Unknown term code"); + break; } - return 1; + return str; } -char *encode_time(time_t time, char *buf) +/* + * Convert Job Type into a string + */ +char *job_type_to_str(int type) { - struct tm tm; - int n; + char *str; + + switch (type) { + case JT_BACKUP: + str = _("Backup"); + break; + case JT_VERIFY: + str = _("Verify"); + break; + case JT_RESTORE: + str = _("Restore"); + break; + case JT_ADMIN: + str = _("Admin"); + break; + default: + str = _("Unknown Type"); + break; + } + return str; +} - if (localtime_r(&time, &tm)) { - n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); +/* + * Convert Job Level into a string + */ +char *job_level_to_str(int level) +{ + char *str; + + switch (level) { + case L_BASE: + str = _("Base"); + case L_FULL: + str = _("Full"); + break; + case L_INCREMENTAL: + str = _("Incremental"); + break; + case L_DIFFERENTIAL: + str = _("Differential"); + break; + case L_SINCE: + str = _("Since"); + break; + case L_VERIFY_CATALOG: + str = _("Verify Catalog"); + break; + case L_VERIFY_INIT: + str = _("Verify Init Catalog"); + break; + case L_VERIFY_VOLUME_TO_CATALOG: + str = _("Verify Volume to Catalog"); + break; + case L_VERIFY_DATA: + str = _("Verify Data"); + break; + default: + str = _("Unknown Job Level"); + break; } - return buf+n; + return str; } + /*********************************************************************** * Encode the mode bits into a 10 character string like LS does ***********************************************************************/ @@ -216,8 +276,8 @@ char *encode_mode(mode_t mode, char *buf) { char *cp = buf; - *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' : - S_ISLNK(mode) ? 'l' : '-'; + *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' : + S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-'; *cp++ = mode & S_IRUSR ? 'r' : '-'; *cp++ = mode & S_IWUSR ? 'w' : '-'; *cp++ = (mode & S_ISUID @@ -237,44 +297,8 @@ char *encode_mode(mode_t mode, char *buf) return cp; } -#ifdef WORKING -extern char *getuser(uid_t uid); -extern char *getgroup(gid_t gid); - -void print_ls_output(char *fname, char *lname, int type, struct stat *statp) -{ - char buf[1000]; - char *p, *f; - int n; - - p = encode_mode(statp->st_mode, buf); - n = sprintf(p, " %2d ", (uint32_t)statp->st_nlink); - p += n; - n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid)); - p += n; - n = sprintf(p, "%8ld ", statp->st_size); - p += n; - p = encode_time(statp->st_ctime, p); - *p++ = ' '; - *p++ = ' '; - for (f=fname; *f; ) - *p++ = *f++; - if (type == FT_LNK) { - *p++ = ' '; - *p++ = '-'; - *p++ = '>'; - *p++ = ' '; - /* Copy link name */ - for (f=lname; *f; ) - *p++ = *f++; - } - *p++ = '\n'; - *p = 0; - fputs(buf, stdout); -} -#endif -int do_shell_expansion(char *name) +int do_shell_expansion(char *name, int name_len) { /* ****FIXME***** this should work for Win32 too */ #define UNIX @@ -286,7 +310,6 @@ int do_shell_expansion(char *name) int pid, wpid, stat; int waitstatus; char *shellcmd; - void (*istat)(int), (*qstat)(int); int i; char echout[PATH_MAX + 256]; int pfd[2]; @@ -324,34 +347,40 @@ int do_shell_expansion(char *name) case 0: /* child */ /* look for shell */ - if ((shellcmd = getenv("SHELL")) == NULL) + if ((shellcmd = getenv("SHELL")) == NULL) { shellcmd = "/bin/sh"; - close(1); dup(pfd[1]); /* attach pipes to stdin and stdout */ - close(2); dup(pfd[1]); - for (i = 3; i < 32; i++) /* close everything else */ - close(i); + } + close(pfd[0]); /* close stdin */ + dup2(pfd[1], 1); /* attach to stdout */ + dup2(pfd[1], 2); /* and stderr */ strcpy(echout, "echo "); /* form echo command */ - strcat(echout, name); + bstrncat(echout, name, sizeof(echout)); execl(shellcmd, shellcmd, "-c", echout, NULL); /* give to shell */ exit(127); /* shouldn't get here */ default: /* parent */ /* read output from child */ - i = read(pfd[0], echout, sizeof echout); - echout[--i] = 0; /* set end of string */ - /* look for first word or first line. */ - while (--i >= 0) { - if (echout[i] == ' ' || echout[i] == '\n') - echout[i] = 0; /* keep only first one */ + echout[0] = 0; + do { + i = read(pfd[0], echout, sizeof echout); + } while (i == -1 && errno == EINTR); + + if (i > 0) { + echout[--i] = 0; /* set end of string */ + /* look for first line. */ + while (--i >= 0) { + if (echout[i] == '\n') { + echout[i] = 0; /* keep only first one */ + } + } } - istat = signal(SIGINT, SIG_IGN); - qstat = signal(SIGQUIT, SIG_IGN); /* wait for child to exit */ while ((wpid = wait(&waitstatus)) != pid && wpid != -1) { ; } - signal(SIGINT, istat); - signal(SIGQUIT, qstat); - strcpy(name, echout); + strip_trailing_junk(echout); + if (strlen(echout) > 0) { + bstrncpy(name, echout, name_len); + } stat = 1; break; } @@ -379,3 +408,173 @@ int do_shell_expansion(char *name) #endif } + + +/* MAKESESSIONKEY -- Generate session key with optional start + key. If mode is TRUE, the key will be + translated to a string, otherwise it is + returned as 16 binary bytes. + + from SpeakFreely by John Walker */ + +void make_session_key(char *key, char *seed, int mode) +{ + int j, k; + struct MD5Context md5c; + unsigned char md5key[16], md5key1[16]; + char s[1024]; + + s[0] = 0; + if (seed != NULL) { + strcat(s, seed); + } + + /* The following creates a seed for the session key generator + based on a collection of volatile and environment-specific + information unlikely to be vulnerable (as a whole) to an + exhaustive search attack. If one of these items isn't + available on your machine, replace it with something + equivalent or, if you like, just delete it. */ + + sprintf(s + strlen(s), "%lu", (unsigned long) getpid()); + sprintf(s + strlen(s), "%lu", (unsigned long) getppid()); + getcwd(s + strlen(s), 256); + sprintf(s + strlen(s), "%lu", (unsigned long) clock()); + sprintf(s + strlen(s), "%lu", (unsigned long) time(NULL)); +#ifdef Solaris + sysinfo(SI_HW_SERIAL,s + strlen(s), 12); +#endif +#ifdef HAVE_GETHOSTID + sprintf(s + strlen(s), "%lu", (unsigned long) gethostid()); +#endif +#ifdef HAVE_GETDOMAINNAME + getdomainname(s + strlen(s), 256); +#endif + gethostname(s + strlen(s), 256); + sprintf(s + strlen(s), "%u", (unsigned)getuid()); + sprintf(s + strlen(s), "%u", (unsigned)getgid()); + MD5Init(&md5c); + MD5Update(&md5c, (unsigned char *)s, strlen(s)); + MD5Final(md5key, &md5c); + sprintf(s + strlen(s), "%lu", (unsigned long) ((time(NULL) + 65121) ^ 0x375F)); + MD5Init(&md5c); + MD5Update(&md5c, (unsigned char *)s, strlen(s)); + MD5Final(md5key1, &md5c); +#define nextrand (md5key[j] ^ md5key1[j]) + if (mode) { + for (j = k = 0; j < 16; j++) { + unsigned char rb = nextrand; + +#define Rad16(x) ((x) + 'A') + key[k++] = Rad16((rb >> 4) & 0xF); + key[k++] = Rad16(rb & 0xF); +#undef Rad16 + if (j & 1) { + key[k++] = '-'; + } + } + key[--k] = 0; + } else { + for (j = 0; j < 16; j++) { + key[j] = nextrand; + } + } +} +#undef nextrand + + + +/* + * Edit job codes into main command line + * %% = % + * %j = Job name + * %t = Job type (Backup, ...) + * %e = Job Exit code + * %i = JobId + * %l = job level + * %c = Client's name + * %r = Recipients + * %d = Director's name + * + * omsg = edited output message + * imsg = input string containing edit codes (%x) + * to = recepients list + * + */ +POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to) +{ + char *p, *str; + char add[20]; + + *omsg = 0; + Dmsg1(200, "edit_job_codes: %s\n", imsg); + for (p=imsg; *p; p++) { + if (*p == '%') { + switch (*++p) { + case '%': + str = "%"; + break; + case 'c': + str = jcr->client_name; + if (!str) { + str = ""; + } + break; + case 'd': + str = my_name; /* Director's name */ + break; + case 'e': + str = job_status_to_str(jcr->JobStatus); + break; + case 'i': + bsnprintf(add, sizeof(add), "%d", jcr->JobId); + str = add; + break; + case 'j': /* Job name */ + str = jcr->Job; + break; + case 'l': + str = job_level_to_str(jcr->JobLevel); + break; + case 'r': + str = to; + break; + case 't': + str = job_type_to_str(jcr->JobType); + break; + default: + add[0] = '%'; + add[1] = *p; + add[2] = 0; + str = add; + break; + } + } else { + add[0] = *p; + add[1] = 0; + str = add; + } + Dmsg1(1200, "add_str %s\n", str); + pm_strcat(&omsg, str); + Dmsg1(1200, "omsg=%s\n", omsg); + } + return omsg; +} + +void set_working_directory(char *wd) +{ + struct stat stat_buf; + + if (wd == NULL) { + Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n")); + } + if (stat(wd, &stat_buf) != 0) { + Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"), + wd); + } + if (!S_ISDIR(stat_buf.st_mode)) { + Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"), + wd); + } + working_directory = wd; /* set global */ +}