1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Miscellaneous BAREOS memory and thread safe routines
25  * Generally, these are interfaces to system or standard
26  * library routines.
27  *
28  * BAREOS utility functions are in util.c
29  */
30 
31 #include "include/bareos.h"
32 #ifndef HAVE_REGEX_H
33 #include "lib/bregex.h"
34 #else
35 #include <regex.h>
36 #endif
37 
38 static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
39 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
40 static const char *secure_erase_cmdline = NULL;
41 
42 /*
43  * This routine is a somewhat safer unlink in that it
44  * allows you to run a regex on the filename before
45  * excepting it. It also requires the file to be in
46  * the working directory.
47  */
SaferUnlink(const char * pathname,const char * regx)48 int SaferUnlink(const char *pathname, const char *regx)
49 {
50    int rc;
51    regex_t preg1;
52    char prbuf[500];
53    int rtn;
54 
55    /*
56     * Name must start with working directory
57     */
58    if (strncmp(pathname, working_directory, strlen(working_directory)) != 0) {
59       Pmsg1(000, "Safe_unlink excluded: %s\n", pathname);
60       return EROFS;
61    }
62 
63    /*
64     * Compile regex expression
65     */
66    rc = regcomp(&preg1, regx, REG_EXTENDED);
67    if (rc != 0) {
68       regerror(rc, &preg1, prbuf, sizeof(prbuf));
69       Pmsg2(000,  _("safe_unlink could not compile regex pattern \"%s\" ERR=%s\n"),
70            regx, prbuf);
71       return ENOENT;
72    }
73 
74    /*
75     * Unlink files that match regexes
76     */
77    if (regexec(&preg1, pathname, 0, NULL, 0) == 0) {
78       Dmsg1(100, "safe_unlink unlinking: %s\n", pathname);
79       rtn = SecureErase(NULL, pathname);
80    } else {
81       Pmsg2(000, "safe_unlink regex failed: regex=%s file=%s\n", regx, pathname);
82       rtn = EROFS;
83    }
84    regfree(&preg1);
85 
86    return rtn;
87 }
88 
89 /*
90  * This routine will use an external secure erase program to delete a file.
91  */
SecureErase(JobControlRecord * jcr,const char * pathname)92 int SecureErase(JobControlRecord *jcr, const char *pathname)
93 {
94    int retval = -1;
95 
96    if (secure_erase_cmdline) {
97       int status;
98       Bpipe *bpipe;
99       PoolMem line(PM_NAME),
100                cmdline(PM_MESSAGE);
101 
102       Mmsg(cmdline,"%s \"%s\"", secure_erase_cmdline, pathname);
103       if (jcr) {
104          Jmsg(jcr, M_INFO, 0, _("SecureErase: executing %s\n"), cmdline.c_str());
105       }
106 
107       bpipe = OpenBpipe(cmdline.c_str(), 0, "r");
108       if (bpipe == NULL) {
109          BErrNo be;
110 
111          if (jcr) {
112             Jmsg(jcr, M_FATAL, 0, _("SecureErase: %s could not execute. ERR=%s\n"),
113                  secure_erase_cmdline, be.bstrerror());
114          }
115          goto bail_out;
116       }
117 
118       while (fgets(line.c_str(), line.size(), bpipe->rfd)) {
119          StripTrailingJunk(line.c_str());
120          if (jcr) {
121             Jmsg(jcr, M_INFO, 0, _("SecureErase: %s\n"), line.c_str());
122          }
123       }
124 
125       status = CloseBpipe(bpipe);
126       if (status != 0) {
127          BErrNo be;
128 
129          if (jcr) {
130             Jmsg(jcr, M_FATAL, 0, _("SecureErase: %s returned non-zero status=%d. ERR=%s\n"),
131                  secure_erase_cmdline, be.code(status), be.bstrerror(status));
132          }
133          goto bail_out;
134       }
135 
136       Dmsg0(100, "wpipe_command OK\n");
137       retval = 0;
138    } else {
139       retval = unlink(pathname);
140    }
141 
142    return retval;
143 
144 bail_out:
145    errno = EROFS;
146    return retval;
147 }
148 
SetSecureEraseCmdline(const char * cmdline)149 void SetSecureEraseCmdline(const char *cmdline)
150 {
151    secure_erase_cmdline = cmdline;
152 }
153 
154 /*
155  * This routine will sleep (sec, microsec).  Note, however, that if a
156  * signal occurs, it will return early.  It is up to the caller
157  * to recall this routine if he/she REALLY wants to sleep the
158  * requested time.
159  */
Bmicrosleep(int32_t sec,int32_t usec)160 int Bmicrosleep(int32_t sec, int32_t usec)
161 {
162    struct timespec timeout;
163    struct timeval tv;
164    struct timezone tz;
165    int status;
166 
167    timeout.tv_sec = sec;
168    timeout.tv_nsec = usec * 1000;
169 
170 #ifdef HAVE_NANOSLEEP
171    status = nanosleep(&timeout, NULL);
172    if (!(status < 0 && errno == ENOSYS)) {
173       return status;
174    }
175    /*
176     * If we reach here it is because nanosleep is not supported by the OS
177     */
178 #endif
179 
180    /*
181     * Do it the old way
182     */
183    gettimeofday(&tv, &tz);
184    timeout.tv_nsec += tv.tv_usec * 1000;
185    timeout.tv_sec += tv.tv_sec;
186    while (timeout.tv_nsec >= 1000000000) {
187       timeout.tv_nsec -= 1000000000;
188       timeout.tv_sec++;
189    }
190 
191    Dmsg2(200, "pthread_cond_timedwait sec=%lld usec=%d\n", sec, usec);
192 
193    /*
194     * Note, this unlocks mutex during the sleep
195     */
196    P(timer_mutex);
197    status = pthread_cond_timedwait(&timer, &timer_mutex, &timeout);
198    V(timer_mutex);
199 
200    return status;
201 }
202 
203 /*
204  * Copy a string inline from one point in the same string
205  * to another.
206  */
bstrinlinecpy(char * dest,const char * src)207 char *bstrinlinecpy(char *dest, const char *src)
208 {
209    int len;
210 
211    /*
212     * Sanity check. We can only inline copy if the src > dest
213     * otherwise the resulting copy will overwrite the end of
214     * the string.
215     */
216    if (src <= dest) {
217       return NULL;
218    }
219 
220    len = strlen(src);
221 #if HAVE_BCOPY
222    /*
223     * Cannot use strcpy or memcpy as those functions are not
224     * allowed on overlapping data and this is inline replacement
225     * for sure is. So we use bcopy which is allowed on overlapping
226     * data.
227     */
228    bcopy(src, dest, len + 1);
229 #else
230    /*
231     * Cannot use strcpy or memcpy as those functions are not
232     * allowed on overlapping data and this is inline replacement
233     * for sure is. So we use memmove which is allowed on
234     * overlapping data.
235     */
236    memmove(dest, src, len + 1);
237 #endif
238    return dest;
239 }
240 
241 /*
242  * Guarantee that the string is properly terminated
243  */
bstrncpy(char * dest,const char * src,int maxlen)244 char *bstrncpy(char *dest, const char *src, int maxlen)
245 {
246    strncpy(dest, src, maxlen - 1);
247    dest[maxlen - 1] = 0;
248    return dest;
249 }
250 
251 /*
252  * Guarantee that the string is properly terminated
253  */
bstrncpy(char * dest,PoolMem & src,int maxlen)254 char *bstrncpy(char *dest, PoolMem &src, int maxlen)
255 {
256    strncpy(dest, src.c_str(), maxlen - 1);
257    dest[maxlen - 1] = 0;
258    return dest;
259 }
260 
261 /*
262  * Note: Here the maxlen is the maximum length permitted
263  *  stored in dest, while on Unix systems, it is the maximum characters
264  *  that may be copied from src.
265  */
bstrncat(char * dest,const char * src,int maxlen)266 char *bstrncat(char *dest, const char *src, int maxlen)
267 {
268    int len = strlen(dest);
269    if (len < maxlen - 1) {
270       strncpy(dest + len, src, maxlen - len - 1);
271    }
272    dest[maxlen - 1] = 0;
273    return dest;
274 }
275 
276 /*
277  * Note: Here the maxlen is the maximum length permitted
278  *  stored in dest, while on Unix systems, it is the maximum characters
279  *  that may be copied from src.
280  */
bstrncat(char * dest,PoolMem & src,int maxlen)281 char *bstrncat(char *dest, PoolMem &src, int maxlen)
282 {
283    int len = strlen(dest);
284    if (len < maxlen - 1) {
285       strncpy(dest + len, src.c_str(), maxlen - (len + 1));
286    }
287    dest[maxlen - 1] = 0;
288    return dest;
289 }
290 
291 /*
292  * Allows one or both pointers to be NULL
293  */
bstrcmp(const char * s1,const char * s2)294 bool bstrcmp(const char *s1, const char *s2)
295 {
296    if (s1 == s2) return true;
297    if (s1 == NULL || s2 == NULL) return false;
298    return strcmp(s1, s2) == 0;
299 }
300 
bstrncmp(const char * s1,const char * s2,int n)301 bool bstrncmp(const char *s1, const char *s2, int n)
302 {
303    if (s1 == s2) return true;
304    if (s1 == NULL || s2 == NULL) return false;
305    return strncmp(s1, s2, n) == 0;
306 }
307 
Bstrcasecmp(const char * s1,const char * s2)308 bool Bstrcasecmp(const char *s1, const char *s2)
309 {
310    if (s1 == s2) return true;
311    if (s1 == NULL || s2 == NULL) return false;
312    return strcasecmp(s1, s2) == 0;
313 }
314 
bstrncasecmp(const char * s1,const char * s2,int n)315 bool bstrncasecmp(const char *s1, const char *s2, int n)
316 {
317    if (s1 == s2) return true;
318    if (s1 == NULL || s2 == NULL) return false;
319    return strncasecmp(s1, s2, n) == 0;
320 }
321 
322 /*
323  * Get character length of UTF-8 string
324  *
325  * Valid UTF-8 codes
326  * U-00000000 - U-0000007F: 0xxxxxxx
327  * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
328  * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
329  * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
330  * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
331  * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
332  */
cstrlen(const char * str)333 int cstrlen(const char *str)
334 {
335    uint8_t *p = (uint8_t *)str;
336    int len = 0;
337    if (str == NULL) {
338       return 0;
339    }
340    while (*p) {
341       if ((*p & 0xC0) != 0xC0) {
342          p++;
343          len++;
344          continue;
345       }
346       if ((*p & 0xD0) == 0xC0) {
347          p += 2;
348          len++;
349          continue;
350       }
351       if ((*p & 0xF0) == 0xD0) {
352          p += 3;
353          len++;
354          continue;
355       }
356       if ((*p & 0xF8) == 0xF0) {
357          p += 4;
358          len++;
359          continue;
360       }
361       if ((*p & 0xFC) == 0xF8) {
362          p += 5;
363          len++;
364          continue;
365       }
366       if ((*p & 0xFE) == 0xFC) {
367          p += 6;
368          len++;
369          continue;
370       }
371       p++;                      /* Shouln't get here but must advance */
372    }
373    return len;
374 }
375 
376 #ifndef bmalloc
bmalloc(size_t size)377 void *bmalloc(size_t size)
378 {
379   void *buf;
380 
381 #ifdef SMARTALLOC
382   buf = sm_malloc(file, line, size);
383 #else
384   buf = malloc(size);
385 #endif
386   if (buf == NULL) {
387      BErrNo be;
388      Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
389   }
390   return buf;
391 }
392 #endif
393 
b_malloc(const char * file,int line,size_t size)394 void *b_malloc(const char *file, int line, size_t size)
395 {
396   void *buf;
397 
398 #ifdef SMARTALLOC
399   buf = sm_malloc(file, line, size);
400 #else
401   buf = malloc(size);
402 #endif
403   if (buf == NULL) {
404      BErrNo be;
405      e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
406   }
407   return buf;
408 }
409 
410 
bfree(void * buf)411 void bfree(void *buf)
412 {
413 #ifdef SMARTALLOC
414   sm_free(__FILE__, __LINE__, buf);
415 #else
416   free(buf);
417 #endif
418 }
419 
brealloc(void * buf,size_t size)420 void *brealloc (void *buf, size_t size)
421 {
422 #ifdef SMARTALOC
423    buf = sm_realloc(__FILE__, __LINE__, buf, size);
424 #else
425    buf = realloc(buf, size);
426 #endif
427    if (buf == NULL) {
428       BErrNo be;
429       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
430    }
431    return buf;
432 }
433 
bcalloc(size_t size1,size_t size2)434 void *bcalloc(size_t size1, size_t size2)
435 {
436   void *buf;
437 
438    buf = calloc(size1, size2);
439    if (buf == NULL) {
440       BErrNo be;
441       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
442    }
443    return buf;
444 }
445 
446 /* Code now in src/lib/bsnprintf.c */
447 #ifndef USE_BSNPRINTF
448 
449 #define BIG_BUF 5000
450 /*
451  * Implement snprintf
452  */
Bsnprintf(char * str,int32_t size,const char * fmt,...)453 int Bsnprintf(char *str, int32_t size, const char *fmt,  ...)
454 {
455    va_list   arg_ptr;
456    int len;
457 
458    va_start(arg_ptr, fmt);
459    len = Bvsnprintf(str, size, fmt, arg_ptr);
460    va_end(arg_ptr);
461    return len;
462 }
463 
464 /*
465  * Implement vsnprintf()
466  */
Bvsnprintf(char * str,int32_t size,const char * format,va_list ap)467 int Bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
468 {
469 #ifdef HAVE_VSNPRINTF
470    int len;
471    len = vsnprintf(str, size, format, ap);
472    str[size - 1] = 0;
473    return len;
474 
475 #else
476 
477    int len, buflen;
478    char *buf;
479    buflen = size > BIG_BUF ? size : BIG_BUF;
480    buf = GetMemory(buflen);
481    len = vsprintf(buf, format, ap);
482    if (len >= buflen) {
483       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
484    }
485    memcpy(str, buf, len);
486    str[len] = 0;                /* len excludes the null */
487    FreeMemory(buf);
488    return len;
489 #endif
490 }
491 #endif /* USE_BSNPRINTF */
492 
493 #ifndef HAVE_LOCALTIME_R
localtime_r(const time_t * timep,struct tm * tm)494 struct tm *localtime_r(const time_t *timep, struct tm *tm)
495 {
496     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
497     struct tm *ltm,
498 
499     P(mutex);
500     ltm = localtime(timep);
501     if (ltm) {
502        memcpy(tm, ltm, sizeof(struct tm));
503     }
504     V(mutex);
505     return ltm ? tm : NULL;
506 }
507 #endif /* HAVE_LOCALTIME_R */
508 
509 #ifndef HAVE_READDIR_R
510 #ifndef HAVE_WIN32
511 #include <dirent.h>
512 
Readdir_r(DIR * dirp,struct dirent * entry,struct dirent ** result)513 int Readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
514 {
515     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
516     struct dirent *ndir;
517     int status;
518 
519     P(mutex);
520     errno = 0;
521     ndir = readdir(dirp);
522     status = errno;
523     if (ndir) {
524        memcpy(entry, ndir, sizeof(struct dirent));
525        strcpy(entry->d_name, ndir->d_name);
526        *result = entry;
527     } else {
528        *result = NULL;
529     }
530     V(mutex);
531     return status;
532 
533 }
534 #endif
535 #endif /* HAVE_READDIR_R */
536 
b_strerror(int errnum,char * buf,size_t bufsiz)537 int b_strerror(int errnum, char *buf, size_t bufsiz)
538 {
539     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
540     int status = 0;
541     const char *msg;
542 
543     P(mutex);
544 
545     msg = strerror(errnum);
546     if (!msg) {
547        msg = _("Bad errno");
548        status = -1;
549     }
550     bstrncpy(buf, msg, bufsiz);
551     V(mutex);
552     return status;
553 }
554 
555 #ifdef DEBUG_MEMSET
556 /* These routines are not normally turned on */
557 #undef memset
b_memset(const char * file,int line,void * mem,int val,size_t num)558 void b_memset(const char *file, int line, void *mem, int val, size_t num)
559 {
560    /* Testing for 2000 byte zero at beginning of Volume block */
561    if (num > 1900 && num < 3000) {
562       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
563    }
564    memset(mem, val, num);
565 }
566 #endif
567 
568 #if !defined(HAVE_WIN32)
569 static bool del_pid_file_ok = false;
570 #endif
571 
572 /*
573  * Create a standard "Unix" pid file.
574  */
CreatePidFile(char * dir,const char * progname,int port)575 void CreatePidFile(char *dir, const char *progname, int port)
576 {
577 #if !defined(HAVE_WIN32)
578    int pidfd = -1;
579    int len;
580    int oldpid;
581    char  pidbuf[20];
582    POOLMEM *fname = GetPoolMemory(PM_FNAME);
583    struct stat statp;
584 
585    Mmsg(fname, "%s/%s.%d.pid", dir, progname, port);
586    if (stat(fname, &statp) == 0) {
587       /* File exists, see what we have */
588       *pidbuf = 0;
589       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
590            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
591            sscanf(pidbuf, "%d", &oldpid) != 1) {
592          BErrNo be;
593          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname,
594                be.bstrerror());
595       } else {
596          /*
597           * Some OSes (IRIX) don't bother to clean out the old pid files after a crash, and
598           * since they use a deterministic algorithm for assigning PIDs, we can have
599           * pid conflicts with the old PID file after a reboot.
600           * The intent the following code is to check if the oldpid read from the pid
601           * file is the same as the currently executing process's pid,
602           * and if oldpid == getpid(), skip the attempt to
603           * kill(oldpid,0), since the attempt is guaranteed to succeed,
604           * but the success won't actually mean that there is an
605           * another BAREOS process already running.
606           * For more details see bug #797.
607           */
608           if ((oldpid != (int)getpid()) && (kill(oldpid, 0) != -1 || errno != ESRCH)) {
609             Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
610                   progname, oldpid, fname);
611          }
612       }
613 
614       if (pidfd >= 0) {
615          close(pidfd);
616       }
617 
618       /*
619        * He is not alive, so take over file ownership
620        */
621       unlink(fname);                  /* remove stale pid file */
622    }
623 
624    /*
625     * Create new pid file
626     */
627    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
628       len = sprintf(pidbuf, "%d\n", (int)getpid());
629       write(pidfd, pidbuf, len);
630       close(pidfd);
631       del_pid_file_ok = true;         /* we created it so we can delete it */
632    } else {
633       BErrNo be;
634       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname,
635             be.bstrerror());
636    }
637    FreePoolMemory(fname);
638 #endif
639 }
640 
641 /*
642  * Delete the pid file if we created it
643  */
DeletePidFile(char * dir,const char * progname,int port)644 int DeletePidFile(char *dir, const char *progname, int port)
645 {
646 #if !defined(HAVE_WIN32)
647    POOLMEM *fname = GetPoolMemory(PM_FNAME);
648 
649    if (!del_pid_file_ok) {
650       FreePoolMemory(fname);
651       return 0;
652    }
653    del_pid_file_ok = false;
654    Mmsg(fname, "%s/%s.%d.pid", dir, progname, port);
655    unlink(fname);
656    FreePoolMemory(fname);
657 #endif
658    return 1;
659 }
660 
661 struct s_state_hdr {
662    char id[14];
663    int32_t version;
664    uint64_t last_jobs_addr;
665    uint64_t reserved[20];
666 };
667 
668 static struct s_state_hdr state_hdr = {
669    "Bareos State\n",
670    4,
671    0
672 };
673 
674 /*
675  * Open and read the state file for the daemon
676  */
ReadStateFile(char * dir,const char * progname,int port)677 void ReadStateFile(char *dir, const char *progname, int port)
678 {
679    int sfd;
680    ssize_t status;
681    bool ok = false;
682    POOLMEM *fname = GetPoolMemory(PM_FNAME);
683    struct s_state_hdr hdr;
684    int hdr_size = sizeof(hdr);
685 
686    Mmsg(fname, "%s/%s.%d.state", dir, progname, port);
687    /*
688     * If file exists, see what we have
689     */
690    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
691       BErrNo be;
692       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
693             sfd, sizeof(hdr), be.bstrerror());
694       goto bail_out;
695    }
696    if ((status = read(sfd, &hdr, hdr_size)) != hdr_size) {
697       BErrNo be;
698       Dmsg4(010, "Could not read state file. sfd=%d status=%d size=%d: ERR=%s\n",
699             sfd, (int)status, hdr_size, be.bstrerror());
700       goto bail_out;
701    }
702    if (hdr.version != state_hdr.version) {
703       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
704             state_hdr.version, hdr.version);
705       goto bail_out;
706    }
707    hdr.id[13] = 0;
708    if (!bstrcmp(hdr.id, state_hdr.id)) {
709       Dmsg0(000, "State file header id invalid.\n");
710       goto bail_out;
711    }
712 
713    if (!ReadLastJobsList(sfd, hdr.last_jobs_addr)) {
714       goto bail_out;
715    }
716    ok = true;
717 bail_out:
718    if (sfd >= 0) {
719       close(sfd);
720    }
721 
722    if (!ok) {
723       SecureErase(NULL, fname);
724    }
725 
726    FreePoolMemory(fname);
727 }
728 
729 /*
730  * Write the state file
731  */
732 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
733 
WriteStateFile(char * dir,const char * progname,int port)734 void WriteStateFile(char *dir, const char *progname, int port)
735 {
736    int sfd;
737    bool ok = false;
738    POOLMEM *fname = GetPoolMemory(PM_FNAME);
739 
740    P(state_mutex);                    /* Only one job at a time can call here */
741    Mmsg(fname, "%s/%s.%d.state", dir, progname, port);
742 
743    /*
744     * Create new state file
745     */
746    SecureErase(NULL, fname);
747    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
748       BErrNo be;
749       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.bstrerror());
750       goto bail_out;
751    }
752 
753    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
754       BErrNo be;
755       Dmsg1(000, "Write hdr error: ERR=%s\n", be.bstrerror());
756       goto bail_out;
757    }
758 
759    state_hdr.last_jobs_addr = sizeof(state_hdr);
760    state_hdr.reserved[0] = WriteLastJobsList(sfd, state_hdr.last_jobs_addr);
761    if (lseek(sfd, 0, SEEK_SET) < 0) {
762       BErrNo be;
763       Dmsg1(000, "lseek error: ERR=%s\n", be.bstrerror());
764       goto bail_out;
765    }
766 
767    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
768       BErrNo be;
769       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.bstrerror());
770       goto bail_out;
771    }
772    ok = true;
773 bail_out:
774    if (sfd >= 0) {
775       close(sfd);
776    }
777 
778    if (!ok) {
779       SecureErase(NULL, fname);
780    }
781    V(state_mutex);
782    FreePoolMemory(fname);
783 }
784 
785 /* BSDI does not have this.  This is a *poor* simulation */
786 #ifndef HAVE_STRTOLL
787 long long int
strtoll(const char * ptr,char ** endptr,int base)788 strtoll(const char *ptr, char **endptr, int base)
789 {
790    return (long long int)strtod(ptr, endptr);
791 }
792 #endif
793 
794 /*
795  * BAREOS's implementation of fgets(). The difference is that it handles
796  *   being interrupted by a signal (e.g. a SIGCHLD).
797  */
798 #undef fgetc
bfgets(char * s,int size,FILE * fd)799 char *bfgets(char *s, int size, FILE *fd)
800 {
801    char *p = s;
802    int ch;
803    *p = 0;
804    for (int i = 0; i < size - 1; i++) {
805       do {
806          errno = 0;
807          ch = fgetc(fd);
808       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
809       if (ch == EOF) {
810          if (i == 0) {
811             return NULL;
812          } else {
813             return s;
814          }
815       }
816       *p++ = ch;
817       *p = 0;
818       if (ch == '\r') { /* Support for Mac/Windows file format */
819          ch = fgetc(fd);
820          if (ch != '\n') { /* Mac (\r only) */
821             (void)ungetc(ch, fd); /* Push next character back to fd */
822          }
823          p[-1] = '\n';
824          break;
825       }
826       if (ch == '\n') {
827          break;
828       }
829    }
830    return s;
831 }
832 
833 /*
834  * BAREOS's implementation of fgets(). The difference is that it handles
835  *   being interrupted by a signal (e.g. a SIGCHLD) and it has a
836  *   different calling sequence which implements input lines of
837  *   up to a million characters.
838  */
bfgets(POOLMEM * & s,FILE * fd)839 char *bfgets(POOLMEM *&s, FILE *fd)
840 {
841    int ch;
842    int soft_max;
843    int i = 0;
844 
845    s[0] = 0;
846    soft_max = SizeofPoolMemory(s) - 10;
847    for ( ;; ) {
848       do {
849          errno = 0;
850          ch = fgetc(fd);
851       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
852       if (ch == EOF) {
853          if (i == 0) {
854             return NULL;
855          } else {
856             return s;
857          }
858       }
859       if (i > soft_max) {
860          /* Insanity check */
861          if (soft_max > 1000000) {
862             return s;
863          }
864          s = CheckPoolMemorySize(s, soft_max+10000);
865          soft_max = SizeofPoolMemory(s) - 10;
866       }
867       s[i++] = ch;
868       s[i] = 0;
869       if (ch == '\r') { /* Support for Mac/Windows file format */
870          ch = fgetc(fd);
871          if (ch != '\n') { /* Mac (\r only) */
872             (void)ungetc(ch, fd); /* Push next character back to fd */
873          }
874          s[i - 1] = '\n';
875          break;
876       }
877       if (ch == '\n') {
878          break;
879       }
880    }
881    return s;
882 }
883 
884 /*
885  * Make a "unique" filename.  It is important that if
886  *   called again with the same "what" that the result
887  *   will be identical. This allows us to use the file
888  *   without saving its name, and re-generate the name
889  *   so that it can be deleted.
890  */
MakeUniqueFilename(POOLMEM * & name,int Id,char * what)891 void MakeUniqueFilename(POOLMEM *&name, int Id, char *what)
892 {
893    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
894 }
895 
escape_filename(const char * file_path)896 char *escape_filename(const char *file_path)
897 {
898    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
899       return NULL;
900    }
901 
902    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
903    char *cur_char = escaped_path;
904 
905    while (*file_path) {
906       if (*file_path == '\\' || *file_path == '"') {
907          *cur_char++ = '\\';
908       }
909 
910       *cur_char++ = *file_path++;
911    }
912 
913    *cur_char = '\0';
914 
915    return escaped_path;
916 }
917 
PathExists(const char * path)918 bool PathExists(const char *path)
919 {
920    struct stat statp;
921 
922    if (!path || !strlen(path)) {
923       return false;
924    }
925 
926    return (stat(path, &statp) == 0);
927 }
928 
PathExists(PoolMem & path)929 bool PathExists(PoolMem &path)
930 {
931    return PathExists(path.c_str());
932 }
933 
PathIsDirectory(const char * path)934 bool PathIsDirectory(const char *path)
935 {
936    struct stat statp;
937 
938    if (!path || !strlen(path)) {
939       return false;
940    }
941 
942    if (stat(path, &statp) == 0) {
943       return (S_ISDIR(statp.st_mode));
944    } else {
945       return false;
946    }
947 }
948 
PathIsDirectory(PoolMem & path)949 bool PathIsDirectory(PoolMem &path)
950 {
951    return PathIsDirectory(path.c_str());
952 }
953 
PathIsAbsolute(const char * path)954 bool PathIsAbsolute(const char *path)
955 {
956    if (!path || !strlen(path)) {
957       /*
958        * No path: not an absolute path
959        */
960       return false;
961    }
962 
963    /*
964     * Is path absolute?
965     */
966    if (IsPathSeparator(path[0])) {
967       return true;
968    }
969 
970 #ifdef HAVE_WIN32
971    /*
972     * Windows:
973     * Does path begin with drive? if yes, it is absolute
974     */
975    if (strlen(path) >= 3) {
976       if (isalpha(path[0]) && path[1] == ':' && IsPathSeparator(path[2])) {
977          return true;
978       }
979    }
980 #endif
981 
982    return false;
983 }
984 
PathIsAbsolute(PoolMem & path)985 bool PathIsAbsolute(PoolMem &path)
986 {
987    return PathIsAbsolute(path.c_str());
988 }
989 
PathContainsDirectory(const char * path)990 bool PathContainsDirectory(const char *path)
991 {
992    int i;
993 
994    if (!path) {
995       return false;
996    }
997 
998    i = strlen(path) - 1;
999 
1000    while (i >= 0) {
1001       if (IsPathSeparator(path[i])) {
1002          return true;
1003       }
1004       i--;
1005    }
1006 
1007    return false;
1008 }
1009 
PathContainsDirectory(PoolMem & path)1010 bool PathContainsDirectory(PoolMem &path)
1011 {
1012    return PathContainsDirectory(path.c_str());
1013 }
1014 
1015 
1016 /*
1017  * Get directory from path.
1018  */
PathGetDirectory(PoolMem & directory,PoolMem & path)1019 bool PathGetDirectory(PoolMem &directory, PoolMem &path)
1020 {
1021    char *dir = NULL;
1022    int i = path.strlen();
1023 
1024    directory.strcpy(path);
1025    if (!PathIsDirectory(directory)) {
1026       dir = directory.addr();
1027       while ((!IsPathSeparator(dir[i])) && (i > 0)) {
1028          dir[i] = 0;
1029          i--;
1030       }
1031    }
1032 
1033    if (PathIsDirectory(directory)) {
1034       /*
1035        * Make sure, path ends with path separator
1036        */
1037       PathAppend(directory, "");
1038       return true;
1039    }
1040 
1041    return false;
1042 }
1043 
PathAppend(char * path,const char * extra,unsigned int max_path)1044 bool PathAppend(char *path, const char *extra, unsigned int max_path)
1045 {
1046    unsigned int path_len;
1047    unsigned int required_length;
1048 
1049    if (!path || !extra) {
1050       return true;
1051    }
1052 
1053    path_len = strlen(path);
1054    required_length = path_len + 1 + strlen(extra);
1055    if (required_length > max_path) {
1056       return false;
1057    }
1058 
1059    /*
1060     * Add path separator after original path if missing.
1061     */
1062    if (!IsPathSeparator(path[path_len - 1])) {
1063       path[path_len] = PathSeparator;
1064       path_len++;
1065    }
1066 
1067    memcpy(path + path_len, extra, strlen(extra) + 1);
1068 
1069    return true;
1070 }
1071 
PathAppend(PoolMem & path,const char * extra)1072 bool PathAppend(PoolMem &path, const char *extra)
1073 {
1074    unsigned int required_length;
1075 
1076    if (!extra) {
1077       return true;
1078    }
1079 
1080    required_length = path.strlen() + 2 + strlen(extra);
1081    if (!path.check_size(required_length)) {
1082       return false;
1083    }
1084    return PathAppend(path.c_str(), extra, required_length);
1085 }
1086 
1087 /*
1088  * Append to paths together.
1089  */
PathAppend(PoolMem & path,PoolMem & extra)1090 bool PathAppend(PoolMem &path, PoolMem &extra)
1091 {
1092    return PathAppend(path, extra.c_str());
1093 }
1094 
1095 /*
1096  * based on
1097  * src/findlib/mkpath.c:bool makedir(...)
1098  */
PathMkdir(char * path,mode_t mode)1099 static bool PathMkdir(char *path, mode_t mode)
1100 {
1101    if (PathExists(path)) {
1102       Dmsg1(500, "skipped, path %s already exists.\n", path);
1103       return PathIsDirectory(path);
1104    }
1105 
1106    if (mkdir(path, mode) != 0) {
1107       BErrNo be;
1108       Emsg2(M_ERROR, 0, "Falied to create directory %s: ERR=%s\n",
1109               path, be.bstrerror());
1110       return false;
1111    }
1112 
1113    return true;
1114 }
1115 
1116 /*
1117  * based on
1118  * src/findlib/mkpath.c:bool makepath(Attributes *attr, const char *apath, mode_t mode, mode_t parent_mode, ...
1119  */
PathCreate(const char * apath,mode_t mode)1120 bool PathCreate(const char *apath, mode_t mode)
1121 {
1122    char *p;
1123    int len;
1124    bool ok = false;
1125    struct stat statp;
1126    char *path = NULL;
1127 
1128    if (stat(apath, &statp) == 0) {     /* Does dir exist? */
1129       if (!S_ISDIR(statp.st_mode)) {
1130          Emsg1(M_ERROR, 0, "%s exists but is not a directory.\n", path);
1131          return false;
1132       }
1133       return true;
1134    }
1135 
1136    len = strlen(apath);
1137    path = (char *)alloca(len + 1);
1138    bstrncpy(path, apath, len + 1);
1139    StripTrailingSlashes(path);
1140 
1141 #if defined(HAVE_WIN32)
1142    /*
1143     * Validate drive letter
1144     */
1145    if (path[1] == ':') {
1146       char drive[4] = "X:\\";
1147 
1148       drive[0] = path[0];
1149 
1150       UINT drive_type = GetDriveType(drive);
1151 
1152       if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) {
1153          Emsg1(M_ERROR, 0, "%c: is not a valid drive.\n", path[0]);
1154          goto bail_out;
1155       }
1156 
1157       if (path[2] == '\0') {          /* attempt to create a drive */
1158          ok = true;
1159          goto bail_out;               /* OK, it is already there */
1160       }
1161 
1162       p = &path[3];
1163    } else {
1164       p = path;
1165    }
1166 #else
1167    p = path;
1168 #endif
1169 
1170    /*
1171     * Skip leading slash(es)
1172     */
1173    while (IsPathSeparator(*p)) {
1174       p++;
1175    }
1176    while ((p = first_path_separator(p))) {
1177       char save_p;
1178       save_p = *p;
1179       *p = 0;
1180       if (!PathMkdir(path, mode)) {
1181          goto bail_out;
1182       }
1183       *p = save_p;
1184       while (IsPathSeparator(*p)) {
1185          p++;
1186       }
1187    }
1188 
1189    if (!PathMkdir(path, mode)) {
1190       goto bail_out;
1191    }
1192 
1193    ok = true;
1194 
1195 bail_out:
1196    return ok;
1197 }
1198 
PathCreate(PoolMem & path,mode_t mode)1199 bool PathCreate(PoolMem &path, mode_t mode)
1200 {
1201    return PathCreate(path.c_str(), mode);
1202 }
1203 
1204 /*
1205  * Some Solaris specific support needed for Solaris 10 and lower.
1206  */
1207 #if defined(HAVE_SUN_OS)
1208 
1209 /*
1210  * If libc doesn't have Addrtosymstr emulate it.
1211  * Solaris 11 has Addrtosymstr in libc older
1212  * Solaris versions don't have this.
1213  */
1214 #ifndef HAVE_ADDRTOSYMSTR
1215 
1216 #include <dlfcn.h>
1217 
1218 #ifdef _LP64
1219 #define _ELF64
1220 #endif
1221 #include <sys/machelf.h>
1222 
Addrtosymstr(void * pc,char * buffer,int size)1223 static int Addrtosymstr(void *pc, char *buffer, int size)
1224 {
1225    Dl_info info;
1226    Sym *sym;
1227 
1228    if (dladdr1(pc, &info, (void **)&sym, RTLD_DL_SYMENT) == 0) {
1229       return (Bsnprintf(buffer, size, "[0x%p]", pc));
1230    }
1231 
1232    if ((info.dli_fname != NULL && info.dli_sname != NULL) &&
1233       ((uintptr_t)pc - (uintptr_t)info.dli_saddr < sym->st_size)) {
1234       return (Bsnprintf(buffer, size, "%s'%s+0x%x [0x%p]",
1235                         info.dli_fname,
1236                         info.dli_sname,
1237                         (unsigned long)pc - (unsigned long)info.dli_saddr,
1238                         pc));
1239    } else {
1240       return (Bsnprintf(buffer, size, "%s'0x%p [0x%p]",
1241                         info.dli_fname,
1242                         (unsigned long)pc - (unsigned long)info.dli_fbase,
1243                         pc));
1244    }
1245 }
1246 #endif /* HAVE_ADDRTOSYMSTR */
1247 
1248 /*
1249  * If libc doesn't have backtrace_symbols emulate it.
1250  * Solaris 11 has backtrace_symbols in libc older
1251  * Solaris versions don't have this.
1252  */
1253 #ifndef HAVE_BACKTRACE_SYMBOLS
backtrace_symbols(void * const * array,int size)1254 static char **backtrace_symbols(void *const *array, int size)
1255 {
1256    int bufferlen, len;
1257    char **ret_buffer;
1258    char **ret = NULL;
1259    char linebuffer[512];
1260    int i;
1261 
1262    bufferlen = size * sizeof(char *);
1263    ret_buffer = (char **)actuallymalloc(bufferlen);
1264    if (ret_buffer) {
1265       for (i = 0; i < size; i++) {
1266          (void) Addrtosymstr(array[i], linebuffer, sizeof(linebuffer));
1267          ret_buffer[i] = (char *)actuallymalloc(len = strlen(linebuffer) + 1);
1268          strcpy(ret_buffer[i], linebuffer);
1269          bufferlen += len;
1270       }
1271       ret = (char **)actuallymalloc(bufferlen);
1272       if (ret) {
1273          for (len = i = 0; i < size; i++) {
1274             ret[i] = (char *)ret + size * sizeof(char *) + len;
1275             (void) strcpy(ret[i], ret_buffer[i]);
1276             len += strlen(ret_buffer[i]) + 1;
1277          }
1278       }
1279    }
1280 
1281    return (ret);
1282 }
1283 
1284 /*
1285  * Define that we now know backtrace_symbols()
1286  */
1287 #define HAVE_BACKTRACE_SYMBOLS 1
1288 
1289 #endif /* HAVE_BACKTRACE_SYMBOLS */
1290 
1291 /*
1292  * If libc doesn't have backtrace call emulate it using getcontext(3)
1293  * Solaris 11 has backtrace in libc older Solaris versions don't have this.
1294  */
1295 #ifndef HAVE_BACKTRACE
1296 
1297 #ifdef HAVE_UCONTEXT_H
1298 #include <ucontext.h>
1299 #endif
1300 
1301 typedef struct backtrace {
1302    void **bt_buffer;
1303    int bt_maxcount;
1304    int bt_actcount;
1305 } backtrace_t;
1306 
callback(uintptr_t pc,int signo,void * arg)1307 static int callback(uintptr_t pc, int signo, void *arg)
1308 {
1309    backtrace_t *bt = (backtrace_t *)arg;
1310 
1311    if (bt->bt_actcount >= bt->bt_maxcount)
1312       return (-1);
1313 
1314    bt->bt_buffer[bt->bt_actcount++] = (void *)pc;
1315 
1316    return (0);
1317 }
1318 
backtrace(void ** buffer,int count)1319 static int backtrace(void **buffer, int count)
1320 {
1321    backtrace_t bt;
1322    ucontext_t u;
1323 
1324    bt.bt_buffer = buffer;
1325    bt.bt_maxcount = count;
1326    bt.bt_actcount = 0;
1327 
1328    if (getcontext(&u) < 0)
1329       return (0);
1330 
1331    (void) walkcontext(&u, callback, &bt);
1332 
1333    return (bt.bt_actcount);
1334 }
1335 
1336 /*
1337  * Define that we now know backtrace()
1338  */
1339 #define HAVE_BACKTRACE 1
1340 
1341 #endif /* HAVE_BACKTRACE */
1342 #endif /* HAVE_SUN_OS */
1343 
1344 /*
1345  * Support strack_trace support on platforms that use GCC as compiler.
1346  */
1347 #if defined(HAVE_BACKTRACE) && \
1348     defined(HAVE_BACKTRACE_SYMBOLS) && \
1349     defined(HAVE_GCC)
1350 
1351 #ifdef HAVE_CXXABI_H
1352 #include <cxxabi.h>
1353 #endif
1354 
1355 #ifdef HAVE_EXECINFO_H
1356 #include <execinfo.h>
1357 #endif
1358 
stack_trace()1359 void stack_trace()
1360 {
1361    int status;
1362    size_t stack_depth, sz, i;
1363    const size_t max_depth = 100;
1364    void *stack_addrs[max_depth];
1365    char **stack_strings, *begin, *end, *j, *function, *ret;
1366 
1367    stack_depth = backtrace(stack_addrs, max_depth);
1368    stack_strings = backtrace_symbols(stack_addrs, stack_depth);
1369 
1370    for (i = 3; i < stack_depth; i++) {
1371       sz = 200; /* Just a guess, template names will go much wider */
1372       function = (char *)actuallymalloc(sz);
1373       begin = end = 0;
1374       /*
1375        * Find the parentheses and address offset surrounding the mangled name
1376        */
1377       for (j = stack_strings[i]; *j; ++j) {
1378          if (*j == '(') {
1379             begin = j;
1380          } else if (*j == '+') {
1381             end = j;
1382          }
1383       }
1384       if (begin && end) {
1385          *begin++ = '\0';
1386          *end = '\0';
1387          /*
1388           * Found our mangled name, now in [begin, end]
1389           */
1390          ret = abi::__cxa_demangle(begin, function, &sz, &status);
1391          if (ret) {
1392             /*
1393              * Return value may be a realloc() of the input
1394              */
1395             function = ret;
1396          } else {
1397             /*
1398              * Demangling failed, just pretend it's a C function with no args
1399              */
1400             strncpy(function, begin, sz - 3);
1401             strcat(function, "()");
1402             function[sz - 1] = '\0';
1403          }
1404          Pmsg2(000, "    %s:%s\n", stack_strings[i], function);
1405 
1406       } else {
1407          /* didn't find the mangled name, just print the whole line */
1408          Pmsg1(000, "    %s\n", stack_strings[i]);
1409       }
1410       Actuallyfree(function);
1411    }
1412    Actuallyfree(stack_strings); /* malloc()ed by backtrace_symbols */
1413 }
1414 
1415 /*
1416  * Support strack_trace support on Solaris when using the SUNPRO_CC compiler.
1417  */
1418 #elif defined(HAVE_SUN_OS) && \
1419      !defined(HAVE_NON_WORKING_WALKCONTEXT) && \
1420       defined(HAVE_UCONTEXT_H) && \
1421       defined(HAVE_DEMANGLE_H) && \
1422       defined(HAVE_CPLUS_DEMANGLE) && \
1423       defined(__SUNPRO_CC)
1424 
1425 #ifdef HAVE_UCONTEXT_H
1426 #include <ucontext.h>
1427 #endif
1428 
1429 #if defined(HAVE_EXECINFO_H)
1430 #include <execinfo.h>
1431 #endif
1432 
1433 #include <demangle.h>
1434 
stack_trace()1435 void stack_trace()
1436 {
1437    int ret, i;
1438    bool demangled_symbol;
1439    size_t stack_depth;
1440    size_t sz = 200; /* Just a guess, template names will go much wider */
1441    const size_t max_depth = 100;
1442    void *stack_addrs[100];
1443    char **stack_strings, *begin, *end, *j, *function;
1444 
1445    stack_depth = backtrace(stack_addrs, max_depth);
1446    stack_strings = backtrace_symbols(stack_addrs, stack_depth);
1447 
1448    for (i = 1; i < stack_depth; i++) {
1449       function = (char *)actuallymalloc(sz);
1450       begin = end = 0;
1451       /*
1452        * Find the single quote and address offset surrounding the mangled name
1453        */
1454       for (j = stack_strings[i]; *j; ++j) {
1455          if (*j == '\'') {
1456             begin = j;
1457          } else if (*j == '+') {
1458             end = j;
1459          }
1460       }
1461       if (begin && end) {
1462          *begin++ = '\0';
1463          *end = '\0';
1464          /*
1465           * Found our mangled name, now in [begin, end)
1466           */
1467          demangled_symbol = false;
1468          while (!demangled_symbol) {
1469             ret = cplus_demangle(begin, function, sz);
1470             switch (ret) {
1471             case DEMANGLE_ENAME:
1472                /*
1473                 * Demangling failed, just pretend it's a C function with no args
1474                 */
1475                strcat(function, "()");
1476                function[sz - 1] = '\0';
1477                demangled_symbol = true;
1478                break;
1479             case DEMANGLE_ESPACE:
1480                /*
1481                 * Need more space for demangled function name.
1482                 */
1483                Actuallyfree(function);
1484                sz = sz * 2;
1485                function = (char *)actuallymalloc(sz);
1486                continue;
1487             default:
1488                demangled_symbol = true;
1489                break;
1490             }
1491          }
1492          Pmsg2(000, "    %s:%s\n", stack_strings[i], function);
1493       } else {
1494          /*
1495           * Didn't find the mangled name, just print the whole line
1496           */
1497          Pmsg1(000, "    %s\n", stack_strings[i]);
1498       }
1499       Actuallyfree(function);
1500    }
1501    Actuallyfree(stack_strings); /* malloc()ed by backtrace_symbols */
1502 }
1503 
1504 #else
1505 
stack_trace()1506 void stack_trace()
1507 {
1508 }
1509 
1510 #endif
1511