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