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