]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
kes Extend new GUI API.
[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.strerror(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.strerror());
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.strerror());
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    buf = realloc(buf, size);
238    if (buf == NULL) {
239       berrno be;
240       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
241    }
242    return buf;
243 }
244
245
246 void *bcalloc (size_t size1, size_t size2)
247 {
248   void *buf;
249
250    buf = calloc(size1, size2);
251    if (buf == NULL) {
252       berrno be;
253       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
254    }
255    return buf;
256 }
257
258 /* Code now in src/lib/bsnprintf.c */
259 #ifndef USE_BSNPRINTF
260
261 #define BIG_BUF 5000
262 /*
263  * Implement snprintf
264  */
265 int bsnprintf(char *str, int32_t size, const char *fmt,  ...)
266 {
267    va_list   arg_ptr;
268    int len;
269
270    va_start(arg_ptr, fmt);
271    len = bvsnprintf(str, size, fmt, arg_ptr);
272    va_end(arg_ptr);
273    return len;
274 }
275
276 /*
277  * Implement vsnprintf()
278  */
279 int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
280 {
281 #ifdef HAVE_VSNPRINTF
282    int len;
283    len = vsnprintf(str, size, format, ap);
284    str[size-1] = 0;
285    return len;
286
287 #else
288
289    int len, buflen;
290    char *buf;
291    buflen = size > BIG_BUF ? size : BIG_BUF;
292    buf = get_memory(buflen);
293    len = vsprintf(buf, format, ap);
294    if (len >= buflen) {
295       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
296    }
297    memcpy(str, buf, len);
298    str[len] = 0;                /* len excludes the null */
299    free_memory(buf);
300    return len;
301 #endif
302 }
303 #endif /* USE_BSNPRINTF */
304
305 #ifndef HAVE_LOCALTIME_R
306
307 struct tm *localtime_r(const time_t *timep, struct tm *tm)
308 {
309     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
310     struct tm *ltm,
311
312     P(mutex);
313     ltm = localtime(timep);
314     if (ltm) {
315        memcpy(tm, ltm, sizeof(struct tm));
316     }
317     V(mutex);
318     return ltm ? tm : NULL;
319 }
320 #endif /* HAVE_LOCALTIME_R */
321
322 #ifndef HAVE_READDIR_R
323 #ifndef HAVE_WIN32
324 #include <dirent.h>
325
326 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
327 {
328     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
329     struct dirent *ndir;
330     int stat;
331
332     P(mutex);
333     errno = 0;
334     ndir = readdir(dirp);
335     stat = errno;
336     if (ndir) {
337        memcpy(entry, ndir, sizeof(struct dirent));
338        strcpy(entry->d_name, ndir->d_name);
339        *result = entry;
340     } else {
341        *result = NULL;
342     }
343     V(mutex);
344     return stat;
345
346 }
347 #endif
348 #endif /* HAVE_READDIR_R */
349
350
351 int bstrerror(int errnum, char *buf, size_t bufsiz)
352 {
353     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
354     int stat = 0;
355     const char *msg;
356
357     P(mutex);
358
359     msg = strerror(errnum);
360     if (!msg) {
361        msg = _("Bad errno");
362        stat = -1;
363     }
364     bstrncpy(buf, msg, bufsiz);
365     V(mutex);
366     return stat;
367 }
368
369 /*
370  * These are mutex routines that do error checking
371  *  for deadlock and such.  Normally not turned on.
372  */
373 #ifdef DEBUG_MUTEX
374 void _p(char *file, int line, pthread_mutex_t *m)
375 {
376    int errstat;
377    if ((errstat = pthread_mutex_trylock(m))) {
378       e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n"));
379       /* We didn't get the lock, so do it definitely now */
380       if ((errstat=pthread_mutex_lock(m))) {
381          berrno be;
382          e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
383                be.strerror(errstat));
384       } else {
385          e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n"));
386       }
387
388    }
389 }
390
391 void _v(char *file, int line, pthread_mutex_t *m)
392 {
393    int errstat;
394
395    /* Note, this trylock *should* fail if the mutex is locked */
396    if ((errstat=pthread_mutex_trylock(m)) == 0) {
397       berrno be;
398       e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"),
399            be.strerror(errstat));
400     }
401     if ((errstat=pthread_mutex_unlock(m))) {
402        berrno be;
403        e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
404               be.strerror(errstat));
405     }
406 }
407
408 #else
409
410 void _p(pthread_mutex_t *m)
411 {
412    int errstat;
413    if ((errstat=pthread_mutex_lock(m))) {
414       berrno be;
415       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
416             be.strerror(errstat));
417    }
418 }
419
420 void _v(pthread_mutex_t *m)
421 {
422    int errstat;
423    if ((errstat=pthread_mutex_unlock(m))) {
424       berrno be;
425       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
426             be.strerror(errstat));
427    }
428 }
429
430 #endif /* DEBUG_MUTEX */
431
432 #ifdef DEBUG_MEMSET
433 /* These routines are not normally turned on */
434 #undef memset
435 void b_memset(const char *file, int line, void *mem, int val, size_t num)
436 {
437    /* Testing for 2000 byte zero at beginning of Volume block */
438    if (num > 1900 && num < 3000) {
439       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
440    }
441    memset(mem, val, num);
442 }
443 #endif
444
445 #if !defined(HAVE_WIN32)
446 static int del_pid_file_ok = FALSE;
447 #endif
448
449 /*
450  * Create a standard "Unix" pid file.
451  */
452 void create_pid_file(char *dir, const char *progname, int port)
453 {
454 #if !defined(HAVE_WIN32)
455    int pidfd, len;
456    int oldpid;
457    char  pidbuf[20];
458    POOLMEM *fname = get_pool_memory(PM_FNAME);
459    struct stat statp;
460
461    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
462    if (stat(fname, &statp) == 0) {
463       /* File exists, see what we have */
464       *pidbuf = 0;
465       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
466            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
467            sscanf(pidbuf, "%d", &oldpid) != 1) {
468          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno));
469       }
470       /* See if other Bacula is still alive */
471       if (kill(oldpid, 0) != -1 || errno != ESRCH) {
472          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
473                progname, oldpid, fname);
474       }
475       /* He is not alive, so take over file ownership */
476       unlink(fname);                  /* remove stale pid file */
477    }
478    /* Create new pid file */
479    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
480       len = sprintf(pidbuf, "%d\n", (int)getpid());
481       write(pidfd, pidbuf, len);
482       close(pidfd);
483       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
484    } else {
485       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno));
486    }
487    free_pool_memory(fname);
488 #endif
489 }
490
491
492 /*
493  * Delete the pid file if we created it
494  */
495 int delete_pid_file(char *dir, const char *progname, int port)
496 {
497 #if !defined(HAVE_WIN32)
498    POOLMEM *fname = get_pool_memory(PM_FNAME);
499
500    if (!del_pid_file_ok) {
501       free_pool_memory(fname);
502       return 0;
503    }
504    del_pid_file_ok = FALSE;
505    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
506    unlink(fname);
507    free_pool_memory(fname);
508 #endif
509    return 1;
510 }
511
512 struct s_state_hdr {
513    char id[14];
514    int32_t version;
515    uint64_t last_jobs_addr;
516    uint64_t reserved[20];
517 };
518
519 static struct s_state_hdr state_hdr = {
520    "Bacula State\n",
521    3,
522    0
523 };
524
525 /*
526  * Open and read the state file for the daemon
527  */
528 void read_state_file(char *dir, const char *progname, int port)
529 {
530    int sfd;
531    ssize_t stat;
532    bool ok = false;
533    POOLMEM *fname = get_pool_memory(PM_FNAME);
534    struct s_state_hdr hdr;
535    int hdr_size = sizeof(hdr);
536
537    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
538    /* If file exists, see what we have */
539 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
540    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
541       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
542                     sfd, sizeof(hdr), strerror(errno));
543       goto bail_out;
544    }
545    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
546       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
547                     sfd, (int)stat, hdr_size, strerror(errno));
548       goto bail_out;
549    }
550    if (hdr.version != state_hdr.version) {
551       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
552          state_hdr.version, hdr.version);
553       goto bail_out;
554    }
555    hdr.id[13] = 0;
556    if (strcmp(hdr.id, state_hdr.id) != 0) {
557       Dmsg0(000, "State file header id invalid.\n");
558       goto bail_out;
559    }
560 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
561    if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) {
562       goto bail_out;
563    }
564    ok = true;
565 bail_out:
566    if (sfd >= 0) {
567       close(sfd);
568    }
569    if (!ok) {
570       unlink(fname);
571     }
572    free_pool_memory(fname);
573 }
574
575 /*
576  * Write the state file
577  */
578 void write_state_file(char *dir, const char *progname, int port)
579 {
580    int sfd;
581    bool ok = false;
582    POOLMEM *fname = get_pool_memory(PM_FNAME);
583
584    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
585    /* Create new state file */
586    unlink(fname);
587    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
588       berrno be;
589       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.strerror());
590       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.strerror());
591       goto bail_out;
592    }
593    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
594       berrno be;
595       Dmsg1(000, "Write hdr error: ERR=%s\n", be.strerror());
596       goto bail_out;
597    }
598 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
599    state_hdr.last_jobs_addr = sizeof(state_hdr);
600    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
601 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
602    if (lseek(sfd, 0, SEEK_SET) < 0) {
603       berrno be;
604       Dmsg1(000, "lseek error: ERR=%s\n", be.strerror());
605       goto bail_out;
606    }
607    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
608       berrno be;
609       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.strerror());
610       goto bail_out;
611    }
612    ok = true;
613 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
614 bail_out:
615    if (sfd >= 0) {
616       close(sfd);
617    }
618    if (!ok) {
619       unlink(fname);
620    }
621    free_pool_memory(fname);
622 }
623
624
625 /*
626  * Drop to privilege new userid and new gid if non-NULL
627  */
628 void drop(char *uname, char *gname)
629 {
630 #if   defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
631    struct passwd *passw = NULL;
632    struct group *group = NULL;
633    gid_t gid;
634    uid_t uid;
635    char username[1000];         
636
637    Dmsg2(900, "uname=%s gname=%s\n", uname?uname:"NONE", gname?gname:"NONE");
638    if (!uname && !gname) {
639       return;                            /* Nothing to do */
640    }
641
642    if (uname) {
643       if ((passw = getpwnam(uname)) == NULL) {
644          berrno be;
645          Emsg2(M_ERROR_TERM, 0, _("Could not find userid=%s: ERR=%s\n"), uname,
646             be.strerror());
647       }
648    } else {
649       if ((passw = getpwuid(getuid())) == NULL) {
650          berrno be;
651          Emsg1(M_ERROR_TERM, 0, _("Could not find password entry. ERR=%s\n"),
652             be.strerror());
653       } else {
654          uname = passw->pw_name;
655       }
656    }
657    /* Any OS uname pointer may get overwritten, so save name, uid, and gid */
658    bstrncpy(username, uname, sizeof(username));
659    uid = passw->pw_uid;
660    gid = passw->pw_gid;
661    if (gname) {
662       if ((group = getgrnam(gname)) == NULL) {
663          berrno be;
664          Emsg2(M_ERROR_TERM, 0, _("Could not find group=%s: ERR=%s\n"), gname,
665             be.strerror());
666       }
667       gid = group->gr_gid;
668    }
669    if (initgroups(username, gid)) {
670       berrno be;
671       if (gname) {
672          Emsg3(M_ERROR_TERM, 0, _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"),         
673             gname, username, be.strerror());
674       } else {
675          Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),         
676             username, be.strerror());
677       }
678    }
679    if (gname) {
680       if (setgid(gid)) {
681          berrno be;
682          Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
683             be.strerror());
684       }
685    }
686    if (setuid(uid)) {
687       berrno be;
688       Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
689    }
690 #endif
691 }
692
693
694 /* BSDI does not have this.  This is a *poor* simulation */
695 #ifndef HAVE_STRTOLL
696 long long int
697 strtoll(const char *ptr, char **endptr, int base)
698 {
699    return (long long int)strtod(ptr, endptr);
700 }
701 #endif
702
703 /*
704  * Bacula's implementation of fgets(). The difference is that it handles
705  *   being interrupted by a signal (e.g. a SIGCHLD).
706  */
707 #undef fgetc
708 char *bfgets(char *s, int size, FILE *fd)
709 {
710    char *p = s;
711    int ch;
712    *p = 0;
713    for (int i=0; i < size-1; i++) {
714       do {
715          errno = 0;
716          ch = fgetc(fd);
717       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
718       if (ch == EOF) {
719          if (i == 0) {
720             return NULL;
721          } else {
722             return s;
723          }
724       }
725       *p++ = ch;
726       *p = 0;
727       if (ch == '\r') { /* Support for Mac/Windows file format */
728          ch = fgetc(fd);
729          if (ch != '\n') { /* Mac (\r only) */
730             (void)ungetc(ch, fd); /* Push next character back to fd */
731          }
732          p[-1] = '\n';
733          break;
734       }
735       if (ch == '\n') {
736          break;
737       }
738    }
739    return s;
740 }
741
742 /*
743  * Make a "unique" filename.  It is important that if
744  *   called again with the same "what" that the result
745  *   will be identical. This allows us to use the file
746  *   without saving its name, and re-generate the name
747  *   so that it can be deleted.
748  */
749 void make_unique_filename(POOLMEM **name, int Id, char *what)
750 {
751    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
752 }
753
754 char *escape_filename(const char *file_path)
755 {
756    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
757       return NULL;
758    }
759
760    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
761    char *cur_char = escaped_path;
762
763    while (*file_path) {
764       if (*file_path == '\\' || *file_path == '"') {
765          *cur_char++ = '\\';
766       }
767
768       *cur_char++ = *file_path++;
769    }
770
771    *cur_char = '\0';
772
773    return escaped_path;
774 }