1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Miscellaneous Bacula memory and thread safe routines
21  *   Generally, these are interfaces to system or standard
22  *   library routines.
23  *
24  *  Bacula utility functions are in util.c
25  *
26  */
27 
28 #include "bacula.h"
29 #ifndef HAVE_REGEX_H
30 #include "lib/bregex.h"
31 #else
32 #include <regex.h>
33 #endif
34 
35 static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
36 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
37 
38 /* bacula => Bacula
39  * Works only for standard ASCII strings
40  */
ucfirst(char * dst,const char * src,int len)41 char *ucfirst(char *dst, const char *src, int len)
42 {
43    int i=0;
44    len--;                       /* Keep the last byte for \0 */
45    for (i=0; src[i] && i < len ; i++) {
46       dst[i] = (i == 0) ? toupper(src[i]) : tolower(src[i]);
47    }
48    dst[i] = 0;
49    return dst;
50 }
51 
52 /*
53  * Quote a string
54  */
quote_string(POOLMEM * & snew,const char * old)55 POOLMEM *quote_string(POOLMEM *&snew, const char *old)
56 {
57    char *n;
58    int i;
59 
60    if (!old) {
61       strcpy(snew, "null");
62       return snew;
63    }
64    snew = check_pool_memory_size(snew, strlen(old)*2+2+1);
65    n = snew;
66    *n++ = '"';
67    for (i=0; old[i]; i++) {
68       switch (old[i]) {
69       case '"':
70          *n++ = '\\';
71          *n++ = '"';
72          break;
73       case '\\':
74          *n++ = '\\';
75          *n++ = '\\';
76          break;
77       case '\r':
78          *n++ = '\\';
79          *n++ = 'r';
80          break;
81       case '\n':
82          *n++ = '\\';
83          *n++ = 'n';
84          break;
85       default:
86          *n++ = old[i];
87          break;
88       }
89    }
90    *n++ = '"';
91    *n = 0;
92    return snew;
93 }
94 
95 /*
96  * Quote a where (list of addresses separated by spaces)
97  */
quote_where(POOLMEM * & snew,const char * old)98 POOLMEM *quote_where(POOLMEM *&snew, const char *old)
99 {
100    char *n;
101    int i;
102 
103    if (!old) {
104       strcpy(snew, "null");
105       return snew;
106    }
107    snew = check_pool_memory_size(snew, strlen(old)*3+2+1);
108    n = snew;
109    *n++ = '"';
110    for (i=0; old[i]; i++) {
111       switch (old[i]) {
112       case ' ':
113          *n++ = '"';
114          *n++ = ',';
115          *n++ = '"';
116          break;
117       case '"':
118          *n++ = '\\';
119          *n++ = '"';
120          break;
121       case '\\':
122          *n++ = '\\';
123          *n++ = '\\';
124          break;
125       default:
126          *n++ = old[i];
127          break;
128       }
129    }
130    *n++ = '"';
131    *n = 0;
132    return snew;
133 }
134 
135 /*
136  * This routine is a somewhat safer unlink in that it
137  *   allows you to run a regex on the filename before
138  *   excepting it. It also requires the file to be in
139  *   the working directory.
140  */
safer_unlink(const char * pathname,const char * regx)141 int safer_unlink(const char *pathname, const char *regx)
142 {
143    int rc;
144    regex_t preg1;
145    char prbuf[500];
146    const int nmatch = 30;
147    regmatch_t pmatch[nmatch];
148    int rtn;
149 
150    /* Name must start with working directory */
151    if (strncmp(pathname, working_directory, strlen(working_directory)) != 0) {
152       Pmsg1(000, "Safe_unlink excluded: %s\n", pathname);
153       return EROFS;
154    }
155 
156    /* Compile regex expression */
157    rc = regcomp(&preg1, regx, REG_EXTENDED);
158    if (rc != 0) {
159       regerror(rc, &preg1, prbuf, sizeof(prbuf));
160       Pmsg2(000,  _("safe_unlink could not compile regex pattern \"%s\" ERR=%s\n"),
161            regx, prbuf);
162       return ENOENT;
163    }
164 
165    /* Unlink files that match regexes */
166    if (regexec(&preg1, pathname, nmatch, pmatch,  0) == 0) {
167       Dmsg1(100, "safe_unlink unlinking: %s\n", pathname);
168       rtn = unlink(pathname);
169    } else {
170       Pmsg2(000, "safe_unlink regex failed: regex=%s file=%s\n", regx, pathname);
171       rtn = EROFS;
172    }
173    regfree(&preg1);
174    return rtn;
175 }
176 
177 /*
178  * This routine will sleep (sec, microsec).  Note, however, that if a
179  *   signal occurs, it will return early.  It is up to the caller
180  *   to recall this routine if he/she REALLY wants to sleep the
181  *   requested time.
182  */
bmicrosleep(int32_t sec,int32_t usec)183 int bmicrosleep(int32_t sec, int32_t usec)
184 {
185    struct timespec timeout;
186    struct timeval tv;
187    struct timezone tz;
188    int stat;
189 
190    timeout.tv_sec = sec;
191    timeout.tv_nsec = usec * 1000;
192 
193 #ifdef HAVE_NANOSLEEP
194    stat = nanosleep(&timeout, NULL);
195    if (!(stat < 0 && errno == ENOSYS)) {
196       return stat;
197    }
198    /* If we reach here it is because nanosleep is not supported by the OS */
199 #endif
200 
201    /* Do it the old way */
202    gettimeofday(&tv, &tz);
203    timeout.tv_nsec += tv.tv_usec * 1000;
204    timeout.tv_sec += tv.tv_sec;
205    while (timeout.tv_nsec >= 1000000000) {
206       timeout.tv_nsec -= 1000000000;
207       timeout.tv_sec++;
208    }
209 
210    Dmsg2(200, "pthread_cond_timedwait sec=%d usec=%d\n", sec, usec);
211    /* Note, this unlocks mutex during the sleep */
212    P(timer_mutex);
213    stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout);
214    if (stat != 0) {
215       berrno be;
216       Dmsg2(200, "pthread_cond_timedwait stat=%d ERR=%s\n", stat,
217          be.bstrerror(stat));
218    }
219    V(timer_mutex);
220    return stat;
221 }
222 
223 /* allow using strncpy in this file */
224 #undef strncpy
225 
226 /*
227  * Guarantee that the string is properly terminated */
bstrncpy(char * dest,const char * src,int maxlen)228 char *bstrncpy(char *dest, const char *src, int maxlen)
229 {
230    strncpy(dest, src, maxlen-1);
231    dest[maxlen-1] = 0;
232    return dest;
233 }
234 
235 /*
236  * Guarantee that the string is properly terminated */
bstrncpy(char * dest,POOL_MEM & src,int maxlen)237 char *bstrncpy(char *dest, POOL_MEM &src, int maxlen)
238 {
239    strncpy(dest, src.c_str(), maxlen-1);
240    dest[maxlen-1] = 0;
241    return dest;
242 }
243 
244 /*
245  * Note: Here the maxlen is the maximum length permitted
246  *  stored in dest, while on Unix systems, it is the maximum characters
247  *  that may be copied from src.
248  */
bstrncat(char * dest,const char * src,int maxlen)249 char *bstrncat(char *dest, const char *src, int maxlen)
250 {
251    int len = strlen(dest);
252    if (len < maxlen-1) {
253       strncpy(dest+len, src, maxlen-len-1);
254    }
255    dest[maxlen-1] = 0;
256    return dest;
257 }
258 
259 /*
260  * Note: Here the maxlen is the maximum length permitted
261  *  stored in dest, while on Unix systems, it is the maximum characters
262  *  that may be copied from src.
263  */
bstrncat(char * dest,POOL_MEM & src,int maxlen)264 char *bstrncat(char *dest, POOL_MEM &src, int maxlen)
265 {
266    int len = strlen(dest);
267    if (len < maxlen-1) {
268       strncpy(dest+len, src.c_str(), maxlen-len-1);
269    }
270    dest[maxlen-1] = 0;
271    return dest;
272 }
273 
274 /*
275  * Allows one or both pointers to be NULL
276  */
bstrcmp(const char * s1,const char * s2)277 bool bstrcmp(const char *s1, const char *s2)
278 {
279    if (s1 == s2) return true;
280    if (s1 == NULL || s2 == NULL) return false;
281    return strcmp(s1, s2) == 0;
282 }
283 
284 /*
285  * Allows one or both pointers to be NULL
286  */
bstrcasecmp(const char * s1,const char * s2)287 bool bstrcasecmp(const char *s1, const char *s2)
288 {
289    if (s1 == s2) return true;
290    if (s1 == NULL || s2 == NULL) return false;
291    return strcasecmp(s1, s2) == 0;
292 }
293 
294 
295 /*
296  * Get character length of UTF-8 string
297  *
298  * Valid UTF-8 codes
299  * U-00000000 - U-0000007F: 0xxxxxxx
300  * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
301  * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
302  * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
303  * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
304  * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
305  */
cstrlen(const char * str)306 int cstrlen(const char *str)
307 {
308    uint8_t *p = (uint8_t *)str;
309    int len = 0;
310    if (str == NULL) {
311       return 0;
312    }
313    while (*p) {
314       if ((*p & 0xC0) != 0xC0) {
315          p++;
316          len++;
317          continue;
318       }
319       if ((*p & 0xD0) == 0xC0) {
320          p += 2;
321          len++;
322          continue;
323       }
324       if ((*p & 0xF0) == 0xD0) {
325          p += 3;
326          len++;
327          continue;
328       }
329       if ((*p & 0xF8) == 0xF0) {
330          p += 4;
331          len++;
332          continue;
333       }
334       if ((*p & 0xFC) == 0xF8) {
335          p += 5;
336          len++;
337          continue;
338       }
339       if ((*p & 0xFE) == 0xFC) {
340          p += 6;
341          len++;
342          continue;
343       }
344       p++;                      /* Shouln't get here but must advance */
345    }
346    return len;
347 }
348 
349 /* We need to disable the malloc() macro if SMARTALLOC is not used,
350  * else, it points to b_malloc() and causes problems.
351  */
352 #ifndef SMARTALLOC
353  #ifdef malloc
354   #undef malloc
355  #endif
356 #endif
357 
358 #ifndef bmalloc
bmalloc(size_t size)359 void *bmalloc(size_t size)
360 {
361   void *buf;
362 
363 #ifdef SMARTALLOC
364   buf = sm_malloc(file, line, size);
365 #else
366   buf = malloc(size);
367 #endif
368   if (buf == NULL) {
369      berrno be;
370      Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
371   }
372   return buf;
373 }
374 #endif
375 
b_malloc(const char * file,int line,size_t size)376 void *b_malloc(const char *file, int line, size_t size)
377 {
378   void *buf;
379 
380 #ifdef SMARTALLOC
381   buf = sm_malloc(file, line, size);
382 #else
383   buf = malloc(size);
384 #endif
385   if (buf == NULL) {
386      berrno be;
387      e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
388   }
389   return buf;
390 }
391 
392 
bfree(void * buf)393 void bfree(void *buf)
394 {
395 #ifdef SMARTALLOC
396   sm_free(__FILE__, __LINE__, buf);
397 #else
398   free(buf);
399 #endif
400 }
401 
brealloc(void * buf,size_t size)402 void *brealloc (void *buf, size_t size)
403 {
404 #ifdef SMARTALOC
405    buf = sm_realloc(__FILE__, __LINE__, buf, size);
406 #else
407    buf = realloc(buf, size);
408 #endif
409    if (buf == NULL) {
410       berrno be;
411       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
412    }
413    return buf;
414 }
415 
416 
bcalloc(size_t size1,size_t size2)417 void *bcalloc(size_t size1, size_t size2)
418 {
419   void *buf;
420 
421    buf = calloc(size1, size2);
422    if (buf == NULL) {
423       berrno be;
424       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
425    }
426    return buf;
427 }
428 
429 /* Code now in src/lib/bsnprintf.c */
430 #ifndef USE_BSNPRINTF
431 
432 #define BIG_BUF 5000
433 /*
434  * Implement snprintf
435  */
bsnprintf(char * str,int32_t size,const char * fmt,...)436 int bsnprintf(char *str, int32_t size, const char *fmt,  ...)
437 {
438    va_list   arg_ptr;
439    int len;
440 
441    va_start(arg_ptr, fmt);
442    len = bvsnprintf(str, size, fmt, arg_ptr);
443    va_end(arg_ptr);
444    return len;
445 }
446 
447 /*
448  * Implement vsnprintf()
449  */
bvsnprintf(char * str,int32_t size,const char * format,va_list ap)450 int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
451 {
452 #ifdef HAVE_VSNPRINTF
453    int len;
454    len = vsnprintf(str, size, format, ap);
455    str[size-1] = 0;
456    return len;
457 
458 #else
459 
460    int len, buflen;
461    char *buf;
462    buflen = size > BIG_BUF ? size : BIG_BUF;
463    buf = get_memory(buflen);
464    len = vsprintf(buf, format, ap);
465    if (len >= buflen) {
466       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
467    }
468    memcpy(str, buf, len);
469    str[len] = 0;                /* len excludes the null */
470    free_memory(buf);
471    return len;
472 #endif
473 }
474 #endif /* USE_BSNPRINTF */
475 
476 #ifndef HAVE_LOCALTIME_R
477 
localtime_r(const time_t * timep,struct tm * tm)478 struct tm *localtime_r(const time_t *timep, struct tm *tm)
479 {
480     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
481     struct tm *ltm,
482 
483     P(mutex);
484     ltm = localtime(timep);
485     if (ltm) {
486        memcpy(tm, ltm, sizeof(struct tm));
487     }
488     V(mutex);
489     return ltm ? tm : NULL;
490 }
491 #endif /* HAVE_LOCALTIME_R */
492 
493 #ifndef HAVE_WIN32
494 #include <dirent.h>
495 /*
496  * This is bacula own readdir function, that should be used instead of any
497  * other function
498  * This function is thread safe.
499  * Not all supported systems have a thread safe readdir() function
500  * This is why we are using a mutex.
501  *
502  * The name of the "next" file or directory is returned into d_name
503  * that can be resized to fit the size of the entry
504  *
505  * return 0 for OK
506  * return -1 for EOF
507  * return >0 is for error, the value returned is errno
508 */
breaddir(DIR * dirp,POOLMEM * & d_name)509 int breaddir(DIR *dirp, POOLMEM *&d_name)
510 {
511    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
512 
513    P(mutex);
514    errno = 0;
515    struct dirent *d=readdir(dirp);
516    int ret = errno;
517    if (d != NULL) {
518       pm_strcpy(d_name, d->d_name);
519       ret=0;
520    } else {
521       ret = errno==0?-1:errno; // -1 for EOF or errno for error
522    }
523    V(mutex);
524    return ret;
525 }
526 #endif
527 
b_strerror(int errnum,char * buf,size_t bufsiz)528 int b_strerror(int errnum, char *buf, size_t bufsiz)
529 {
530     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
531     int stat = 0;
532     const char *msg;
533 
534     P(mutex);
535 
536     msg = strerror(errnum);
537     if (!msg) {
538        msg = _("Bad errno");
539        stat = -1;
540     }
541     bstrncpy(buf, msg, bufsiz);
542     V(mutex);
543     return stat;
544 }
545 
546 #ifdef DEBUG_MEMSET
547 /* These routines are not normally turned on */
548 #undef memset
b_memset(const char * file,int line,void * mem,int val,size_t num)549 void b_memset(const char *file, int line, void *mem, int val, size_t num)
550 {
551    /* Testing for 2000 byte zero at beginning of Volume block */
552    if (num > 1900 && num < 3000) {
553       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
554    }
555    memset(mem, val, num);
556 }
557 #endif
558 
559 #if !defined(HAVE_WIN32)
560 static int del_pid_file_ok = FALSE;
561 #endif
562 static int pid_fd = -1;
563 
564 #ifdef HAVE_FCNTL_LOCK
565 /* a convenient function [un]lock file using fnctl()
566  * code must be in F_UNLCK, F_RDLCK, F_WRLCK
567  * return -1 for error and errno is set
568  */
fcntl_lock(int fd,int code)569 int fcntl_lock(int fd, int code)
570 {
571    struct flock l;
572    l.l_type = code;
573    l.l_whence = l.l_start = l.l_len = 0;
574    l.l_len = 1;
575    return fcntl(fd, F_SETLK, &l);
576 }
577 #endif
578 
579 /* Create a disk pid "lock" file
580  *  returns
581  *    0: Error with the error message in errmsg
582  *    1: Succcess
583  *    2: Successs, but a previous file was found
584  */
585 #if !defined(HAVE_FCNTL_LOCK) || defined(HAVE_WIN32)
create_lock_file(char * fname,const char * progname,const char * filetype,POOLMEM ** errmsg,int * fd)586 int create_lock_file(char *fname, const char *progname, const char *filetype, POOLMEM **errmsg, int *fd)
587 {
588    int ret = 1;
589 #if !defined(HAVE_WIN32)
590    int pidfd, len;
591    int oldpid;
592    char  pidbuf[20];
593    struct stat statp;
594 
595    if (stat(fname, &statp) == 0) {
596       /* File exists, see what we have */
597       *pidbuf = 0;
598       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
599            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
600            sscanf(pidbuf, "%d", &oldpid) != 1) {
601          berrno be;
602          Mmsg(errmsg, _("Cannot open %s file. %s ERR=%s\n"), filetype, fname,
603               be.bstrerror());
604          close(pidfd); /* if it was successfully opened */
605          return 0;
606       }
607       /* Some OSes (IRIX) don't bother to clean out the old pid files after a crash, and
608        * since they use a deterministic algorithm for assigning PIDs, we can have
609        * pid conflicts with the old PID file after a reboot.
610        * The intent the following code is to check if the oldpid read from the pid
611        * file is the same as the currently executing process's pid,
612        * and if oldpid == getpid(), skip the attempt to
613        * kill(oldpid,0), since the attempt is guaranteed to succeed,
614        * but the success won't actually mean that there is an
615        * another Bacula process already running.
616        * For more details see bug #797.
617        */
618        if ((oldpid != (int)getpid()) && (kill(oldpid, 0) != -1 || errno != ESRCH)) {
619           Mmsg(errmsg, _("%s is already running. pid=%d\nCheck file %s\n"),
620                progname, oldpid, fname);
621           return 0;
622       }
623       /* He is not alive, so take over file ownership */
624       unlink(fname);                  /* remove stale pid file */
625       ret = 2;
626    }
627    /* Create new pid file */
628    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
629       len = sprintf(pidbuf, "%d\n", (int)getpid());
630       write(pidfd, pidbuf, len);
631       close(pidfd);
632       /* ret is already 1 */
633    } else {
634       berrno be;
635       Mmsg(errmsg, _("Could not open %s file. %s ERR=%s\n"), filetype, fname, be.bstrerror());
636       return 0;
637    }
638 #endif
639    return ret;
640 }
641 #else /* defined(HAVE_FCNTL_LOCK) */
create_lock_file(char * fname,const char * progname,const char * filetype,POOLMEM ** errmsg,int * fd)642 int create_lock_file(char *fname, const char *progname, const char *filetype, POOLMEM **errmsg, int *fd)
643 {
644    int len;
645    int oldpid;
646    char pidbuf[20];
647 
648    /* Open the pidfile for writing */
649    if ((*fd = open(fname, O_CREAT|O_RDWR, 0640)) >= 0) {
650       if (fcntl_lock(*fd, F_WRLCK) == -1) {
651          berrno be;
652          /* already locked by someone else, try to read the pid */
653          if (read(*fd, &pidbuf, sizeof(pidbuf)) > 0 &&
654              sscanf(pidbuf, "%d", &oldpid) == 1) {
655             Mmsg(errmsg, _("%s is already running. pid=%d, check file %s\n"),
656                  progname, oldpid, fname);
657          } else {
658             Mmsg(errmsg, _("Cannot lock %s file. %s ERR=%s\n"), filetype, fname, be.bstrerror());
659          }
660          close(*fd);
661          *fd=-1;
662          return 0;
663       }
664       /* write the pid */
665       len = sprintf(pidbuf, "%d\n", (int)getpid());
666       write(*fd, pidbuf, len);
667       /* KEEP THE FILE OPEN TO KEEP THE LOCK !!! */
668       return 1;
669    } else {
670       berrno be;
671       Mmsg(errmsg, _("Cannot not open %s file. %s ERR=%s\n"), filetype, fname, be.bstrerror());
672       return 0;
673    }
674 }
675 #endif
676 
677 /*
678  * Create a standard "Unix" pid file.
679  */
create_pid_file(char * dir,const char * progname,int port)680 void create_pid_file(char *dir, const char *progname, int port)
681 {
682    POOLMEM *errmsg = get_pool_memory(PM_MESSAGE);
683    POOLMEM *fname = get_pool_memory(PM_FNAME);
684 
685    Mmsg(fname, "%s/%s.%d.pid", dir, progname, port);
686    if (create_lock_file(fname, progname, "pid", &errmsg, &pid_fd) == 0) {
687       Emsg1(M_ERROR_TERM, 0, "%s", errmsg);
688       /* never return */
689    }
690 #if !defined(HAVE_WIN32)
691    del_pid_file_ok = TRUE;         /* we created it so we can delete it */
692 #endif
693 
694    free_pool_memory(fname);
695    free_pool_memory(errmsg);
696 }
697 
698 /*
699  * Delete the pid file if we created it
700  */
delete_pid_file(char * dir,const char * progname,int port)701 int delete_pid_file(char *dir, const char *progname, int port)
702 {
703 #if !defined(HAVE_WIN32)
704    POOLMEM *fname = get_pool_memory(PM_FNAME);
705    if (pid_fd!=-1) {
706       close(pid_fd);
707    }
708    if (!del_pid_file_ok) {
709       free_pool_memory(fname);
710       return 0;
711    }
712    del_pid_file_ok = FALSE;
713    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
714    unlink(fname);
715    free_pool_memory(fname);
716 #endif
717    return 1;
718 }
719 
720 struct s_state_hdr {
721    char id[14];
722    int32_t version;
723    uint64_t last_jobs_addr;
724    uint64_t reserved[20];
725 };
726 
727 static struct s_state_hdr state_hdr = {
728    "Bacula State\n",
729    4,
730    0
731 };
732 
733 /*
734  * Open and read the state file for the daemon
735  */
read_state_file(char * dir,const char * progname,int port)736 void read_state_file(char *dir, const char *progname, int port)
737 {
738    int sfd;
739    ssize_t stat;
740    bool ok = false;
741    POOLMEM *fname = get_pool_memory(PM_FNAME);
742    struct s_state_hdr hdr;
743    int hdr_size = sizeof(hdr);
744 
745    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
746    /* If file exists, see what we have */
747 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
748    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
749       berrno be;
750       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
751             sfd, (int)sizeof(hdr), be.bstrerror());
752       goto bail_out;
753    }
754    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
755       berrno be;
756       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
757                     sfd, (int)stat, hdr_size, be.bstrerror());
758       goto bail_out;
759    }
760    if (hdr.version != state_hdr.version) {
761       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
762          state_hdr.version, hdr.version);
763       goto bail_out;
764    }
765    hdr.id[13] = 0;
766    if (strcmp(hdr.id, state_hdr.id) != 0) {
767       Dmsg0(000, "State file header id invalid.\n");
768       goto bail_out;
769    }
770 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
771    if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) {
772       goto bail_out;
773    }
774    ok = true;
775 bail_out:
776    if (sfd >= 0) {
777       close(sfd);
778    }
779    if (!ok) {
780       unlink(fname);
781     }
782    free_pool_memory(fname);
783 }
784 
785 /*
786  * Write the state file
787  */
788 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
789 
write_state_file(char * dir,const char * progname,int port)790 void write_state_file(char *dir, const char *progname, int port)
791 {
792    int sfd;
793    bool ok = false;
794    POOLMEM *fname = get_pool_memory(PM_FNAME);
795 
796    P(state_mutex);                    /* Only one job at a time can call here */
797    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
798    /* Create new state file */
799    unlink(fname);
800    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
801       berrno be;
802       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.bstrerror());
803       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.bstrerror());
804       goto bail_out;
805    }
806    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
807       berrno be;
808       Dmsg1(000, "Write hdr error: ERR=%s\n", be.bstrerror());
809       goto bail_out;
810    }
811 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
812    state_hdr.last_jobs_addr = sizeof(state_hdr);
813    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
814 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
815    if (lseek(sfd, 0, SEEK_SET) < 0) {
816       berrno be;
817       Dmsg1(000, "lseek error: ERR=%s\n", be.bstrerror());
818       goto bail_out;
819    }
820    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
821       berrno be;
822       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.bstrerror());
823       goto bail_out;
824    }
825    ok = true;
826 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
827 bail_out:
828    if (sfd >= 0) {
829       close(sfd);
830    }
831    if (!ok) {
832       unlink(fname);
833    }
834    V(state_mutex);
835    free_pool_memory(fname);
836 }
837 
838 
839 /* BSDI does not have this.  This is a *poor* simulation */
840 #ifndef HAVE_STRTOLL
841 long long int
strtoll(const char * ptr,char ** endptr,int base)842 strtoll(const char *ptr, char **endptr, int base)
843 {
844    return (long long int)strtod(ptr, endptr);
845 }
846 #endif
847 
848 /*
849  * Bacula's implementation of fgets(). The difference is that it handles
850  *   being interrupted by a signal (e.g. a SIGCHLD).
851  */
852 #undef fgetc
bfgets(char * s,int size,FILE * fd)853 char *bfgets(char *s, int size, FILE *fd)
854 {
855    char *p = s;
856    int ch;
857    *p = 0;
858    for (int i=0; i < size-1; i++) {
859       do {
860          errno = 0;
861          ch = fgetc(fd);
862       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
863       if (ch == EOF) {
864          if (i == 0) {
865             return NULL;
866          } else {
867             return s;
868          }
869       }
870       *p++ = ch;
871       *p = 0;
872       if (ch == '\r') { /* Support for Mac/Windows file format */
873          ch = fgetc(fd);
874          if (ch != '\n') { /* Mac (\r only) */
875             (void)ungetc(ch, fd); /* Push next character back to fd */
876          }
877          p[-1] = '\n';
878          break;
879       }
880       if (ch == '\n') {
881          break;
882       }
883    }
884    return s;
885 }
886 
887 /*
888  * Bacula's implementation of fgets(). The difference is that it handles
889  *   being interrupted by a signal (e.g. a SIGCHLD) and it has a
890  *   different calling sequence which implements input lines of
891  *   up to a million characters.
892  */
bfgets(POOLMEM * & s,FILE * fd)893 char *bfgets(POOLMEM *&s, FILE *fd)
894 {
895    int ch;
896    int soft_max;
897    int i = 0;
898 
899    s[0] = 0;
900    soft_max = sizeof_pool_memory(s) - 10;
901    for ( ;; ) {
902       do {
903          errno = 0;
904          ch = fgetc(fd);
905       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
906       if (ch == EOF) {
907          if (i == 0) {
908             return NULL;
909          } else {
910             return s;
911          }
912       }
913       if (i > soft_max) {
914          /* Insanity check */
915          if (soft_max > 1000000) {
916             return s;
917          }
918          s = check_pool_memory_size(s, soft_max+10000);
919          soft_max = sizeof_pool_memory(s) - 10;
920       }
921       s[i++] = ch;
922       s[i] = 0;
923       if (ch == '\r') { /* Support for Mac/Windows file format */
924          ch = fgetc(fd);
925          if (ch != '\n') { /* Mac (\r only) */
926             (void)ungetc(ch, fd); /* Push next character back to fd */
927          }
928          s[i-1] = '\n';
929          break;
930       }
931       if (ch == '\n') {
932          break;
933       }
934    }
935    return s;
936 }
937 
938 /*
939  * Make a "unique" filename.  It is important that if
940  *   called again with the same "what" that the result
941  *   will be identical. This allows us to use the file
942  *   without saving its name, and re-generate the name
943  *   so that it can be deleted.
944  */
make_unique_filename(POOLMEM ** name,int Id,char * what)945 void make_unique_filename(POOLMEM **name, int Id, char *what)
946 {
947    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
948 }
949 
escape_filename(const char * file_path)950 char *escape_filename(const char *file_path)
951 {
952    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
953       return NULL;
954    }
955 
956    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
957    char *cur_char = escaped_path;
958 
959    while (*file_path) {
960       if (*file_path == '\\' || *file_path == '"') {
961          *cur_char++ = '\\';
962       }
963 
964       *cur_char++ = *file_path++;
965    }
966 
967    *cur_char = '\0';
968 
969    return escaped_path;
970 }
971 
972 #if HAVE_BACKTRACE && HAVE_GCC && HAVE_LINUX_OS
973 /* if some names are not resolved you can try using : addr2line, like this
974  * $ addr2line -e bin/bacula-sd -a 0x43cd11
975  * OR
976  * use the the -rdynamic option in the linker, like this
977  * $ LDFLAGS="-rdynamic" make setup
978  */
979 #include <cxxabi.h>
980 #include <execinfo.h>
stack_trace()981 void stack_trace()
982 {
983    const size_t max_depth = 100;
984    size_t stack_depth;
985    void *stack_addrs[max_depth];
986    char **stack_strings;
987    char syscom[512];
988    BPIPE *bpipe;
989    bool ok;
990 
991    stack_depth = backtrace(stack_addrs, max_depth);
992    stack_strings = backtrace_symbols(stack_addrs, stack_depth);
993 
994    for (size_t i = 3; i < stack_depth; i++) {
995       size_t sz = 200; /* just a guess, template names will go much wider */
996       char *begin = 0, *end = 0, *final = 0;
997       /* find the parentheses and address offset surrounding the mangled name */
998       for (char *j = stack_strings[i]; *j; ++j) {
999          if (*j == '(') {
1000             begin = j;
1001          } else if (*j == '+') {
1002             end = j;
1003          } else if (*j == ')') {
1004             final = j;
1005          }
1006       }
1007       ok = false;
1008       if (begin && end && end>(begin+1)) {
1009          /* /home/bac/workspace2/bee/regress/bin/bacula-dir(+0x3c400) */
1010          char *function = (char *)actuallymalloc(sz);
1011          *begin++ = '\0';
1012          *end = '\0';
1013          /* found our mangled name, now in [begin, end] */
1014 
1015          int status;
1016          char *ret = abi::__cxa_demangle(begin, function, &sz, &status);
1017          if (ret) {
1018             /* return value may be a realloc() of the input */
1019             function = ret;
1020          } else {
1021             /* demangling failed, just pretend it's a C function with no args */
1022             bstrncpy(function, begin, sz);
1023             bstrncat(function, "()", sz);
1024          }
1025          Pmsg2(000, "    %s:%s\n", stack_strings[i], function);
1026          actuallyfree(function);
1027          ok = true;
1028       } else if (begin) {
1029          /* .../regress/bin/bacula-dir(+0x3c400) */
1030          /* demangle cannot work on an empty function name, use addr2line() */
1031          // this should work, but it don't
1032          // sprintf(syscom, "addr2line %p -e %.*s", stack_addrs[i], (int)(begin-stack_strings[i]), stack_strings[i]);
1033          // use the "+0x3c400" above for the address
1034          if (end && final) {
1035             snprintf(syscom, sizeof(syscom), "addr2line %.*s -e %.*s", (int)(final-end)-1, end+1, (int)(begin-stack_strings[i]), stack_strings[i]);
1036             bpipe = open_bpipe(syscom, 0, "r");
1037             if (bpipe) {
1038                char buf[1000];
1039                *buf = '\0';
1040                while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1041                   Pmsg1(000, "    %s\n", buf);
1042                }
1043                if (close_bpipe(bpipe) == 0) {
1044                   ok = true;
1045                }
1046             }
1047          }
1048       }
1049       if (!ok) {
1050          /* didn't find the mangled name, just print the whole line */
1051          Pmsg1(000, "    %s\n", stack_strings[i]);
1052       }
1053    }
1054    actuallyfree(stack_strings); /* malloc()ed by backtrace_symbols */
1055 }
1056 #include <sys/types.h>
1057 #include <sys/syscall.h>
1058 
gdb_get_threadid(char * name_buf,int len)1059 int gdb_get_threadid(char *name_buf, int len)
1060 {
1061    int thread_num = -1;
1062    char syscom[1024];
1063    BPIPE *bpipe;
1064 
1065    int systag = syscall(__NR_gettid);
1066 
1067    name_buf[readlink("/proc/self/exe", name_buf, len-1)]=0;
1068    snprintf(syscom, sizeof(syscom), "gdb --batch -n -ex \"thread find %d\" %s %d", systag, name_buf, getpid());
1069    bpipe = open_bpipe(syscom, 0, "r");
1070    if (bpipe) {
1071       char buf[1000];
1072       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1073          // thread find 241041
1074          // Thread 7 has target id 'Thread 0x7f8c62ffd700 (LWP 241041)'
1075          int tn;
1076          if (scan_string(buf, "Thread %d", &tn)==1) {
1077             thread_num = tn;
1078          }
1079       }
1080       if (close_bpipe(bpipe) !=0) {
1081          return -1;
1082       }
1083    } else {
1084       return -1;
1085    }
1086    return thread_num;
1087 }
1088 
gdb_stack_trace()1089 void gdb_stack_trace()
1090 {
1091    char name_buf[512];
1092    char syscom[1024];
1093    BPIPE *bpipe;
1094 
1095    int thread_num = gdb_get_threadid(name_buf, sizeof(name_buf));
1096    if (thread_num < 0) {
1097       return;
1098    }
1099    snprintf(syscom, sizeof(syscom), "gdb --batch -n -ex \"thread apply %d bt\" %s %d", thread_num, name_buf, getpid());
1100    bpipe = open_bpipe(syscom, 0, "r");
1101    if (bpipe) {
1102       bool ok = false;
1103       char buf[1000];
1104       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1105          if (!ok) {
1106             // Skip the "header" up to the caller of gdb_stack_trace()
1107             ok = strstr(buf, "in gdb_stack_trace")!=NULL;
1108          } else {
1109             Pmsg1(000, "    %s", buf);
1110          }
1111       }
1112       if (close_bpipe(bpipe) !=0) {
1113          return;
1114       }
1115    }
1116 }
1117 
gdb_print_local(int level)1118 void gdb_print_local(int level)
1119 {
1120    char name_buf[512];
1121    char syscom[1024];
1122    char fname[64];
1123    int fd;
1124    FILE *fp;
1125    BPIPE *bpipe = NULL;
1126    int thread_num = gdb_get_threadid(name_buf, sizeof(name_buf));
1127    if (thread_num < 0) {
1128       return;
1129    }
1130    bstrncpy(fname, "/tmp/traces.XXXXXX", sizeof(fname));
1131    fd = mkstemp(fname);
1132    if (fd < 0) {
1133       return;
1134    }
1135    fp = fdopen(fd, "w");
1136    if (!fp) {
1137       goto bail_out;
1138    }
1139    fprintf(fp, "thread %d\nf %d\nprint \":here:\"\ninfo locals\ndetach\nquit\n", thread_num, level + 5);
1140    fclose(fp);
1141    snprintf(syscom, sizeof(syscom), "gdb -quiet --batch -x %s %s %d", fname, name_buf, getpid());
1142    bpipe = open_bpipe(syscom, 0, "r");
1143    if (bpipe) {
1144       bool ok = false;
1145       char buf[1000];
1146       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1147          if (!ok) {
1148             // Skip the "header" up to the caller of gdb_stack_trace()
1149             ok = strstr(buf, ":here:")!=NULL;
1150          } else {
1151             Pmsg1(000, "    %s", buf);
1152          }
1153       }
1154    }
1155 bail_out:
1156    unlink(fname);
1157    if (bpipe) {
1158       close_bpipe(bpipe);
1159    }
1160 
1161 }
1162 
1163 #else /* HAVE_BACKTRACE && HAVE_GCC */
stack_trace()1164 void stack_trace() {}
gdb_stack_trace()1165 void gdb_stack_trace() {}
gdb_print_local()1166 void gdb_print_local() {}
1167 #endif /* HAVE_BACKTRACE && HAVE_GCC */
1168 
1169 #ifdef HAVE_SYS_STATVFS_H
1170 #include <sys/statvfs.h>
1171 #else
1172 #define statvfs statfs
1173 #endif
1174 /* statvfs.h defines ST_APPEND, which is also used by Bacula */
1175 #undef ST_APPEND
1176 
1177 
fs_get_free_space(const char * path,int64_t * freeval,int64_t * totalval)1178 int fs_get_free_space(const char *path, int64_t *freeval, int64_t *totalval)
1179 {
1180 #if defined(HAVE_SYS_STATVFS_H) || !defined(HAVE_WIN32)
1181    struct statvfs st;
1182 
1183    if (statvfs(path, &st) == 0) {
1184       *freeval  = (uint64_t)st.f_bavail * (uint64_t)st.f_frsize;
1185       *totalval = (uint64_t)st.f_blocks * (uint64_t)st.f_frsize;
1186       return 0;
1187    }
1188 #endif
1189 
1190    *totalval = *freeval = 0;
1191    return -1;
1192 }
1193 
1194 #if defined(HAVE_DARWIN_OS)
1195 #include <malloc/malloc.h>
1196 #endif
1197 
1198 /*
1199  * Determine the amount of heap used
1200  * macOS - sbrk(0) is deprecated, use malloc info
1201  * Windows - not implemented
1202  * others - use sbrk(0)
1203  */
1204 
1205 /* the initial heap value */
1206 static int64_t start_heap = 0;
1207 
mark_heap()1208 void mark_heap()
1209 {
1210 #if defined(HAVE_WIN32)
1211    start_heap = 0;
1212 #elif defined(HAVE_DARWIN_OS)
1213    struct mstats ms = mstats();
1214    start_heap = (int64_t) ms.bytes_used;
1215 #else
1216    start_heap = (int64_t) sbrk(0);
1217 #endif
1218 }
1219 
heap_used()1220 int64_t heap_used()
1221 {
1222 #if defined(HAVE_WIN32)
1223    return get_memory_info(NULL, 0);
1224 #elif defined(HAVE_DARWIN_OS)
1225    struct mstats ms = mstats();
1226    return (int64_t) ms.bytes_used - start_heap;
1227 #else
1228    return (int64_t) sbrk(0) - start_heap;
1229 #endif
1230 }
1231 
1232 /*
1233  * This function is used after a fork, the memory manager is not be initialized
1234  * properly, so we must stay simple.
1235  */
setup_env(char * envp[])1236 void setup_env(char *envp[])
1237 {
1238    if (envp) {
1239 #if defined(HAVE_SETENV)
1240       char *p;
1241       for (int i=0; envp[i] ; i++) {
1242          p = strchr(envp[i], '='); /* HOME=/tmp */
1243          if (p) {
1244             *p=0;                       /* HOME\0tmp\0 */
1245             setenv(envp[i], p+1, true);
1246             *p='=';
1247          }
1248       }
1249 #elif defined(HAVE_PUTENV)
1250       for (int i=0; envp[i] ; i++) {
1251          putenv(envp[i]);
1252       }
1253 #else
1254 #error "putenv() and setenv() are not available on this system"
1255 #endif
1256    }
1257 }
1258 
1259 /* Small function to copy a file somewhere else,
1260  * for debug purpose.
1261  */
1262 #ifndef HAVE_WIN32
copyfile(const char * src,const char * dst)1263 int copyfile(const char *src, const char *dst)
1264 {
1265    int     fd_src=-1, fd_dst=-1;
1266    ssize_t len, lenw;
1267    char    buf[4096];
1268    berrno  be;
1269    fd_src = open(src, O_RDONLY);
1270    if (fd_src < 0) {
1271       Dmsg2(0, "Unable to open %s ERR=%s\n", src, be.bstrerror(errno));
1272       goto bail_out;
1273    }
1274    fd_dst = open(dst, O_WRONLY | O_CREAT | O_EXCL, 0600);
1275    if (fd_dst < 0) {
1276       Dmsg2(0, "Unable to open %s ERR=%s\n", dst, be.bstrerror(errno));
1277       goto bail_out;
1278    }
1279 
1280    while ((len = read(fd_src, buf, sizeof(buf))) > 0)
1281     {
1282         char *out_ptr = buf;
1283         do {
1284             lenw = write(fd_dst, out_ptr, len);
1285             if (lenw >= 0) {
1286                 len -= lenw;
1287                 out_ptr += lenw;
1288             } else if (errno != EINTR) {
1289                Dmsg3(0, "Unable to write %d bytes in %s. ERR=%s\n", len, dst, be.bstrerror(errno));
1290                goto bail_out;
1291             }
1292         } while (len > 0);
1293     }
1294 
1295     if (len == 0) {
1296        close(fd_src);
1297        if (close(fd_dst) < 0) {
1298           Dmsg2(0, "Unable to close %s properly. ERR=%s\n", dst, be.bstrerror(errno));
1299           return -1;
1300        }
1301        /* Success! */
1302        return 0;
1303     }
1304 bail_out:
1305     close(fd_src);
1306     close(fd_dst);
1307     return -1;
1308 }
1309 #else
1310 
copyfile(const char * src,const char * dst)1311 int copyfile(const char *src, const char *dst)
1312 {
1313     if (CopyFile((LPCSTR) src, (LPCSTR) dst, false)) {
1314        return 0;
1315     }
1316 
1317     return -1;
1318 }
1319 
1320 #endif
1321 
1322 
1323 /* The poll() code is currently disabled */
1324 #ifdef HAVE_POLL
1325 
1326 #include <poll.h>
1327 #define NB_EVENT 1
1328 
fd_wait_data(int fd,fd_wait_mode mode,int sec,int msec)1329 int fd_wait_data(int fd, fd_wait_mode mode, int sec, int msec)
1330 {
1331    int ret;
1332    struct pollfd fds[NB_EVENT]; /* The structure for one event */
1333 
1334    fds[0].fd = fd;
1335    fds[0].events = (mode == WAIT_READ) ? POLLIN : POLLOUT;
1336 
1337    ret = poll(fds, NB_EVENT, sec * 1000 + msec);
1338 
1339    /* Check if poll actually succeed */
1340    switch(ret) {
1341    case 0:                      /* timeout; no event detected */
1342       return 0;
1343 
1344    case -1:                     /* report error and abort */
1345       return -1;
1346 
1347    default:
1348       if (fds[0].revents & POLLIN || fds[0].revents & POLLOUT) {
1349          return 1;
1350 
1351       } else {
1352          return -1;             /* unexpected... */
1353       }
1354    }
1355    return -1;                   /* unexpected... */
1356 }
1357 #else
1358 
1359 /* The select() code with a bigger fd_set was tested on Linux, FreeBSD and SunOS */
1360 #if defined(HAVE_LINUX_OS) || defined(HAVE_FREEBSD_OS) || defined(HAVE_SUN_OS) || defined(HAVE_WIN32)
1361  #define SELECT_MAX_FD 7990
1362 #else
1363  #define SELECT_MAX_FD 1023     /* For others, we keep it low */
1364 #endif
1365 
fd_wait_data(int fd,fd_wait_mode mode,int sec,int msec)1366 int fd_wait_data(int fd, fd_wait_mode mode, int sec, int msec)
1367 {
1368    union {
1369       fd_set fdset;
1370       char bfd_buf[1000];
1371    };
1372 
1373    fd_set *pfdset=NULL, *tmp=NULL;
1374    struct timeval tv;
1375    int ret;
1376 
1377    /* If the amount of static memory is not big enough to handle the file
1378     * descriptor, we allocate a new buffer ourself
1379     */
1380    if (fd > SELECT_MAX_FD) {
1381       int len = (fd+1+1024) * sizeof(char);
1382       tmp = (fd_set *) malloc(len);
1383       pfdset = tmp;
1384       memset(tmp, 0, len);      /* FD_ZERO() */
1385 
1386    } else {
1387       pfdset = &fdset;
1388       memset(&bfd_buf, 0, sizeof(bfd_buf)); /* FD_ZERO(&fdset) */
1389    }
1390 
1391    FD_SET((unsigned)fd, pfdset);
1392 
1393    tv.tv_sec = sec;
1394    tv.tv_usec = msec * 1000;
1395 
1396    if (mode == WAIT_READ) {
1397       ret = select(fd + 1, pfdset, NULL, NULL, &tv);
1398 
1399    } else { /* WAIT_WRITE */
1400       ret = select(fd + 1, NULL, pfdset, NULL, &tv);
1401    }
1402    if (tmp) {
1403       free(tmp);
1404    }
1405    switch (ret) {
1406    case 0:                      /* timeout */
1407       return 0;
1408    case -1:
1409       return -1;                /* error return */
1410    default:
1411       break;
1412    }
1413    return 1;
1414 }
1415 #endif
1416 
1417 /* Use SOCK_CLOEXEC option when calling accept(). If not available,
1418  * do it ourself (but with a race condition...)
1419  */
baccept(int sockfd,struct sockaddr * addr,socklen_t * addrlen)1420 int baccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
1421 {
1422    int fd;
1423 #ifdef HAVE_ACCEPT4
1424    fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
1425 #else
1426    fd = accept(sockfd, addr, addrlen);
1427 
1428 # ifdef HAVE_DECL_FD_CLOEXEC
1429    if (fd >= 0) {
1430       int tmp_errno = errno;
1431       if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) {
1432          berrno be;
1433          Dmsg2(0, "Unable to set the CLOEXEC flag on fd=%d ERR=%s\n", fd, be.bstrerror());
1434       }
1435       errno = tmp_errno;
1436    }
1437 
1438 # endif  /* HAVE_DECL_FD_CLOEXEC */
1439 #endif   /* HAVE_ACCEPT4 */
1440    return fd;
1441 }
1442 
1443 /* Return the memory available on this system, 0 if not implemented */
1444 /* See https://github.com/ganglia/monitor-core/tree/master/libmetrics to have
1445  * an implementation for all kind of systems (from windows, solaris, aix...)
1446  * mem_free_func()
1447  */
bget_os_memory()1448 uint64_t bget_os_memory()
1449 {
1450    POOLMEM *buf=NULL;
1451    uint64_t ret = 0;
1452 
1453 #ifdef HAVE_LINUX_OS
1454    bool ok=true;
1455    const char *keyword="MemTotal:";
1456    static int len=strlen(keyword);
1457    FILE *fp = bfopen("/proc/meminfo", "r");
1458 
1459    if (!fp) {
1460       berrno be;
1461       Dmsg1(10, "Unable to open /proc/meminfo. ERR=%s\n", be.bstrerror());
1462       goto bail_out;
1463    }
1464 
1465    buf = get_pool_memory(PM_FNAME);
1466    while (ok && bfgets(buf, fp)) {
1467       if (strcmp(buf, keyword) > 0) {
1468          if (!size_to_uint64(buf+len, strlen(buf+len), &ret)) {
1469             ret = 0;
1470          }
1471          ok=false;
1472       }
1473    }
1474    fclose(fp);
1475 
1476 bail_out:
1477 #endif  /* TODO: Implement more systems as needed */
1478 
1479    free_and_null_pool_memory(buf);
1480    return ret;
1481 }
1482 
1483 /* Determine the amount of mlock memory we can allocate on the current
1484  * system. If the value is < 0, this is the memory to keep for the os.
1485  */
bget_max_mlock(int64_t value)1486 uint64_t bget_max_mlock(int64_t value)
1487 {
1488    uint64_t sys, val;
1489 
1490    sys = bget_os_memory();
1491    if (sys == 0) {
1492       Dmsg0(50, "Unable to determine the memory for mlock_max\n");
1493       if (value < 0) {          /* We cannot compute the number  */
1494          return 0;
1495       }
1496       return value;             /* We can't say our word... */
1497    }
1498 
1499    if (value == 0) {
1500       Dmsg0(50, "Limit not set, use the maximum for mlock_max\n");
1501       value = sys;              /* Limit automatically to the maximum */
1502    }
1503 
1504    /* When the value is negative, this is the amount in bytes to keep for the
1505     * system.
1506     */
1507    if (value < 0) {
1508       value = sys + value;
1509       if (value < 0) {
1510          Dmsg0(50, "Limit incorrect set, use the maximum for mlock_max\n");
1511          /* Request to keep 2GB, we have only 1GB, something is incorrect, so
1512           * we take the maximum
1513           */
1514          value = sys;
1515       }
1516    }
1517 
1518    /*
1519     * Min     Max  | Allowed
1520     *--------------+------------
1521     * 0    -> 2GB  | 0   -> 1GB
1522     * 2GB  -> 10GB | 1GB -> 9GB
1523     * 10GB -> 60GB | 9GB -> 54GB
1524     * 60GB -> ...  | 54GB ...
1525     *
1526     */
1527    val = value;
1528    if (sys < 2*1024*1024*1024LL) {
1529       /* If we have less than 2GB of ram, we can allow up to 50% */
1530       val = MIN(sys * 0.5, val);
1531 
1532    } else if (sys < 10*1024*1024*1024LL) {
1533       /* If we have a lot of memory, keep at least 1G for the system */
1534       val = MIN(sys - 1*1024*1024*1024LL, val);
1535 
1536    } else if (sys < 60*1024*1024*1024LL) {
1537       /* Below 60GB of ram, keep 10% for the system */
1538       val = MIN(sys * 0.9, val);
1539 
1540    } else {
1541       /* For very large systems, keep 6G of ram */
1542       val = MIN(sys - 6*1024*1024*1024LL, val);
1543    }
1544    Dmsg2(50, "Requested %lld can %lld\n", value, val);
1545    return val;
1546 }
1547 
1548 #undef fopen
bfopen(const char * path,const char * mode)1549 FILE *bfopen(const char *path, const char *mode)
1550 {
1551    FILE *fp;
1552    char options[50];
1553 
1554    bstrncpy(options, mode, sizeof(options));
1555 
1556 #if defined(HAVE_STREAM_CLOEXEC)
1557    bstrncat(options, STREAM_CLOEXEC, sizeof(options));
1558 #endif
1559 
1560    fp = fopen(path, options);
1561 
1562 #if !defined(HAVE_STREAM_CLOEXEC) && defined(HAVE_DECL_FD_CLOEXEC)
1563    if (fp) {
1564       int fd = fileno(fp);
1565       if (fd >= 0) {
1566          int tmp_errno = errno;
1567          if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) {
1568             berrno be;
1569             Dmsg2(0, "Unable to set the CLOEXEC flag on fd=%d ERR=%s\n", fd, be.bstrerror());
1570          }
1571          errno = tmp_errno;
1572       }
1573    }
1574 #endif
1575    return fp;
1576 }
1577 
1578 /* Used to test the program */
1579 static int init_size=1024;
1580 static int dbglevel=500;
1581 
1582 /* alist(100, owned_by_alist) */
1583 /* return 0: ok, -1: error, 1: not found
1584  * Will return a list of users for a group. We look for /etc/groups
1585  * and in /etc/passwd
1586  */
get_group_members(const char * name,alist * users)1587 int get_group_members(const char *name, alist *users)
1588 {
1589    int ret = -1;
1590    /* Need to create implementation for other OSes */
1591 #ifdef HAVE_LINUX_OS
1592 #ifndef __ANDROID__
1593    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1594    struct group grp, *pgrp;
1595    struct passwd pw, *ppw;
1596    char *buf = NULL;
1597    int size = init_size;
1598    gid_t gid = 0;
1599    bool loop;
1600 
1601 again:
1602    buf = (char *) realloc(buf, size);
1603    errno = 0;
1604    ret = getgrnam_r(name, &grp, buf, size, &pgrp);
1605    if (ret == ERANGE) {
1606       if (size > 1000000) {
1607          ret = -1;
1608          goto bail_out;
1609       }
1610       Dmsg2(DT_MEMORY|dbglevel, "realloc from %d to %d\n", size, 2*size);
1611       size = 2*size;
1612       goto again;
1613 
1614    } else if (ret == EINTR) {
1615       goto again;
1616 
1617    } else if (ret != 0) {
1618       berrno be;
1619       Dmsg1(dbglevel, "Got error for getgrnam_r %s\n", be.bstrerror(ret));
1620       ret = -1;
1621       goto bail_out;
1622 
1623    } else if (pgrp == NULL) {   /* Not found */
1624       Dmsg1(dbglevel, "group %s not found\n", name);
1625       ret = 1;
1626       goto bail_out;
1627 
1628    } else {
1629       Dmsg1(dbglevel, "Got group definition for %s\n", name);
1630    }
1631 
1632    gid = grp.gr_gid;
1633    for (char **p = grp.gr_mem; p && *p ; p++) {
1634       Dmsg1(dbglevel, "Group Member is: %s\n", *p);
1635       users->append(bstrdup(*p));
1636    }
1637 
1638    P(mutex);
1639    setpwent();
1640    do {
1641       loop=false;
1642       errno = 0;
1643       ret = getpwent_r(&pw, buf, size, &ppw);
1644       if (ret == ERANGE) {
1645          if (size > 1000000) {
1646             ret = -1;
1647             endpwent();
1648             V(mutex);
1649             goto bail_out;
1650          }
1651          Dmsg2(DT_MEMORY|dbglevel, "realloc from %d to %d\n", size, 2*size);
1652          size = 2*size;
1653          buf = (char *)realloc(buf, size);
1654          loop=true;
1655 
1656       } else if (ret == ENOENT) {
1657          Dmsg0(dbglevel, "End of loop\n");
1658          ppw = NULL;
1659          ret = 0;
1660 
1661       } else if (ret != 0) {
1662          berrno be;
1663          Dmsg2(dbglevel, "Got error for getpwent_r %d ERR=%s\n", ret, be.bstrerror());
1664          ret = -1;
1665          ppw = NULL;
1666 
1667       } else {
1668          Dmsg1(dbglevel, "Got user %s\n", ppw->pw_name);
1669          if (ppw->pw_gid == gid) {
1670             Dmsg1(dbglevel, "Add %s\n", ppw->pw_name);
1671             users->append(bstrdup(ppw->pw_name));
1672          }
1673       }
1674    } while (ppw || loop);
1675    endpwent();
1676    V(mutex);
1677 
1678 bail_out:
1679    if (buf) {
1680       free(buf);
1681    }
1682 #endif // __ANDROID__
1683 #endif // HAVE_LINUX_OS
1684    return ret;
1685 }
1686 
1687 /* Get the home directory for a user
1688  * TODO: Need a Windows implementation
1689  */
get_user_home_directory(const char * user,POOLMEM * & home)1690 int get_user_home_directory(const char *user, POOLMEM *&home)
1691 {
1692    int ret=-1;
1693 
1694 #ifdef HAVE_LINUX_OS
1695    struct passwd pw, *ppw;
1696    int size = init_size;
1697    char *buf = (char *)malloc(size);
1698 
1699 again:
1700    errno = 0;
1701    ret =  getpwnam_r(user, &pw, buf, size, &ppw);
1702    if (ret == ERANGE) {
1703       if (size > 1000000) {
1704          ret = -1;
1705          goto bail_out;
1706       }
1707       Dmsg2(DT_MEMORY|dbglevel, "realloc from %d to %d\n", size, 2*size);
1708       size = 2*size;
1709       buf = (char *)realloc(buf, size);
1710       goto again;
1711    } else if (ret == EINTR) {
1712       goto again;
1713    } else if (ret != 0) {
1714       berrno be;
1715       Dmsg1(dbglevel, "Got error for getpwnam_r %s\n", be.bstrerror(ret));
1716       ret = -1;
1717    } else if (ppw == NULL) {
1718       Dmsg0(dbglevel, "User not found\n");
1719       ret = -1;
1720    }  else {
1721       Dmsg0(dbglevel, "Got user\n");
1722       pm_strcpy(home, ppw->pw_dir);
1723    }
1724 bail_out:
1725    if (buf) {
1726       free(buf);
1727    }
1728 #endif // HAVE_LINUX_OS
1729    return ret;
1730 }
1731 
1732 /* Get the list of the home directories for a given unix group */
get_home_directories(const char * grpname,alist * dirs)1733 int get_home_directories(const char *grpname, alist *dirs)
1734 {
1735    char *name;
1736    POOL_MEM dir;
1737    alist users(100, owned_by_alist);
1738    if (get_group_members(grpname, &users) == 0) {
1739       Dmsg1(dbglevel, "get_group_members() = %d\n", users.size());
1740       foreach_alist(name, &users) {
1741          Dmsg1(dbglevel, "Get home directory for %s\n", name);
1742          if (get_user_home_directory(name, dir.addr()) == 0) {
1743             dirs->append(bstrdup(dir.c_str()));
1744          }
1745       }
1746    }
1747    return (dirs->size() > 0) ? 0 : -1;
1748 }
1749 
1750 #ifdef TEST_PROGRAM
1751 
1752 #include "unittests.h"
1753 
1754 /* The main idea of the test is pretty simple, we have a writer and a reader, and
1755  * they wait a little bit to read or send data over the fifo.
1756  * So, for the first packets, the writer will wait, then the reader will wait
1757  * read/write requests should always be fast. Only the time of the fd_wait_data()
1758  * should be long.
1759  */
1760 #include "findlib/namedpipe.h"
1761 #define PIPENAME "/tmp/wait.pipe.%d"
1762 
1763 #define NBPACKETS 10
1764 #define BUFSIZE   128*512       /* The pipe size looks to be 65K */
1765 
1766 typedef struct {
1767    int       nb;
1768    pthread_t writer;
1769    pthread_t reader;
1770 } job;
1771 
1772 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
1773 pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
1774 int nb_ready=0;
1775 
th1(void * a)1776 void *th1(void *a)
1777 {
1778    NamedPipe p;
1779    int fd, r;
1780    btime_t s, e;
1781    ssize_t nb;
1782    char buf[BUFSIZE];
1783    job *j = (job *)a;
1784 
1785    namedpipe_init(&p);
1786    bsnprintf(buf, sizeof(buf), PIPENAME, j->nb);
1787    if (namedpipe_create(&p, buf, 0600) < 0) {
1788       berrno be;
1789       Dmsg2(0, "R: Unable to create the fifo %s. ERR=%s\n", buf, be.bstrerror());
1790       namedpipe_free(&p);
1791       exit(2);
1792    }
1793    fd = namedpipe_open(&p, buf, O_RDONLY);
1794    if (fd < 0) {
1795       berrno be;
1796       Dmsg2(0, "R: Unable to open the fifo %s. ERR=%s\n", buf, be.bstrerror());
1797       return NULL;
1798    }
1799    P(cond_mutex);
1800    nb_ready++;
1801    pthread_cond_wait(&cond, &cond_mutex);
1802    V(cond_mutex);
1803    for (int i = 0; i < NBPACKETS; i++) {
1804       if (i < (NBPACKETS/2)) {
1805          bmicrosleep(5, 0);
1806       }
1807       s = get_current_btime();
1808       r = fd_wait_data(fd, WAIT_READ, 10, 0);
1809       if (r > 0) {
1810          e = get_current_btime();
1811          Dmsg2(0, "Wait to read pkt %d %lldms\n",i, (int64_t) (e - s));
1812 
1813          if (i <= NBPACKETS/2) {
1814             ASSERT2((e-s) < 10000, "In the 1st phase, we are blocking the process");
1815          } else {
1816             ASSERT2((e-s) > 10000, "In the 2nd phase, the writer is slowing down things");
1817          }
1818 
1819          s = get_current_btime();
1820          nb = read(fd, buf, sizeof(buf));
1821          e = get_current_btime();
1822          Dmsg3(0, "Read pkt %d %d bytes in %lldms\n",i, (int)nb, (int64_t) (e - s));
1823          ASSERT2((e-s) < 10000, "The read operation should be FAST");
1824       }
1825    }
1826    namedpipe_free(&p);
1827    return NULL;
1828 }
1829 
th2(void * a)1830 void *th2(void *a)
1831 {
1832    NamedPipe p;
1833    btime_t s, e;
1834    job *j = (job *)a;
1835    char buf[BUFSIZE];
1836    int fd;
1837    ssize_t nb;
1838 
1839    bsnprintf(buf, sizeof(buf), PIPENAME, j->nb);
1840    namedpipe_init(&p);
1841    if (namedpipe_create(&p, buf, 0600) < 0) {
1842       berrno be;
1843       Dmsg2(0, "W: Unable to create the fifo %s. ERR=%s\n", buf, be.bstrerror());
1844       namedpipe_free(&p);
1845       exit(2);
1846    }
1847 
1848    fd = namedpipe_open(&p, buf, O_WRONLY);
1849    if (fd < 0) {
1850       berrno be;
1851       Dmsg2(0, "W: Unable to open the fifo %s. ERR=%s\n", buf, be.bstrerror());
1852       namedpipe_free(&p);
1853       exit(2);
1854    }
1855 
1856    P(cond_mutex);
1857    nb_ready++;
1858    pthread_cond_wait(&cond, &cond_mutex);
1859    V(cond_mutex);
1860 
1861    unlink(buf);
1862 
1863    for (int i=0; i < NBPACKETS; i++) {
1864       if (i > (NBPACKETS/2)) {
1865          bmicrosleep(5, 0);
1866       }
1867       s = get_current_btime();
1868       if (fd_wait_data(fd, WAIT_WRITE, 10, 0) > 0) {
1869          e = get_current_btime();
1870          Dmsg2(0, "Wait to write pkt %d %lldms\n",i, (int64_t) (e - s));
1871 
1872          if (i == 0 || i > NBPACKETS/2) { /* The first packet doesn't count */
1873             ASSERT2((e-s) < 100000, "In the 2nd phase, it's fast to send, we are the blocker");
1874          } else {
1875             ASSERT2((e-s) > 100000, "In the 1st phase, we wait for the reader");
1876          }
1877 
1878          s = get_current_btime();
1879          nb = write(fd, buf, sizeof(buf));
1880          e = get_current_btime();
1881          Dmsg3(0, "Wrote pkt %d %d bytes in %lldms\n", i, (int)nb, (int64_t) (e - s));
1882          ASSERT2((e-s) < 100000, "The write operation should never block");
1883       }
1884    }
1885    namedpipe_free(&p);
1886    return NULL;
1887 }
1888 
main(int argc,char ** argv)1889 int main(int argc, char **argv)
1890 {
1891    Unittests u("bsys", true);
1892    job pthread_list[10000];
1893    int j = (argc >= 2) ? atoi(argv[1]) : 1;
1894    int maxfd = (argc == 3) ? atoi(argv[2]) : 0;
1895    uint64_t mem = bget_os_memory();
1896    Dmsg1(0, "mem:  %lld\n", mem);
1897    Dmsg1(0, "max1: %lld\n", bget_max_mlock(mem));
1898    Dmsg1(0, "max2: %lld\n", bget_max_mlock(-mem));
1899    Dmsg1(0, "max3: %lld\n", bget_max_mlock(-100000));
1900    Dmsg1(0, "max4: %lld\n", bget_max_mlock(mem+10000));
1901    Dmsg1(0, "max5: %lld\n", bget_max_mlock(mem-10000));
1902 
1903    j = MIN(10000, j);
1904    lmgr_init_thread();
1905    set_debug_flags((char *)"h");
1906 
1907    for (int i=3; i < maxfd; i++) {
1908       open("/dev/null", O_RDONLY);
1909    }
1910 
1911    for (int i=0; i < j; i++) {
1912       pthread_list[i].nb=i;
1913       pthread_create(&pthread_list[i].writer, NULL, th2, &pthread_list[i]);
1914       pthread_create(&pthread_list[i].reader, NULL, th1, &pthread_list[i]);
1915    }
1916 
1917    while (nb_ready < j*2) {
1918       bmicrosleep(1, 0);
1919    }
1920 
1921    Dmsg0(0, "All threads are started\n");
1922    P(cond_mutex);
1923    pthread_cond_broadcast(&cond);
1924    V(cond_mutex);
1925 
1926    for (int i=0; i < j; i++) {
1927       pthread_join(pthread_list[i].writer, NULL);
1928       pthread_join(pthread_list[i].reader, NULL);
1929    }
1930 
1931    for (int i=3; i < maxfd; i++) {
1932       close(i);
1933    }
1934 
1935    /* Start with a small buffer to test if we increase it */
1936    init_size=20;
1937    dbglevel=0;
1938    debug_level=DT_MEMORY;
1939    alist a(100, owned_by_alist);
1940    POOL_MEM home;
1941    char *name;
1942    int ret;
1943 
1944    ret = get_group_members("bin", &a);
1945    ok(ret == 0, "get_group_members()");
1946    ok(a.size() > 0, "get_group_members() size");
1947 
1948    foreach_alist(name, &a) {
1949       Pmsg1(0, "%s\n", name);
1950    }
1951    a.destroy();
1952 
1953    ret = get_home_directories("bin", &a);
1954    ok(ret == 0, "get_home_directories()");
1955    ok(a.size() > 0, "get_home_directories(users)");
1956    foreach_alist(name, &a) {
1957       Pmsg1(0, "%s\n", name);
1958    }
1959 
1960    ok(get_user_home_directory("root", home.addr()) == 0, "get_user_home_directory()");
1961 
1962    return report();
1963 }
1964 #endif
1965