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