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