]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/util.c
Fix conio.h problem on Solaris
[bacula/bacula] / bacula / src / lib / util.c
1 /*
2  *   util.c  miscellaneous utility subroutines for Bacula
3  * 
4  *    Kern Sibbald, MM
5  *
6  *   Version $Id$
7  */
8
9 /*
10    Copyright (C) 2000-2004 Kern Sibbald and John Walker
11
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.
16
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.
21
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,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "jcr.h"
31 #include "findlib/find.h"
32
33 /*
34  * Various Bacula Utility subroutines
35  *
36  */
37
38 /* Return true of buffer has all zero bytes */
39 int is_buf_zero(char *buf, int len)
40 {
41    uint64_t *ip;
42    char *p;
43    int i, len64, done, rem;
44
45    if (buf[0] != 0) {
46       return 0;
47    }
48    ip = (uint64_t *)buf;
49    /* Optimize by checking uint64_t for zero */
50    len64 = len / sizeof(uint64_t);
51    for (i=0; i < len64; i++) {
52       if (ip[i] != 0) {
53          return 0;
54       }
55    }
56    done = len64 * sizeof(uint64_t);  /* bytes already checked */
57    p = buf + done;
58    rem = len - done;
59    for (i = 0; i < rem; i++) {
60       if (p[i] != 0) {
61          return 0;
62       }
63    }
64    return 1;
65 }
66
67
68 /* Convert a string in place to lower case */
69 void lcase(char *str)
70 {
71    while (*str) {
72       if (B_ISUPPER(*str))
73          *str = tolower((int)(*str));
74        str++;
75    }
76 }
77
78 /* Convert spaces to non-space character. 
79  * This makes scanf of fields containing spaces easier.
80  */
81 void
82 bash_spaces(char *str)
83 {
84    while (*str) {
85       if (*str == ' ')
86          *str = 0x1;
87       str++;
88    }
89 }
90
91 /* Convert non-space characters (0x1) back into spaces */
92 void
93 unbash_spaces(char *str)
94 {
95    while (*str) {
96      if (*str == 0x1)
97         *str = ' ';
98      str++;
99    }
100 }
101
102
103 char *encode_time(time_t time, char *buf)
104 {
105    struct tm tm;
106    int n = 0;
107
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);
112    }
113    return buf+n;
114 }
115
116 /*
117  * Concatenate a string (str) onto a pool memory buffer pm
118  *   Returns: length of concatenated string
119  */
120 int pm_strcat(POOLMEM **pm, const char *str)
121 {
122    int pmlen = strlen(*pm);
123    int len = strlen(str) + 1;
124
125    *pm = check_pool_memory_size(*pm, pmlen + len);
126    memcpy(*pm+pmlen, str, len);
127    return pmlen + len - 1;
128 }
129
130 int pm_strcat(POOLMEM *&pm, const char *str)
131 {
132    int pmlen = strlen(pm);
133    int len = strlen(str) + 1;
134
135    pm = check_pool_memory_size(pm, pmlen + len);
136    memcpy(pm+pmlen, str, len);
137    return pmlen + len - 1;
138 }
139
140
141
142 /*
143  * Copy a string (str) into a pool memory buffer pm
144  *   Returns: length of string copied
145  */
146 int pm_strcpy(POOLMEM **pm, const char *str)
147 {
148    int len = strlen(str) + 1;
149
150    *pm = check_pool_memory_size(*pm, len);
151    memcpy(*pm, str, len);
152    return len - 1;
153 }
154
155 int pm_strcpy(POOLMEM *&pm, const char *str)
156 {
157    int len = strlen(str) + 1;
158
159    pm = check_pool_memory_size(pm, len);
160    memcpy(pm, str, len);
161    return len - 1;
162 }
163
164
165  
166
167
168 /*
169  * Convert a JobStatus code into a human readable form
170  */
171 void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
172 {
173    const char *jobstat;
174    char buf[100];
175
176    switch (JobStatus) {
177    case JS_Created:
178       jobstat = _("Created");
179       break;
180    case JS_Running:
181       jobstat = _("Running");
182       break;
183    case JS_Blocked:
184       jobstat = _("Blocked");
185       break;
186    case JS_Terminated:
187       jobstat = _("OK");
188       break;
189    case JS_FatalError:
190    case JS_ErrorTerminated:
191       jobstat = _("Error");
192       break;
193    case JS_Error:
194       jobstat = _("Non-fatal error");
195       break;
196    case JS_Canceled:
197       jobstat = _("Canceled");
198       break;
199    case JS_Differences:
200       jobstat = _("Verify differences");
201       break;
202    case JS_WaitFD:
203       jobstat = _("Waiting on FD");
204       break;
205    case JS_WaitSD:
206       jobstat = _("Wait on SD");
207       break;
208    case JS_WaitMedia:
209       jobstat = _("Wait for new Volume");
210       break;
211    case JS_WaitMount:
212       jobstat = _("Waiting for mount");
213       break;
214    case JS_WaitStoreRes:
215       jobstat = _("Waiting for Storage resource");
216       break;
217    case JS_WaitJobRes:
218       jobstat = _("Waiting for Job resource");
219       break;
220    case JS_WaitClientRes:
221       jobstat = _("Waiting for Client resource");
222       break;
223    case JS_WaitMaxJobs:
224       jobstat = _("Waiting on Max Jobs");
225       break;
226    case JS_WaitStartTime:
227       jobstat = _("Waiting for Start Time");
228       break;
229    case JS_WaitPriority:
230       jobstat = _("Waiting on Priority");
231       break;
232
233    default:
234       if (JobStatus == 0) {
235          buf[0] = 0;
236       } else {
237          bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
238       }
239       jobstat = buf;
240       break;
241    }
242    bstrncpy(msg, jobstat, maxlen);
243 }
244
245 /*
246  * Convert Job Termination Status into a string
247  */
248 const char *job_status_to_str(int stat) 
249 {
250    const char *str;
251
252    switch (stat) {
253    case JS_Terminated:
254       str = _("OK");
255       break;
256    case JS_ErrorTerminated:
257    case JS_Error:
258       str = _("Error");
259       break;
260    case JS_FatalError:
261       str = _("Fatal Error");
262       break;
263    case JS_Canceled:
264       str = _("Canceled");
265       break;
266    case JS_Differences:
267       str = _("Differences");
268       break;
269    default:
270       str = _("Unknown term code");
271       break;
272    }
273    return str;
274 }
275
276
277 /*
278  * Convert Job Type into a string
279  */
280 const char *job_type_to_str(int type) 
281 {
282    const char *str;
283
284    switch (type) {
285    case JT_BACKUP:
286       str = _("Backup");
287       break;
288    case JT_VERIFY:
289       str = _("Verify");
290       break;
291    case JT_RESTORE:
292       str = _("Restore");
293       break;
294    case JT_ADMIN:
295       str = _("Admin");
296       break;
297    default:
298       str = _("Unknown Type");
299       break;
300    }
301    return str;
302 }
303
304 /*
305  * Convert Job Level into a string
306  */
307 const char *job_level_to_str(int level) 
308 {
309    const char *str;
310
311    switch (level) {
312    case L_BASE:
313       str = _("Base");
314    case L_FULL:
315       str = _("Full");
316       break;
317    case L_INCREMENTAL:
318       str = _("Incremental");
319       break;
320    case L_DIFFERENTIAL:
321       str = _("Differential");
322       break;
323    case L_SINCE:
324       str = _("Since");
325       break;
326    case L_VERIFY_CATALOG:
327       str = _("Verify Catalog");
328       break;
329    case L_VERIFY_INIT:
330       str = _("Verify Init Catalog");
331       break;
332    case L_VERIFY_VOLUME_TO_CATALOG:
333       str = _("Verify Volume to Catalog");
334       break;
335    case L_VERIFY_DISK_TO_CATALOG:
336       str = _("Verify Disk to Catalog");
337       break;
338    case L_VERIFY_DATA:
339       str = _("Verify Data");
340       break;
341    case L_NONE:
342       str = " ";
343       break;
344    default:
345       str = _("Unknown Job Level");
346       break;
347    }
348    return str;
349 }
350
351
352 /***********************************************************************
353  * Encode the mode bits into a 10 character string like LS does
354  ***********************************************************************/
355
356 char *encode_mode(mode_t mode, char *buf)
357 {
358   char *cp = buf;  
359
360   *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode)  ? 'b' : S_ISCHR(mode)  ? 'c' :
361           S_ISLNK(mode) ? 'l' : S_ISFIFO(mode) ? 'f' : S_ISSOCK(mode) ? 's' : '-';
362   *cp++ = mode & S_IRUSR ? 'r' : '-';
363   *cp++ = mode & S_IWUSR ? 'w' : '-';
364   *cp++ = (mode & S_ISUID
365                ? (mode & S_IXUSR ? 's' : 'S')
366                : (mode & S_IXUSR ? 'x' : '-'));
367   *cp++ = mode & S_IRGRP ? 'r' : '-';
368   *cp++ = mode & S_IWGRP ? 'w' : '-';
369   *cp++ = (mode & S_ISGID
370                ? (mode & S_IXGRP ? 's' : 'S')
371                : (mode & S_IXGRP ? 'x' : '-'));
372   *cp++ = mode & S_IROTH ? 'r' : '-';
373   *cp++ = mode & S_IWOTH ? 'w' : '-';
374   *cp++ = (mode & S_ISVTX
375                ? (mode & S_IXOTH ? 't' : 'T')
376                : (mode & S_IXOTH ? 'x' : '-'));
377   *cp = '\0';
378   return cp;
379 }
380
381
382 int do_shell_expansion(char *name, int name_len)
383 {
384    static char meta[] = "~\\$[]*?`'<>\"";
385    bool found = false;
386    int len, i, stat;
387    POOLMEM *cmd;
388    BPIPE *bpipe;
389    char line[MAXSTRING];
390    const char *shellcmd;
391
392    /* Check if any meta characters are present */
393    len = strlen(meta);
394    for (i = 0; i < len; i++) {
395       if (strchr(name, meta[i])) {
396          found = true;
397          break;
398       }
399    }
400    if (found) {
401       cmd =  get_pool_memory(PM_FNAME);
402       /* look for shell */
403       if ((shellcmd = getenv("SHELL")) == NULL) {
404          shellcmd = "/bin/sh";
405       }
406       pm_strcpy(&cmd, shellcmd);
407       pm_strcat(&cmd, " -c \"echo ");
408       pm_strcat(&cmd, name);
409       pm_strcat(&cmd, "\"");
410       Dmsg1(400, "Send: %s\n", cmd);
411       if ((bpipe = open_bpipe(cmd, 0, "r"))) {
412          *line = 0;
413          fgets(line, sizeof(line), bpipe->rfd);
414          strip_trailing_junk(line);
415          stat = close_bpipe(bpipe);
416          Dmsg2(400, "stat=%d got: %s\n", stat, line);
417       } else {
418          stat = 1;                    /* error */
419       }
420       free_pool_memory(cmd);
421       if (stat == 0) {
422          bstrncpy(name, line, name_len);
423       }
424    }
425    return 1;
426 }
427
428
429 /*  MAKESESSIONKEY  --  Generate session key with optional start
430                         key.  If mode is TRUE, the key will be
431                         translated to a string, otherwise it is
432                         returned as 16 binary bytes.
433
434     from SpeakFreely by John Walker */
435
436 void make_session_key(char *key, char *seed, int mode)
437 {
438      int j, k;
439      struct MD5Context md5c;
440      unsigned char md5key[16], md5key1[16];
441      char s[1024];
442
443      s[0] = 0;
444      if (seed != NULL) {
445         bstrncat(s, seed, sizeof(s));
446      }
447
448      /* The following creates a seed for the session key generator
449         based on a collection of volatile and environment-specific
450         information unlikely to be vulnerable (as a whole) to an
451         exhaustive search attack.  If one of these items isn't
452         available on your machine, replace it with something
453         equivalent or, if you like, just delete it. */
454
455      sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
456      sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
457      getcwd(s + strlen(s), 256);
458      sprintf(s + strlen(s), "%lu", (unsigned long)clock());
459      sprintf(s + strlen(s), "%lu", (unsigned long)time(NULL));
460 #ifdef Solaris
461      sysinfo(SI_HW_SERIAL,s + strlen(s), 12);
462 #endif
463 #ifdef HAVE_GETHOSTID
464      sprintf(s + strlen(s), "%lu", (unsigned long) gethostid());
465 #endif
466 #ifdef HAVE_GETDOMAINNAME
467      getdomainname(s + strlen(s), 256);
468 #endif
469      gethostname(s + strlen(s), 256);
470      sprintf(s + strlen(s), "%u", (unsigned)getuid());
471      sprintf(s + strlen(s), "%u", (unsigned)getgid());
472      MD5Init(&md5c);
473      MD5Update(&md5c, (unsigned char *)s, strlen(s));
474      MD5Final(md5key, &md5c);
475      sprintf(s + strlen(s), "%lu", (unsigned long)((time(NULL) + 65121) ^ 0x375F));
476      MD5Init(&md5c);
477      MD5Update(&md5c, (unsigned char *)s, strlen(s));
478      MD5Final(md5key1, &md5c);
479 #define nextrand    (md5key[j] ^ md5key1[j])
480      if (mode) {
481         for (j = k = 0; j < 16; j++) {
482            unsigned char rb = nextrand;
483
484 #define Rad16(x) ((x) + 'A')
485            key[k++] = Rad16((rb >> 4) & 0xF);
486            key[k++] = Rad16(rb & 0xF);
487 #undef Rad16
488            if (j & 1) {
489               key[k++] = '-';
490            }
491         }
492         key[--k] = 0;
493      } else {
494         for (j = 0; j < 16; j++) {
495            key[j] = nextrand;
496         }
497      }
498 }
499 #undef nextrand
500
501
502
503 /*
504  * Edit job codes into main command line
505  *  %% = %
506  *  %c = Client's name
507  *  %d = Director's name
508  *  %e = Job Exit code
509  *  %i = JobId
510  *  %j = Unique Job name
511  *  %l = job level
512  *  %n = Unadorned Job name
513  *  %t = Job type (Backup, ...)
514  *  %r = Recipients
515  *  %v = Volume name
516  *
517  *  omsg = edited output message
518  *  imsg = input string containing edit codes (%x)
519  *  to = recepients list 
520  *
521  */
522 POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, const char *to)   
523 {
524    char *p, *q;
525    const char *str;
526    char add[20];
527    char name[MAX_NAME_LENGTH];
528    int i;
529
530    *omsg = 0;
531    Dmsg1(200, "edit_job_codes: %s\n", imsg);
532    for (p=imsg; *p; p++) {
533       if (*p == '%') {
534          switch (*++p) {
535          case '%':
536             str = "%";
537             break;
538          case 'c':
539             str = jcr->client_name;
540             if (!str) {
541                str = "";
542             }
543             break;
544          case 'd':
545             str = my_name;            /* Director's name */
546             break;
547          case 'e':
548             str = job_status_to_str(jcr->JobStatus); 
549             break;
550          case 'i':
551             bsnprintf(add, sizeof(add), "%d", jcr->JobId);
552             str = add;
553             break;
554          case 'j':                    /* Job name */
555             str = jcr->Job;
556             break;
557          case 'l':
558             str = job_level_to_str(jcr->JobLevel);
559             break;
560          case 'n':
561              bstrncpy(name, jcr->Job, sizeof(name));
562              /* There are three periods after the Job name */
563              for (i=0; i<3; i++) {
564                 if ((q=strrchr(name, '.')) != NULL) {
565                     *q = 0;
566                 }
567              }
568              str = name;
569              break;
570          case 'r':
571             str = to;
572             break;
573          case 't':
574             str = job_type_to_str(jcr->JobType);
575             break;
576          case 'v':
577             if (jcr->VolumeName && jcr->VolumeName[0]) {
578                str = jcr->VolumeName;
579             } else {
580                str = "";
581             }
582             break;
583          default:
584             add[0] = '%';
585             add[1] = *p;
586             add[2] = 0;
587             str = add;
588             break;
589          }
590       } else {
591          add[0] = *p;
592          add[1] = 0;
593          str = add;
594       }
595       Dmsg1(1200, "add_str %s\n", str);
596       pm_strcat(&omsg, str);
597       Dmsg1(1200, "omsg=%s\n", omsg);
598    }
599    return omsg;
600 }
601
602 void set_working_directory(char *wd)
603 {
604    struct stat stat_buf; 
605
606    if (wd == NULL) {
607       Emsg0(M_ERROR_TERM, 0, _("Working directory not defined. Cannot continue.\n"));
608    }
609    if (stat(wd, &stat_buf) != 0) {
610       Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
611          wd);
612    }
613    if (!S_ISDIR(stat_buf.st_mode)) {
614       Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
615          wd);
616    }
617    working_directory = wd;            /* set global */
618 }