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