X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Futil.c;h=5d3bffa30afa8ee894efd1cbf7e0ee21ba7caeb8;hb=74de3a7b8c973e2206ecfceed422fbae821965cf;hp=63a71911f4ad3d2e941fee74cd9b1c4cdf53820a;hpb=458061b568c4451c7f1d2212879645b2625651fb;p=bacula%2Fbacula diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 63a71911f4..5d3bffa30a 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -1,29 +1,36 @@ /* - * util.c miscellaneous utility subroutines for Bacula - * - * Kern Sibbald, MM - * - * Version $Id$ - */ + Bacula® - The Network Backup Solution -/* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2000-2009 Free Software Foundation Europe e.V. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * util.c miscellaneous utility subroutines for Bacula + * + * Kern Sibbald, MM + * + * Version $Id$ */ #include "bacula.h" @@ -36,28 +43,32 @@ */ /* Return true of buffer has all zero bytes */ -int is_buf_zero(char *buf, int len) +bool is_buf_zero(char *buf, int len) { - uint64_t *ip = (uint64_t *)buf; + uint64_t *ip; char *p; int i, len64, done, rem; + if (buf[0] != 0) { + return false; + } + ip = (uint64_t *)buf; /* Optimize by checking uint64_t for zero */ - len64 = len >> sizeof(uint64_t); + len64 = len / sizeof(uint64_t); for (i=0; i < len64; i++) { if (ip[i] != 0) { - return 0; + return false; } } - done = len64 << sizeof(uint64_t); /* bytes already checked */ + 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; + return false; } } - return 1; + return true; } @@ -65,13 +76,14 @@ int is_buf_zero(char *buf, int len) void lcase(char *str) { while (*str) { - if (B_ISUPPER(*str)) - *str = tolower((int)(*str)); + if (B_ISUPPER(*str)) { + *str = tolower((int)(*str)); + } str++; } } -/* Convert spaces to non-space character. +/* Convert spaces to non-space character. * This makes scanf of fields containing spaces easier. */ void @@ -79,11 +91,26 @@ bash_spaces(char *str) { while (*str) { if (*str == ' ') - *str = 0x1; + *str = 0x1; + str++; + } +} + +/* Convert spaces to non-space character. + * This makes scanf of fields containing spaces easier. + */ +void +bash_spaces(POOL_MEM &pm) +{ + char *str = pm.c_str(); + while (*str) { + if (*str == ' ') + *str = 0x1; str++; } } + /* Convert non-space characters (0x1) back into spaces */ void unbash_spaces(char *str) @@ -95,179 +122,207 @@ unbash_spaces(char *str) } } -/* Strip any trailing junk from the command */ -void strip_trailing_junk(char *cmd) -{ - char *p; - p = cmd + strlen(cmd) - 1; - - /* strip trailing junk from command */ - while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) - *p-- = 0; -} - -/* Strip any trailing slashes from a directory path */ -void strip_trailing_slashes(char *dir) -{ - char *p; - p = dir + strlen(dir) - 1; - - /* strip trailing slashes */ - while ((p >= dir) && (*p == '/')) - *p-- = 0; -} - -/* - * Skip spaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter - */ -int skip_spaces(char **msg) +/* Convert non-space characters (0x1) back into spaces */ +void +unbash_spaces(POOL_MEM &pm) { - char *p = *msg; - if (!p) { - return 0; - } - while (*p && *p == ' ') { - p++; + char *str = pm.c_str(); + while (*str) { + if (*str == 0x1) + *str = ' '; + str++; } - *msg = p; - return *p ? 1 : 0; } -/* - * Skip nonspaces - * Returns: 0 on failure (EOF) - * 1 on success - * new address in passed parameter - */ -int skip_nonspaces(char **msg) +char *encode_time(utime_t utime, char *buf) { - char *p = *msg; - - if (!p) { - return 0; - } - while (*p && *p != ' ') { - p++; + struct tm tm; + int n = 0; + time_t time = utime; + +#if defined(HAVE_WIN32) + /* + * Avoid a seg fault in Microsoft's CRT localtime_r(), + * which incorrectly references a NULL returned from gmtime() if + * time is negative before or after the timezone adjustment. + */ + struct tm *gtm; + + if ((gtm = gmtime(&time)) == NULL) { + return buf; } - *msg = p; - return *p ? 1 : 0; -} -/* folded search for string - case insensitive */ -int -fstrsch(char *a, char *b) /* folded case search */ -{ - 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 */ + if (gtm->tm_year == 1970 && gtm->tm_mon == 1 && gtm->tm_mday < 3) { + return buf; } - while (*a) { /* do it over the correct slow way */ - if (B_ISUPPER(c1 = *a)) { - c1 = tolower((int)c1); - } - if (B_ISUPPER(c2 = *b)) { - c2 = tolower((int)c2); - } - if (c1 != c2) { - return 0; - } - a++; - b++; - } - return 1; -} - - -char *encode_time(time_t time, char *buf) -{ - struct tm tm; - int n = 0; +#endif 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); + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); } return buf+n; } -/* - * Concatenate a string (str) onto a pool memory buffer pm - */ -void pm_strcat(POOLMEM **pm, char *str) -{ - int pmlen = strlen(*pm); - int len = strlen(str) + 1; - - *pm = check_pool_memory_size(*pm, pmlen + len); - memcpy(*pm+pmlen, str, len); -} /* - * Copy a string (str) into a pool memory buffer pm + * Convert a JobStatus code into a human readable form */ -void pm_strcpy(POOLMEM **pm, char *str) +void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen) { - int len = strlen(str) + 1; + const char *jobstat; + char buf[100]; - *pm = check_pool_memory_size(*pm, len); - memcpy(*pm, str, len); -} + switch (JobStatus) { + case JS_Created: + jobstat = _("Created"); + break; + case JS_Running: + jobstat = _("Running"); + break; + case JS_Blocked: + jobstat = _("Blocked"); + break; + case JS_Terminated: + jobstat = _("OK"); + break; + case JS_FatalError: + case JS_ErrorTerminated: + jobstat = _("Error"); + break; + case JS_Error: + jobstat = _("Non-fatal error"); + break; + case JS_Warnings: + jobstat = _("OK -- with warnings"); + break; + case JS_Canceled: + jobstat = _("Canceled"); + break; + case JS_Differences: + jobstat = _("Verify differences"); + break; + case JS_WaitFD: + jobstat = _("Waiting on FD"); + break; + case JS_WaitSD: + jobstat = _("Wait on SD"); + break; + case JS_WaitMedia: + jobstat = _("Wait for new Volume"); + break; + case JS_WaitMount: + jobstat = _("Waiting for mount"); + break; + case JS_WaitStoreRes: + jobstat = _("Waiting for Storage resource"); + break; + case JS_WaitJobRes: + jobstat = _("Waiting for Job resource"); + break; + case JS_WaitClientRes: + jobstat = _("Waiting for Client resource"); + break; + case JS_WaitMaxJobs: + jobstat = _("Waiting on Max Jobs"); + break; + case JS_WaitStartTime: + jobstat = _("Waiting for Start Time"); + break; + case JS_WaitPriority: + jobstat = _("Waiting on Priority"); + break; + case JS_DataCommitting: + jobstat = _("SD committing Data"); + break; + case JS_DataDespooling: + jobstat = _("SD despooling Data"); + break; + case JS_AttrDespooling: + jobstat = _("SD despooling Attributes"); + break; + case JS_AttrInserting: + jobstat = _("Dir inserting Attributes"); + break; + default: + if (JobStatus == 0) { + buf[0] = 0; + } else { + bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus); + } + jobstat = buf; + break; + } + bstrncpy(msg, jobstat, maxlen); +} /* - * Convert a JobStatus code into a human readable form + * Convert a JobStatus code into a human readable form - gui version */ -void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen) +void jobstatus_to_ascii_gui(int JobStatus, char *msg, int maxlen) { - char *termstat, jstat[2]; - + const char *cnv = NULL; 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; + case JS_Terminated: + cnv = _("Completed successfully"); + break; + case JS_Warnings: + cnv = _("Completed with warnings"); + break; + case JS_ErrorTerminated: + cnv = _("Terminated with errors"); + break; + case JS_FatalError: + cnv = _("Fatal error"); + break; + case JS_Created: + cnv = _("Created, not yet running"); + break; + case JS_Canceled: + cnv = _("Canceled by user"); + break; + case JS_Differences: + cnv = _("Verify found differences"); + break; + case JS_WaitFD: + cnv = _("Waiting for File daemon"); + break; + case JS_WaitSD: + cnv = _("Waiting for Storage daemon"); + break; + case JS_WaitPriority: + cnv = _("Waiting for higher priority jobs"); + break; + case JS_AttrInserting: + cnv = _("Batch inserting file records"); + break; + }; + + if (cnv) { + bstrncpy(msg, cnv, maxlen); + } else { + jobstatus_to_ascii(JobStatus, msg, maxlen); } - bstrncpy(msg, termstat, maxlen); } + /* * Convert Job Termination Status into a string */ -char *job_status_to_str(int stat) +const char *job_status_to_str(int stat) { - char *str; + const char *str; switch (stat) { case JS_Terminated: str = _("OK"); break; + case JS_Warnings: + str = _("OK -- with warnings"); + break; case JS_ErrorTerminated: case JS_Error: str = _("Error"); @@ -292,9 +347,9 @@ char *job_status_to_str(int stat) /* * Convert Job Type into a string */ -char *job_type_to_str(int type) +const char *job_type_to_str(int type) { - char *str; + const char *str; switch (type) { case JT_BACKUP: @@ -309,6 +364,24 @@ char *job_type_to_str(int type) case JT_ADMIN: str = _("Admin"); break; + case JT_MIGRATE: + str = _("Migrate"); + break; + case JT_COPY: + str = _("Copy"); + break; + case JT_JOB_COPY: + str = _("Job Copy"); + break; + case JT_CONSOLE: + str = _("Console"); + break; + case JT_SYSTEM: + str = _("System or Console"); + break; + case JT_SCAN: + str = _("Scan"); + break; default: str = _("Unknown Type"); break; @@ -319,9 +392,9 @@ char *job_type_to_str(int type) /* * Convert Job Level into a string */ -char *job_level_to_str(int level) +const char *job_level_to_str(int level) { - char *str; + const char *str; switch (level) { case L_BASE: @@ -347,9 +420,18 @@ char *job_level_to_str(int level) case L_VERIFY_VOLUME_TO_CATALOG: str = _("Verify Volume to Catalog"); break; + case L_VERIFY_DISK_TO_CATALOG: + str = _("Verify Disk to Catalog"); + break; case L_VERIFY_DATA: str = _("Verify Data"); break; + case L_VIRTUAL_FULL: + str = _("Virtual Full"); + break; + case L_NONE: + str = " "; + break; default: str = _("Unknown Job Level"); break; @@ -357,6 +439,33 @@ char *job_level_to_str(int level) return str; } +const char *volume_status_to_str(const char *status) +{ + int pos; + const char *vs[] = { + NT_("Append"), _("Append"), + NT_("Archive"), _("Archive"), + NT_("Disabled"), _("Disabled"), + NT_("Full"), _("Full"), + NT_("Used"), _("Used"), + NT_("Cleaning"), _("Cleaning"), + NT_("Purged"), _("Purged"), + NT_("Recycle"), _("Recycle"), + NT_("Read-Only"), _("Read-Only"), + NT_("Error"), _("Error"), + NULL, NULL}; + + if (status) { + for (pos = 0 ; vs[pos] ; pos += 2) { + if ( !strcmp(vs[pos],status) ) { + return vs[pos+1]; + } + } + } + + return _("Invalid volume status"); +} + /*********************************************************************** * Encode the mode bits into a 10 character string like LS does @@ -364,7 +473,7 @@ char *job_level_to_str(int level) char *encode_mode(mode_t mode, char *buf) { - char *cp = buf; + char *cp = buf; *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' : '-'; @@ -387,258 +496,330 @@ char *encode_mode(mode_t mode, char *buf) return cp; } - -int do_shell_expansion(char *name) +#if defined(HAVE_WIN32) +int do_shell_expansion(char *name, int name_len) { -/* ****FIXME***** this should work for Win32 too */ -#define UNIX -#ifdef UNIX -#ifndef PATH_MAX -#define PATH_MAX 512 -#endif + char *src = bstrdup(name); - int pid, wpid, stat; - int waitstatus; - char *shellcmd; - int i; - char echout[PATH_MAX + 256]; - int pfd[2]; + ExpandEnvironmentStrings(src, name, name_len); + + free(src); + + return 1; +} +#else +int do_shell_expansion(char *name, int name_len) +{ static char meta[] = "~\\$[]*?`'<>\""; - int found = FALSE; - int len; + bool found = false; + int len, i, stat; + POOLMEM *cmd; + BPIPE *bpipe; + char line[MAXSTRING]; + const char *shellcmd; /* Check if any meta characters are present */ len = strlen(meta); for (i = 0; i < len; i++) { if (strchr(name, meta[i])) { - found = TRUE; - break; + found = true; + break; } } - stat = 0; if (found) { -#ifdef nt - /* If the filename appears to be a DOS filename, - convert all backward slashes \ to Unix path - separators / and insert a \ infront of spaces. */ - len = strlen(name); - if (len >= 3 && name[1] == ':' && name[2] == '\\') { - for (i=2; 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 */ - } - } - } - /* wait for child to exit */ - while ((wpid = wait(&waitstatus)) != pid && wpid != -1) - { ; } - strcpy(name, echout); - stat = 1; - break; - } - close(pfd[0]); /* close pipe */ - close(pfd[1]); -#endif /* nt */ - } - return stat; - -#endif /* UNIX */ - -#if MSC | MSDOS | __WATCOMC__ - - char prefix[100], *env, *getenv(); - - /* Home directory reference? */ - if (*name == '~' && (env=getenv("HOME"))) { - strcpy(prefix, env); /* copy HOME directory name */ - name++; /* skip over ~ in name */ - strcat(prefix, name); - name--; /* get back to beginning */ - strcpy(name, prefix); /* move back into name */ + cmd = get_pool_memory(PM_FNAME); + /* look for shell */ + if ((shellcmd = getenv("SHELL")) == NULL) { + shellcmd = "/bin/sh"; + } + pm_strcpy(&cmd, shellcmd); + pm_strcat(&cmd, " -c \"echo "); + pm_strcat(&cmd, name); + pm_strcat(&cmd, "\""); + Dmsg1(400, "Send: %s\n", cmd); + if ((bpipe = open_bpipe(cmd, 0, "r"))) { + *line = 0; + fgets(line, sizeof(line), bpipe->rfd); + strip_trailing_junk(line); + stat = close_bpipe(bpipe); + Dmsg2(400, "stat=%d got: %s\n", stat, line); + } else { + stat = 1; /* error */ + } + free_pool_memory(cmd); + if (stat == 0) { + bstrncpy(name, line, name_len); + } } return 1; -#endif - } +#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. +/* 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 makeSessionKey(char *key, char *seed, int mode) +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); - } + int j, k; + struct MD5Context md5c; + unsigned char md5key[16], md5key1[16]; + char s[1024]; + +#define ss sizeof(s) + + s[0] = 0; + if (seed != NULL) { + bstrncat(s, seed, sizeof(s)); + } - /* 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); + /* 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. */ + +#if defined(HAVE_WIN32) + { + LARGE_INTEGER li; + DWORD length; + FILETIME ft; + char *p; + + p = s; + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)GetCurrentProcessId()); + (void)getcwd(s + strlen(s), 256); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)GetTickCount()); + QueryPerformanceCounter(&li); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)li.LowPart); + GetSystemTimeAsFileTime(&ft); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)ft.dwLowDateTime); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)ft.dwHighDateTime); + length = 256; + GetComputerName(s + strlen(s), &length); + length = 256; + GetUserName(s + strlen(s), &length); + } +#else + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getpid()); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getppid()); + (void)getcwd(s + strlen(s), 256); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)clock()); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)time(NULL)); +#if defined(Solaris) + sysinfo(SI_HW_SERIAL,s + strlen(s), 12); #endif -#ifdef HAVE_GETHOSTID - sprintf(s + strlen(s), "%lu", (unsigned long) gethostid()); +#if defined(HAVE_GETHOSTID) + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t) gethostid()); #endif -#ifdef HAVE_GETDOMAINNAME - getdomainname(s + strlen(s), 256); + gethostname(s + strlen(s), 256); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getuid()); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getgid()); #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); + MD5Init(&md5c); + MD5Update(&md5c, (uint8_t *)s, strlen(s)); + MD5Final(md5key, &md5c); + bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)((time(NULL) + 65121) ^ 0x375F)); + MD5Init(&md5c); + MD5Update(&md5c, (uint8_t *)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; + 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); + 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; - } + if (j & 1) { + key[k++] = '-'; + } + } + key[--k] = 0; + } else { + for (j = 0; j < 16; j++) { + key[j] = nextrand; } + } } #undef nextrand +void encode_session_key(char *encode, char *session, char *key, int maxlen) +{ + int i; + for (i=0; (i < maxlen-1) && session[i]; i++) { + if (session[i] == '-') { + encode[i] = '-'; + } else { + encode[i] = ((session[i] - 'A' + key[i]) & 0xF) + 'A'; + } + } + encode[i] = 0; + Dmsg3(000, "Session=%s key=%s encode=%s\n", session, key, encode); +} + +void decode_session_key(char *decode, char *session, char *key, int maxlen) +{ + int i, x; + + for (i=0; (i < maxlen-1) && session[i]; i++) { + if (session[i] == '-') { + decode[i] = '-'; + } else { + x = (session[i] - 'A' - key[i]) & 0xF; + if (x < 0) { + x += 16; + } + decode[i] = x + 'A'; + } + } + decode[i] = 0; + Dmsg3(000, "Session=%s key=%s decode=%s\n", session, key, decode); +} + /* * Edit job codes into main command line * %% = % - * %j = Job name - * %t = Job type (Backup, ...) + * %c = Client's name + * %d = Director's name * %e = Job Exit code * %i = JobId + * %j = Unique Job id * %l = job level - * %c = Client's name + * %n = Unadorned Job name + * %s = Since time + * %t = Job type (Backup, ...) * %r = Recipients - * %d = Director's name + * %v = Volume name * * omsg = edited output message * imsg = input string containing edit codes (%x) - * to = recepients list + * to = recepients list * */ -POOLMEM *edit_job_codes(void *mjcr, char *omsg, char *imsg, char *to) +POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to, job_code_callback_t callback) { - char *p, *str; + char *p, *q; + const char *str; char add[20]; - JCR *jcr = (JCR *)mjcr; + char name[MAX_NAME_LENGTH]; + int i; *omsg = 0; Dmsg1(200, "edit_job_codes: %s\n", imsg); for (p=imsg; *p; p++) { if (*p == '%') { - switch (*++p) { + switch (*++p) { case '%': str = "%"; - break; + break; case 'c': - str = jcr->client_name; - if (!str) { - str = ""; - } - break; + if (jcr) { + str = jcr->client_name; + } else { + str = _("*none*"); + } + break; case 'd': str = my_name; /* Director's name */ - break; + break; case 'e': - str = job_status_to_str(jcr->JobStatus); - break; + if (jcr) { + str = job_status_to_str(jcr->JobStatus); + } else { + str = _("*none*"); + } + break; case 'i': - sprintf(add, "%d", jcr->JobId); - str = add; - break; + if (jcr) { + bsnprintf(add, sizeof(add), "%d", jcr->JobId); + str = add; + } else { + str = _("*none*"); + } + break; case 'j': /* Job name */ - str = jcr->Job; - break; + if (jcr) { + str = jcr->Job; + } else { + str = _("*none*"); + } + break; case 'l': - str = job_level_to_str(jcr->JobLevel); - break; + if (jcr) { + str = job_level_to_str(jcr->get_JobLevel()); + } else { + str = _("*none*"); + } + break; + case 'n': + if (jcr) { + bstrncpy(name, jcr->Job, sizeof(name)); + /* There are three periods after the Job name */ + for (i=0; i<3; i++) { + if ((q=strrchr(name, '.')) != NULL) { + *q = 0; + } + } + str = name; + } else { + str = _("*none*"); + } + break; case 'r': - str = to; - break; + str = to; + break; + case 's': /* since time */ + if (jcr && jcr->stime) { + str = jcr->stime; + } else { + str = _("*none*"); + } + break; case 't': - str = job_type_to_str(jcr->JobType); - break; - default: - add[0] = '%'; - add[1] = *p; - add[2] = 0; - str = add; - break; - } + if (jcr) { + str = job_type_to_str(jcr->get_JobType()); + } else { + str = _("*none*"); + } + break; + case 'v': + if (jcr) { + if (jcr->VolumeName && jcr->VolumeName[0]) { + str = jcr->VolumeName; + } else { + str = ""; + } + } else { + str = _("*none*"); + } + break; + default: + str = NULL; + if (callback != NULL) { + str = callback(jcr, p); + } + + if (!str) { + add[0] = '%'; + add[1] = *p; + add[2] = 0; + str = add; + } + break; + } } else { - add[0] = *p; - add[1] = 0; - str = add; + add[0] = *p; + add[1] = 0; + str = add; } Dmsg1(1200, "add_str %s\n", str); pm_strcat(&omsg, str); @@ -647,119 +828,32 @@ POOLMEM *edit_job_codes(void *mjcr, char *omsg, char *imsg, char *to) return omsg; } -/* - * Return next argument from command line. Note, this - * routine is destructive. - */ -char *next_arg(char **s) +void set_working_directory(char *wd) { - char *p, *q, *n; - int in_quote = 0; - - /* skip past spaces to next arg */ - for (p=*s; *p && *p == ' '; ) { - p++; - } - Dmsg1(400, "Next arg=%s\n", p); - for (n = q = p; *p ; ) { - if (*p == '\\') { - p++; - if (*p) { - *q++ = *p++; - } else { - *q++ = *p; - } - continue; - } - if (*p == '"') { /* start or end of quote */ - if (in_quote) { - p++; /* skip quote */ - in_quote = 0; - continue; - } - in_quote = 1; - p++; - continue; - } - if (!in_quote && *p == ' ') { /* end of field */ - p++; - break; - } - *q++ = *p++; - } - *q = 0; - *s = p; - Dmsg2(400, "End arg=%s next=%s\n", n, p); - return n; -} + struct stat stat_buf; -/* - * This routine parses the input command line. - * It makes a copy in args, then builds an - * argc, argv like list where - * - * argc = count of arguments - * argk[i] = argument keyword (part preceding =) - * argv[i] = argument value (part after =) - * - * example: arg1 arg2=abc arg3= - * - * argc = c - * argk[0] = arg1 - * argv[0] = NULL - * argk[1] = arg2 - * argv[1] = abc - * argk[2] = arg3 - * argv[2] = - */ + 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 */ +} -void parse_command_args(POOLMEM *cmd, POOLMEM *args, int *argc, - char **argk, char **argv) +const char *last_path_separator(const char *str) { - char *p, *q, *n; - int len; - - len = strlen(cmd) + 1; - args = check_pool_memory_size(args, len); - bstrncpy(args, cmd, len); - strip_trailing_junk(args); - *argc = 0; - p = args; - /* Pick up all arguments */ - while (*argc < MAX_CMD_ARGS) { - n = next_arg(&p); - if (*n) { - argk[*argc] = n; - argv[(*argc)++] = NULL; - } else { - break; - } - } - /* Separate keyword and value */ - for (int i=0; i < *argc; i++) { - p = strchr(argk[i], '='); - if (p) { - *p++ = 0; /* terminate keyword and point to value */ - /* Unquote quoted values */ - if (*p == '"') { - for (n = q = ++p; *p && *p != '"'; ) { - if (*p == '\\') { - p++; - } - *q++ = *p++; - } - *q = 0; /* terminate string */ - p = n; /* point to string */ - } - if (strlen(p) > MAX_NAME_LENGTH-1) { - p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */ - } + if (*str != '\0') { + for (const char *p = &str[strlen(str) - 1]; p >= str; p--) { + if (IsPathSeparator(*p)) { + return p; + } } - argv[i] = p; /* save ptr to value or NULL */ - } -#ifdef xxxx - for (i=0; i