]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
ebl move Errors count up to be more easy to parse with Bweb
[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 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(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          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno));
478       }
479       /* Some OSes (IRIX) don't bother to clean out the old pid files after a crash, and
480        * since they use a deterministic algorithm for assigning PIDs, we can have
481        * pid conflicts with the old PID file after a reboot.
482        * The intent the following code is to check if the oldpid read from the pid
483        * file is the same as the currently executing process's pid,
484        * and if oldpid == getpid(), skip the attempt to
485        * kill(oldpid,0), since the attempt is guaranteed to succeed,
486        * but the success won't actually mean that there is an
487        * another Bacula process already running.
488        * For more details see bug #797.
489        */
490        if ((oldpid != (int)getpid()) && (kill(oldpid, 0) != -1 || errno != ESRCH)) {
491          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
492                progname, oldpid, fname);
493       }
494       /* He is not alive, so take over file ownership */
495       unlink(fname);                  /* remove stale pid file */
496    }
497    /* Create new pid file */
498    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
499       len = sprintf(pidbuf, "%d\n", (int)getpid());
500       write(pidfd, pidbuf, len);
501       close(pidfd);
502       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
503    } else {
504       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno));
505    }
506    free_pool_memory(fname);
507 #endif
508 }
509
510
511 /*
512  * Delete the pid file if we created it
513  */
514 int delete_pid_file(char *dir, const char *progname, int port)
515 {
516 #if !defined(HAVE_WIN32)
517    POOLMEM *fname = get_pool_memory(PM_FNAME);
518
519    if (!del_pid_file_ok) {
520       free_pool_memory(fname);
521       return 0;
522    }
523    del_pid_file_ok = FALSE;
524    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
525    unlink(fname);
526    free_pool_memory(fname);
527 #endif
528    return 1;
529 }
530
531 struct s_state_hdr {
532    char id[14];
533    int32_t version;
534    uint64_t last_jobs_addr;
535    uint64_t reserved[20];
536 };
537
538 static struct s_state_hdr state_hdr = {
539    "Bacula State\n",
540    3,
541    0
542 };
543
544 /*
545  * Open and read the state file for the daemon
546  */
547 void read_state_file(char *dir, const char *progname, int port)
548 {
549    int sfd;
550    ssize_t stat;
551    bool ok = false;
552    POOLMEM *fname = get_pool_memory(PM_FNAME);
553    struct s_state_hdr hdr;
554    int hdr_size = sizeof(hdr);
555
556    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
557    /* If file exists, see what we have */
558 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
559    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
560       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
561                     sfd, sizeof(hdr), strerror(errno));
562       goto bail_out;
563    }
564    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
565       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
566                     sfd, (int)stat, hdr_size, strerror(errno));
567       goto bail_out;
568    }
569    if (hdr.version != state_hdr.version) {
570       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
571          state_hdr.version, hdr.version);
572       goto bail_out;
573    }
574    hdr.id[13] = 0;
575    if (strcmp(hdr.id, state_hdr.id) != 0) {
576       Dmsg0(000, "State file header id invalid.\n");
577       goto bail_out;
578    }
579 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
580    if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) {
581       goto bail_out;
582    }
583    ok = true;
584 bail_out:
585    if (sfd >= 0) {
586       close(sfd);
587    }
588    if (!ok) {
589       unlink(fname);
590     }
591    free_pool_memory(fname);
592 }
593
594 /*
595  * Write the state file
596  */
597 void write_state_file(char *dir, const char *progname, int port)
598 {
599    int sfd;
600    bool ok = false;
601    POOLMEM *fname = get_pool_memory(PM_FNAME);
602
603    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
604    /* Create new state file */
605    unlink(fname);
606    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
607       berrno be;
608       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.bstrerror());
609       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.bstrerror());
610       goto bail_out;
611    }
612    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
613       berrno be;
614       Dmsg1(000, "Write hdr error: ERR=%s\n", be.bstrerror());
615       goto bail_out;
616    }
617 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
618    state_hdr.last_jobs_addr = sizeof(state_hdr);
619    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
620 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
621    if (lseek(sfd, 0, SEEK_SET) < 0) {
622       berrno be;
623       Dmsg1(000, "lseek error: ERR=%s\n", be.bstrerror());
624       goto bail_out;
625    }
626    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
627       berrno be;
628       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.bstrerror());
629       goto bail_out;
630    }
631    ok = true;
632 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
633 bail_out:
634    if (sfd >= 0) {
635       close(sfd);
636    }
637    if (!ok) {
638       unlink(fname);
639    }
640    free_pool_memory(fname);
641 }
642
643
644 /*
645  * Drop to privilege new userid and new gid if non-NULL
646  */
647 void drop(char *uname, char *gname)
648 {
649 #if   defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
650    struct passwd *passw = NULL;
651    struct group *group = NULL;
652    gid_t gid;
653    uid_t uid;
654    char username[1000];         
655
656    Dmsg2(900, "uname=%s gname=%s\n", uname?uname:"NONE", gname?gname:"NONE");
657    if (!uname && !gname) {
658       return;                            /* Nothing to do */
659    }
660
661    if (uname) {
662       if ((passw = getpwnam(uname)) == NULL) {
663          berrno be;
664          Emsg2(M_ERROR_TERM, 0, _("Could not find userid=%s: ERR=%s\n"), uname,
665             be.bstrerror());
666       }
667    } else {
668       if ((passw = getpwuid(getuid())) == NULL) {
669          berrno be;
670          Emsg1(M_ERROR_TERM, 0, _("Could not find password entry. ERR=%s\n"),
671             be.bstrerror());
672       } else {
673          uname = passw->pw_name;
674       }
675    }
676    /* Any OS uname pointer may get overwritten, so save name, uid, and gid */
677    bstrncpy(username, uname, sizeof(username));
678    uid = passw->pw_uid;
679    gid = passw->pw_gid;
680    if (gname) {
681       if ((group = getgrnam(gname)) == NULL) {
682          berrno be;
683          Emsg2(M_ERROR_TERM, 0, _("Could not find group=%s: ERR=%s\n"), gname,
684             be.bstrerror());
685       }
686       gid = group->gr_gid;
687    }
688    if (initgroups(username, gid)) {
689       berrno be;
690       if (gname) {
691          Emsg3(M_ERROR_TERM, 0, _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"),         
692             gname, username, be.bstrerror());
693       } else {
694          Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),         
695             username, be.bstrerror());
696       }
697    }
698    if (gname) {
699       if (setgid(gid)) {
700          berrno be;
701          Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
702             be.bstrerror());
703       }
704    }
705    if (setuid(uid)) {
706       berrno be;
707       Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
708    }
709 #endif
710 }
711
712
713 /* BSDI does not have this.  This is a *poor* simulation */
714 #ifndef HAVE_STRTOLL
715 long long int
716 strtoll(const char *ptr, char **endptr, int base)
717 {
718    return (long long int)strtod(ptr, endptr);
719 }
720 #endif
721
722 /*
723  * Bacula's implementation of fgets(). The difference is that it handles
724  *   being interrupted by a signal (e.g. a SIGCHLD).
725  */
726 #undef fgetc
727 char *bfgets(char *s, int size, FILE *fd)
728 {
729    char *p = s;
730    int ch;
731    *p = 0;
732    for (int i=0; i < size-1; i++) {
733       do {
734          errno = 0;
735          ch = fgetc(fd);
736       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
737       if (ch == EOF) {
738          if (i == 0) {
739             return NULL;
740          } else {
741             return s;
742          }
743       }
744       *p++ = ch;
745       *p = 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          p[-1] = '\n';
752          break;
753       }
754       if (ch == '\n') {
755          break;
756       }
757    }
758    return s;
759 }
760
761 /*
762  * Make a "unique" filename.  It is important that if
763  *   called again with the same "what" that the result
764  *   will be identical. This allows us to use the file
765  *   without saving its name, and re-generate the name
766  *   so that it can be deleted.
767  */
768 void make_unique_filename(POOLMEM **name, int Id, char *what)
769 {
770    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
771 }
772
773 char *escape_filename(const char *file_path)
774 {
775    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
776       return NULL;
777    }
778
779    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
780    char *cur_char = escaped_path;
781
782    while (*file_path) {
783       if (*file_path == '\\' || *file_path == '"') {
784          *cur_char++ = '\\';
785       }
786
787       *cur_char++ = *file_path++;
788    }
789
790    *cur_char = '\0';
791
792    return escaped_path;
793 }