]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
f37f4cf1519eec37094302384419540f6fda920f
[bacula/bacula] / bacula / src / lib / bsys.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Miscellaneous Bacula memory and thread safe routines
30  *   Generally, these are interfaces to system or standard
31  *   library routines.
32  *
33  *  Bacula utility functions are in util.c
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #ifdef HAVE_PWD_H
40 #include <pwd.h>
41 #endif
42 #ifdef HAVE_GRP_H
43 #include <grp.h>
44 #endif
45
46 #ifdef HAVE_AIX_OS
47 extern "C" int initgroups(const char *,int);
48 #endif
49
50
51 static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
52 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
53
54 /*
55  * This routine will sleep (sec, microsec).  Note, however, that if a
56  *   signal occurs, it will return early.  It is up to the caller
57  *   to recall this routine if he/she REALLY wants to sleep the
58  *   requested time.
59  */
60 int bmicrosleep(time_t sec, long usec)
61 {
62    struct timespec timeout;
63    struct timeval tv;
64    struct timezone tz;
65    int stat;
66
67    timeout.tv_sec = sec;
68    timeout.tv_nsec = usec * 1000;
69
70 #ifdef HAVE_NANOSLEEP
71    stat = nanosleep(&timeout, NULL);
72    if (!(stat < 0 && errno == ENOSYS)) {
73       return stat;
74    }
75    /* If we reach here it is because nanosleep is not supported by the OS */
76 #endif
77
78    /* Do it the old way */
79    gettimeofday(&tv, &tz);
80    timeout.tv_nsec += tv.tv_usec * 1000;
81    timeout.tv_sec += tv.tv_sec;
82    while (timeout.tv_nsec >= 1000000000) {
83       timeout.tv_nsec -= 1000000000;
84       timeout.tv_sec++;
85    }
86
87    Dmsg2(200, "pthread_cond_timedwait sec=%d usec=%d\n", sec, usec);
88    /* Note, this unlocks mutex during the sleep */
89    P(timer_mutex);
90    stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout);
91    if (stat != 0) {
92       berrno be;
93       Dmsg2(200, "pthread_cond_timedwait stat=%d ERR=%s\n", stat,
94          be.bstrerror(stat));
95    }
96    V(timer_mutex);
97    return stat;
98 }
99
100 /*
101  * Guarantee that the string is properly terminated */
102 char *bstrncpy(char *dest, const char *src, int maxlen)
103 {
104    strncpy(dest, src, maxlen-1);
105    dest[maxlen-1] = 0;
106    return dest;
107 }
108
109 /*
110  * Guarantee that the string is properly terminated */
111 char *bstrncpy(char *dest, POOL_MEM &src, int maxlen)
112 {
113    strncpy(dest, src.c_str(), maxlen-1);
114    dest[maxlen-1] = 0;
115    return dest;
116 }
117
118
119 char *bstrncat(char *dest, const char *src, int maxlen)
120 {
121    strncat(dest, src, maxlen-1);
122    dest[maxlen-1] = 0;
123    return dest;
124 }
125
126 char *bstrncat(char *dest, POOL_MEM &src, int maxlen)
127 {
128    strncat(dest, src.c_str(), maxlen-1);
129    dest[maxlen-1] = 0;
130    return dest;
131 }
132
133 /*
134  * Allows one or both pointers to be NULL
135  */
136 bool bstrcmp(const char *s1, const char *s2)
137 {
138    if (s1 == s2) return true;
139    if (s1 == NULL || s2 == NULL) return false;
140    return strcmp(s1, s2) == 0;
141 }
142
143 /*
144  * Get character length of UTF-8 string
145  *
146  * Valid UTF-8 codes
147  * U-00000000 - U-0000007F: 0xxxxxxx 
148  * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 
149  * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
150  * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
151  * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
152  * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
153  */
154 int cstrlen(const char *str)
155 {
156    uint8_t *p = (uint8_t *)str;
157    int len = 0;
158    while (*p) {
159       if ((*p & 0xC0) != 0xC0) {
160          p++;
161          len++;
162          continue;
163       }
164       if ((*p & 0xD0) == 0xC0) {
165          p += 2;
166          len++;
167          continue;
168       }
169       if ((*p & 0xF0) == 0xD0) {
170          p += 3;
171          len++;
172          continue;
173       }
174       if ((*p & 0xF8) == 0xF0) {
175          p += 4;
176          len++;
177          continue;
178       }
179       if ((*p & 0xFC) == 0xF8) {
180          p += 5;
181          len++;
182          continue;
183       }
184       if ((*p & 0xFE) == 0xFC) {
185          p += 6;
186          len++;
187          continue;
188       }
189       p++;                      /* Shouln't get here but must advance */
190    }
191    return len;
192 }
193
194
195
196 #ifndef bmalloc
197 void *bmalloc(size_t size)
198 {
199   void *buf;
200
201 #ifdef SMARTALLOC
202   buf = sm_malloc(file, line, size);
203 #else
204   buf = malloc(size);
205 #endif
206   if (buf == NULL) {
207      berrno be;
208      Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
209   }
210   return buf;
211 }
212 #endif
213
214 void *b_malloc(const char *file, int line, size_t size)
215 {
216   void *buf;
217
218 #ifdef SMARTALLOC
219   buf = sm_malloc(file, line, size);
220 #else
221   buf = malloc(size);
222 #endif
223   if (buf == NULL) {
224      berrno be;
225      e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
226   }
227   return buf;
228 }
229
230
231 void bfree(void *buf)
232 {
233 #ifdef SMARTALLOC
234   sm_free(__FILE__, __LINE__, buf);
235 #else
236   free(buf);
237 #endif
238 }
239
240 void *brealloc (void *buf, size_t size)
241 {
242 #ifdef SMARTALOC
243    buf = sm_realloc(__FILE__, __LINE__, buf, size);
244 #else
245    buf = realloc(buf, size);
246 #endif
247    if (buf == NULL) {
248       berrno be;
249       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
250    }
251    return buf;
252 }
253
254
255 void *bcalloc(size_t size1, size_t size2)
256 {
257   void *buf;
258
259    buf = calloc(size1, size2);
260    if (buf == NULL) {
261       berrno be;
262       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.bstrerror());
263    }
264    return buf;
265 }
266
267 /* Code now in src/lib/bsnprintf.c */
268 #ifndef USE_BSNPRINTF
269
270 #define BIG_BUF 5000
271 /*
272  * Implement snprintf
273  */
274 int bsnprintf(char *str, int32_t size, const char *fmt,  ...)
275 {
276    va_list   arg_ptr;
277    int len;
278
279    va_start(arg_ptr, fmt);
280    len = bvsnprintf(str, size, fmt, arg_ptr);
281    va_end(arg_ptr);
282    return len;
283 }
284
285 /*
286  * Implement vsnprintf()
287  */
288 int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
289 {
290 #ifdef HAVE_VSNPRINTF
291    int len;
292    len = vsnprintf(str, size, format, ap);
293    str[size-1] = 0;
294    return len;
295
296 #else
297
298    int len, buflen;
299    char *buf;
300    buflen = size > BIG_BUF ? size : BIG_BUF;
301    buf = get_memory(buflen);
302    len = vsprintf(buf, format, ap);
303    if (len >= buflen) {
304       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
305    }
306    memcpy(str, buf, len);
307    str[len] = 0;                /* len excludes the null */
308    free_memory(buf);
309    return len;
310 #endif
311 }
312 #endif /* USE_BSNPRINTF */
313
314 #ifndef HAVE_LOCALTIME_R
315
316 struct tm *localtime_r(const time_t *timep, struct tm *tm)
317 {
318     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
319     struct tm *ltm,
320
321     P(mutex);
322     ltm = localtime(timep);
323     if (ltm) {
324        memcpy(tm, ltm, sizeof(struct tm));
325     }
326     V(mutex);
327     return ltm ? tm : NULL;
328 }
329 #endif /* HAVE_LOCALTIME_R */
330
331 #ifndef HAVE_READDIR_R
332 #ifndef HAVE_WIN32
333 #include <dirent.h>
334
335 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
336 {
337     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
338     struct dirent *ndir;
339     int stat;
340
341     P(mutex);
342     errno = 0;
343     ndir = readdir(dirp);
344     stat = errno;
345     if (ndir) {
346        memcpy(entry, ndir, sizeof(struct dirent));
347        strcpy(entry->d_name, ndir->d_name);
348        *result = entry;
349     } else {
350        *result = NULL;
351     }
352     V(mutex);
353     return stat;
354
355 }
356 #endif
357 #endif /* HAVE_READDIR_R */
358
359
360 int b_strerror(int errnum, char *buf, size_t bufsiz)
361 {
362     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
363     int stat = 0;
364     const char *msg;
365
366     P(mutex);
367
368     msg = strerror(errnum);
369     if (!msg) {
370        msg = _("Bad errno");
371        stat = -1;
372     }
373     bstrncpy(buf, msg, bufsiz);
374     V(mutex);
375     return stat;
376 }
377
378 /*
379  * These are mutex routines that do error checking
380  *  for deadlock and such.  Normally not turned on.
381  */
382 #ifdef DEBUG_MUTEX
383 void _p(char *file, int line, pthread_mutex_t *m)
384 {
385    int errstat;
386    if ((errstat = pthread_mutex_trylock(m))) {
387       e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n"));
388       /* We didn't get the lock, so do it definitely now */
389       if ((errstat=pthread_mutex_lock(m))) {
390          berrno be;
391          e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
392                be.bstrerror(errstat));
393       } else {
394          e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n"));
395       }
396
397    }
398 }
399
400 void _v(char *file, int line, pthread_mutex_t *m)
401 {
402    int errstat;
403
404    /* Note, this trylock *should* fail if the mutex is locked */
405    if ((errstat=pthread_mutex_trylock(m)) == 0) {
406       berrno be;
407       e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"),
408            be.bstrerror(errstat));
409     }
410     if ((errstat=pthread_mutex_unlock(m))) {
411        berrno be;
412        e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
413               be.bstrerror(errstat));
414     }
415 }
416
417 #else
418
419 void _p(pthread_mutex_t *m)
420 {
421    int errstat;
422    if ((errstat=pthread_mutex_lock(m))) {
423       berrno be;
424       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
425             be.bstrerror(errstat));
426    }
427 }
428
429 void _v(pthread_mutex_t *m)
430 {
431    int errstat;
432    if ((errstat=pthread_mutex_unlock(m))) {
433       berrno be;
434       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
435             be.bstrerror(errstat));
436    }
437 }
438
439 #endif /* DEBUG_MUTEX */
440
441 #ifdef DEBUG_MEMSET
442 /* These routines are not normally turned on */
443 #undef memset
444 void b_memset(const char *file, int line, void *mem, int val, size_t num)
445 {
446    /* Testing for 2000 byte zero at beginning of Volume block */
447    if (num > 1900 && num < 3000) {
448       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
449    }
450    memset(mem, val, num);
451 }
452 #endif
453
454 #if !defined(HAVE_WIN32)
455 static int del_pid_file_ok = FALSE;
456 #endif
457
458 /*
459  * Create a standard "Unix" pid file.
460  */
461 void create_pid_file(char *dir, const char *progname, int port)
462 {
463 #if !defined(HAVE_WIN32)
464    int pidfd, len;
465    int oldpid;
466    char  pidbuf[20];
467    POOLMEM *fname = get_pool_memory(PM_FNAME);
468    struct stat statp;
469
470    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
471    if (stat(fname, &statp) == 0) {
472       /* File exists, see what we have */
473       *pidbuf = 0;
474       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
475            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
476            sscanf(pidbuf, "%d", &oldpid) != 1) {
477          berrno be;
478          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, 
479                be.bstrerror());
480       }
481       /* Some OSes (IRIX) don't bother to clean out the old pid files after a crash, and
482        * since they use a deterministic algorithm for assigning PIDs, we can have
483        * pid conflicts with the old PID file after a reboot.
484        * The intent the following code is to check if the oldpid read from the pid
485        * file is the same as the currently executing process's pid,
486        * and if oldpid == getpid(), skip the attempt to
487        * kill(oldpid,0), since the attempt is guaranteed to succeed,
488        * but the success won't actually mean that there is an
489        * another Bacula process already running.
490        * For more details see bug #797.
491        */
492        if ((oldpid != (int)getpid()) && (kill(oldpid, 0) != -1 || errno != ESRCH)) {
493          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
494                progname, oldpid, fname);
495       }
496       /* He is not alive, so take over file ownership */
497       unlink(fname);                  /* remove stale pid file */
498    }
499    /* Create new pid file */
500    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
501       len = sprintf(pidbuf, "%d\n", (int)getpid());
502       write(pidfd, pidbuf, len);
503       close(pidfd);
504       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
505    } else {
506       berrno be;
507       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, 
508             be.bstrerror());
509    }
510    free_pool_memory(fname);
511 #endif
512 }
513
514
515 /*
516  * Delete the pid file if we created it
517  */
518 int delete_pid_file(char *dir, const char *progname, int port)
519 {
520 #if !defined(HAVE_WIN32)
521    POOLMEM *fname = get_pool_memory(PM_FNAME);
522
523    if (!del_pid_file_ok) {
524       free_pool_memory(fname);
525       return 0;
526    }
527    del_pid_file_ok = FALSE;
528    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
529    unlink(fname);
530    free_pool_memory(fname);
531 #endif
532    return 1;
533 }
534
535 struct s_state_hdr {
536    char id[14];
537    int32_t version;
538    uint64_t last_jobs_addr;
539    uint64_t reserved[20];
540 };
541
542 static struct s_state_hdr state_hdr = {
543    "Bacula State\n",
544    3,
545    0
546 };
547
548 /*
549  * Open and read the state file for the daemon
550  */
551 void read_state_file(char *dir, const char *progname, int port)
552 {
553    int sfd;
554    ssize_t stat;
555    bool ok = false;
556    POOLMEM *fname = get_pool_memory(PM_FNAME);
557    struct s_state_hdr hdr;
558    int hdr_size = sizeof(hdr);
559
560    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
561    /* If file exists, see what we have */
562 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
563    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
564       berrno be;
565       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
566                     sfd, sizeof(hdr), be.bstrerror());
567       goto bail_out;
568    }
569    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
570       berrno be;
571       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
572                     sfd, (int)stat, hdr_size, be.bstrerror());
573       goto bail_out;
574    }
575    if (hdr.version != state_hdr.version) {
576       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
577          state_hdr.version, hdr.version);
578       goto bail_out;
579    }
580    hdr.id[13] = 0;
581    if (strcmp(hdr.id, state_hdr.id) != 0) {
582       Dmsg0(000, "State file header id invalid.\n");
583       goto bail_out;
584    }
585 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
586    if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) {
587       goto bail_out;
588    }
589    ok = true;
590 bail_out:
591    if (sfd >= 0) {
592       close(sfd);
593    }
594    if (!ok) {
595       unlink(fname);
596     }
597    free_pool_memory(fname);
598 }
599
600 /*
601  * Write the state file
602  */
603 void write_state_file(char *dir, const char *progname, int port)
604 {
605    int sfd;
606    bool ok = false;
607    POOLMEM *fname = get_pool_memory(PM_FNAME);
608
609    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
610    /* Create new state file */
611    unlink(fname);
612    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
613       berrno be;
614       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.bstrerror());
615       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.bstrerror());
616       goto bail_out;
617    }
618    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
619       berrno be;
620       Dmsg1(000, "Write hdr error: ERR=%s\n", be.bstrerror());
621       goto bail_out;
622    }
623 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
624    state_hdr.last_jobs_addr = sizeof(state_hdr);
625    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
626 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
627    if (lseek(sfd, 0, SEEK_SET) < 0) {
628       berrno be;
629       Dmsg1(000, "lseek error: ERR=%s\n", be.bstrerror());
630       goto bail_out;
631    }
632    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
633       berrno be;
634       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.bstrerror());
635       goto bail_out;
636    }
637    ok = true;
638 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
639 bail_out:
640    if (sfd >= 0) {
641       close(sfd);
642    }
643    if (!ok) {
644       unlink(fname);
645    }
646    free_pool_memory(fname);
647 }
648
649
650 /*
651  * Drop to privilege new userid and new gid if non-NULL
652  */
653 void drop(char *uname, char *gname)
654 {
655 #if   defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
656    struct passwd *passw = NULL;
657    struct group *group = NULL;
658    gid_t gid;
659    uid_t uid;
660    char username[1000];         
661
662    Dmsg2(900, "uname=%s gname=%s\n", uname?uname:"NONE", gname?gname:"NONE");
663    if (!uname && !gname) {
664       return;                            /* Nothing to do */
665    }
666
667    if (uname) {
668       if ((passw = getpwnam(uname)) == NULL) {
669          berrno be;
670          Emsg2(M_ERROR_TERM, 0, _("Could not find userid=%s: ERR=%s\n"), uname,
671             be.bstrerror());
672       }
673    } else {
674       if ((passw = getpwuid(getuid())) == NULL) {
675          berrno be;
676          Emsg1(M_ERROR_TERM, 0, _("Could not find password entry. ERR=%s\n"),
677             be.bstrerror());
678       } else {
679          uname = passw->pw_name;
680       }
681    }
682    /* Any OS uname pointer may get overwritten, so save name, uid, and gid */
683    bstrncpy(username, uname, sizeof(username));
684    uid = passw->pw_uid;
685    gid = passw->pw_gid;
686    if (gname) {
687       if ((group = getgrnam(gname)) == NULL) {
688          berrno be;
689          Emsg2(M_ERROR_TERM, 0, _("Could not find group=%s: ERR=%s\n"), gname,
690             be.bstrerror());
691       }
692       gid = group->gr_gid;
693    }
694    if (initgroups(username, gid)) {
695       berrno be;
696       if (gname) {
697          Emsg3(M_ERROR_TERM, 0, _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"),         
698             gname, username, be.bstrerror());
699       } else {
700          Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),         
701             username, be.bstrerror());
702       }
703    }
704    if (gname) {
705       if (setgid(gid)) {
706          berrno be;
707          Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
708             be.bstrerror());
709       }
710    }
711    if (setuid(uid)) {
712       berrno be;
713       Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
714    }
715 #endif
716 }
717
718
719 /* BSDI does not have this.  This is a *poor* simulation */
720 #ifndef HAVE_STRTOLL
721 long long int
722 strtoll(const char *ptr, char **endptr, int base)
723 {
724    return (long long int)strtod(ptr, endptr);
725 }
726 #endif
727
728 /*
729  * Bacula's implementation of fgets(). The difference is that it handles
730  *   being interrupted by a signal (e.g. a SIGCHLD).
731  */
732 #undef fgetc
733 char *bfgets(char *s, int size, FILE *fd)
734 {
735    char *p = s;
736    int ch;
737    *p = 0;
738    for (int i=0; i < size-1; i++) {
739       do {
740          errno = 0;
741          ch = fgetc(fd);
742       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
743       if (ch == EOF) {
744          if (i == 0) {
745             return NULL;
746          } else {
747             return s;
748          }
749       }
750       *p++ = ch;
751       *p = 0;
752       if (ch == '\r') { /* Support for Mac/Windows file format */
753          ch = fgetc(fd);
754          if (ch != '\n') { /* Mac (\r only) */
755             (void)ungetc(ch, fd); /* Push next character back to fd */
756          }
757          p[-1] = '\n';
758          break;
759       }
760       if (ch == '\n') {
761          break;
762       }
763    }
764    return s;
765 }
766
767 /*
768  * Make a "unique" filename.  It is important that if
769  *   called again with the same "what" that the result
770  *   will be identical. This allows us to use the file
771  *   without saving its name, and re-generate the name
772  *   so that it can be deleted.
773  */
774 void make_unique_filename(POOLMEM **name, int Id, char *what)
775 {
776    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
777 }
778
779 char *escape_filename(const char *file_path)
780 {
781    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
782       return NULL;
783    }
784
785    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
786    char *cur_char = escaped_path;
787
788    while (*file_path) {
789       if (*file_path == '\\' || *file_path == '"') {
790          *cur_char++ = '\\';
791       }
792
793       *cur_char++ = *file_path++;
794    }
795
796    *cur_char = '\0';
797
798    return escaped_path;
799 }