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