]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
This commit was manufactured by cvs2svn to create tag
[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-2005 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  * Get character length of UTF-8 string
118  *
119  * Valid UTF-8 codes
120  * U-00000000 - U-0000007F: 0xxxxxxx 
121  * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 
122  * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
123  * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
124  * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
125  * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
126  */
127 int cstrlen(const char *str)
128 {
129    uint8_t *p = (uint8_t *)str;
130    int len = 0;
131    while (*p) {
132       if ((*p & 0xC0) != 0xC0) {
133          p++;
134          len++;
135          continue;
136       }
137       if ((*p & 0xD0) == 0xC0) {
138          p += 2;
139          len++;
140          continue;
141       }
142       if ((*p & 0xF0) == 0xD0) {
143          p += 3;
144          len++;
145          continue;
146       }
147       if ((*p & 0xF8) == 0xF0) {
148          p += 4;
149          len++;
150          continue;
151       }
152       if ((*p & 0xFC) == 0xF8) {
153          p += 5;
154          len++;
155          continue;
156       }
157       if ((*p & 0xFE) == 0xFC) {
158          p += 6;
159          len++;
160          continue;
161       }
162       p++;                      /* Shouln't get here but must advance */
163    }
164    return len;
165 }
166
167
168
169 #ifndef DEBUG
170 void *bmalloc(size_t size)
171 {
172   void *buf;
173
174   buf = malloc(size);
175   if (buf == NULL) {
176      Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno));
177   }
178   return buf;
179 }
180 #endif
181
182 void *b_malloc(const char *file, int line, size_t size)
183 {
184   void *buf;
185
186 #ifdef SMARTALLOC
187   buf = sm_malloc(file, line, size);
188 #else
189   buf = malloc(size);
190 #endif
191   if (buf == NULL) {
192      e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno));
193   }
194   return buf;
195 }
196
197
198 void *brealloc (void *buf, size_t size)
199 {
200    buf = realloc(buf, size);
201    if (buf == NULL) {
202       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno));
203    }
204    return buf;
205 }
206
207
208 void *bcalloc (size_t size1, size_t size2)
209 {
210   void *buf;
211
212    buf = calloc(size1, size2);
213    if (buf == NULL) {
214       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno));
215    }
216    return buf;
217 }
218
219
220 #define BIG_BUF 5000
221 /*
222  * Implement snprintf
223  */
224 int bsnprintf(char *str, int32_t size, const char *fmt,  ...)
225 {
226    va_list   arg_ptr;
227    int len;
228
229    va_start(arg_ptr, fmt);
230    len = bvsnprintf(str, size, fmt, arg_ptr);
231    va_end(arg_ptr);
232    return len;
233 }
234
235 /*
236  * Implement vsnprintf()
237  */
238 int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
239 {
240 #ifdef HAVE_VSNPRINTF
241    int len;
242    len = vsnprintf(str, size, format, ap);
243    str[size-1] = 0;
244    return len;
245
246 #else
247
248    int len, buflen;
249    char *buf;
250    buflen = size > BIG_BUF ? size : BIG_BUF;
251    buf = get_memory(buflen);
252    len = vsprintf(buf, format, ap);
253    if (len >= buflen) {
254       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
255    }
256    memcpy(str, buf, len);
257    str[len] = 0;                /* len excludes the null */
258    free_memory(buf);
259    return len;
260 #endif
261 }
262
263 #ifndef HAVE_LOCALTIME_R
264
265 struct tm *localtime_r(const time_t *timep, struct tm *tm)
266 {
267     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
268     struct tm *ltm,
269
270     P(mutex);
271     ltm = localtime(timep);
272     if (ltm) {
273        memcpy(tm, ltm, sizeof(struct tm));
274     }
275     V(mutex);
276     return ltm ? tm : NULL;
277 }
278 #endif /* HAVE_LOCALTIME_R */
279
280 #ifndef HAVE_READDIR_R
281 #ifndef HAVE_WIN32
282 #include <dirent.h>
283
284 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
285 {
286     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
287     struct dirent *ndir;
288     int stat;
289
290     P(mutex);
291     errno = 0;
292     ndir = readdir(dirp);
293     stat = errno;
294     if (ndir) {
295        memcpy(entry, ndir, sizeof(struct dirent));
296        strcpy(entry->d_name, ndir->d_name);
297        *result = entry;
298     } else {
299        *result = NULL;
300     }
301     V(mutex);
302     return stat;
303
304 }
305 #endif
306 #endif /* HAVE_READDIR_R */
307
308
309 int bstrerror(int errnum, char *buf, size_t bufsiz)
310 {
311     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
312     int stat = 0;
313     const char *msg;
314
315     P(mutex);
316
317     msg = strerror(errnum);
318     if (!msg) {
319        msg = _("Bad errno");
320        stat = -1;
321     }
322     bstrncpy(buf, msg, bufsiz);
323     V(mutex);
324     return stat;
325 }
326
327 /*
328  * These are mutex routines that do error checking
329  *  for deadlock and such.  Normally not turned on.
330  */
331 #ifdef DEBUG_MUTEX
332 void _p(char *file, int line, pthread_mutex_t *m)
333 {
334    int errstat;
335    if ((errstat = pthread_mutex_trylock(m))) {
336       e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n"));
337       /* We didn't get the lock, so do it definitely now */
338       if ((errstat=pthread_mutex_lock(m))) {
339          berrno be;
340          e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
341                be.strerror(errstat));
342       } else {
343          e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n"));
344       }
345
346    }
347 }
348
349 void _v(char *file, int line, pthread_mutex_t *m)
350 {
351    int errstat;
352
353    if ((errstat=pthread_mutex_trylock(m)) == 0) {
354       berrno be;
355       e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"),
356            be.strerror(errstat));
357     }
358     if ((errstat=pthread_mutex_unlock(m))) {
359        berrno be;
360        e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
361               be.strerror(errstat));
362     }
363 }
364
365 #else
366
367 void _p(pthread_mutex_t *m)
368 {
369    int errstat;
370    if ((errstat=pthread_mutex_lock(m))) {
371       berrno be;
372       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
373             be.strerror(errstat));
374    }
375 }
376
377 void _v(pthread_mutex_t *m)
378 {
379    int errstat;
380    if ((errstat=pthread_mutex_unlock(m))) {
381       berrno be;
382       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
383             be.strerror(errstat));
384    }
385 }
386
387 #endif /* DEBUG_MUTEX */
388
389 #ifdef DEBUG_MEMSET
390 /* These routines are not normally turned on */
391 #undef memset
392 void b_memset(const char *file, int line, void *mem, int val, size_t num)
393 {
394    /* Testing for 2000 byte zero at beginning of Volume block */
395    if (num > 1900 && num < 3000) {
396       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
397    }
398    memset(mem, val, num);
399 }
400 #endif
401
402 #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
403 static int del_pid_file_ok = FALSE;
404 #endif
405
406 /*
407  * Create a standard "Unix" pid file.
408  */
409 void create_pid_file(char *dir, const char *progname, int port)
410 {
411 #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
412    int pidfd, len;
413    int oldpid;
414    char  pidbuf[20];
415    POOLMEM *fname = get_pool_memory(PM_FNAME);
416    struct stat statp;
417
418    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
419    if (stat(fname, &statp) == 0) {
420       /* File exists, see what we have */
421       *pidbuf = 0;
422       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
423            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
424            sscanf(pidbuf, "%d", &oldpid) != 1) {
425          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno));
426       }
427       /* See if other Bacula is still alive */
428       if (kill(oldpid, 0) != -1 || errno != ESRCH) {
429          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
430                progname, oldpid, fname);
431       }
432       /* He is not alive, so take over file ownership */
433       unlink(fname);                  /* remove stale pid file */
434    }
435    /* Create new pid file */
436    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
437       len = sprintf(pidbuf, "%d\n", (int)getpid());
438       write(pidfd, pidbuf, len);
439       close(pidfd);
440       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
441    } else {
442       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno));
443    }
444    free_pool_memory(fname);
445 #endif
446 }
447
448
449 /*
450  * Delete the pid file if we created it
451  */
452 int delete_pid_file(char *dir, const char *progname, int port)
453 {
454 #if !defined(HAVE_CYGWIN)  && !defined(HAVE_WIN32)
455    POOLMEM *fname = get_pool_memory(PM_FNAME);
456
457    if (!del_pid_file_ok) {
458       free_pool_memory(fname);
459       return 0;
460    }
461    del_pid_file_ok = FALSE;
462    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
463    unlink(fname);
464    free_pool_memory(fname);
465 #endif
466    return 1;
467 }
468
469 struct s_state_hdr {
470    char id[14];
471    int32_t version;
472    uint64_t last_jobs_addr;
473    uint64_t reserved[20];
474 };
475
476 static struct s_state_hdr state_hdr = {
477    "Bacula State\n",
478    3,
479    0
480 };
481
482 /*
483  * Open and read the state file for the daemon
484  */
485 void read_state_file(char *dir, const char *progname, int port)
486 {
487    int sfd;
488    ssize_t stat;
489    POOLMEM *fname = get_pool_memory(PM_FNAME);
490    struct s_state_hdr hdr;
491    int hdr_size = sizeof(hdr);
492
493    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
494    /* If file exists, see what we have */
495 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
496    if ((sfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0) {
497       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
498                     sfd, sizeof(hdr), strerror(errno));
499            goto bail_out;
500    }
501    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
502       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
503                     sfd, (int)stat, hdr_size, strerror(errno));
504       goto bail_out;
505    }
506    if (hdr.version != state_hdr.version) {
507       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
508          state_hdr.version, hdr.version);
509    }
510    hdr.id[13] = 0;
511    if (strcmp(hdr.id, state_hdr.id) != 0) {
512       Dmsg0(000, "State file header id invalid.\n");
513       goto bail_out;
514    }
515 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
516    read_last_jobs_list(sfd, hdr.last_jobs_addr);
517 bail_out:
518    if (sfd >= 0) {
519       close(sfd);
520    }
521    free_pool_memory(fname);
522 }
523
524 /*
525  * Write the state file
526  */
527 void write_state_file(char *dir, const char *progname, int port)
528 {
529    int sfd;
530    POOLMEM *fname = get_pool_memory(PM_FNAME);
531
532    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
533    /* Create new state file */
534    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
535       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, strerror(errno));
536       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, strerror(errno));
537       goto bail_out;
538    }
539    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
540       Dmsg1(000, "Write hdr error: ERR=%s\n", strerror(errno));
541       goto bail_out;
542    }
543 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
544    state_hdr.last_jobs_addr = sizeof(state_hdr);
545    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
546 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
547    if (lseek(sfd, 0, SEEK_SET) < 0) {
548       Dmsg1(000, "lseek error: ERR=%s\n", strerror(errno));
549       goto bail_out;
550    }
551    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
552       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), strerror(errno));
553    }
554 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
555 bail_out:
556    if (sfd >= 0) {
557       close(sfd);
558    }
559    free_pool_memory(fname);
560 }
561
562
563 /*
564  * Drop to privilege new userid and new gid if non-NULL
565  */
566 void drop(char *uid, char *gid)
567 {
568 #ifdef HAVE_GRP_H
569    if (gid) {
570       struct group *group;
571       gid_t gr_list[1];
572
573       if ((group = getgrnam(gid)) == NULL) {
574          Emsg1(M_ERROR_TERM, 0, _("Could not find specified group: %s\n"), gid);
575       }
576       if (setgid(group->gr_gid)) {
577          Emsg1(M_ERROR_TERM, 0, _("Could not set specified group: %s\n"), gid);
578       }
579       gr_list[0] = group->gr_gid;
580       if (setgroups(1, gr_list)) {
581          Emsg1(M_ERROR_TERM, 0, _("Could not set specified group: %s\n"), gid);
582       }
583    }
584 #endif
585
586 #ifdef HAVE_PWD_H
587    if (uid) {
588       struct passwd *passw;
589       if ((passw = getpwnam(uid)) == NULL) {
590          Emsg1(M_ERROR_TERM, 0, _("Could not find specified userid: %s\n"), uid);
591       }
592       if (setuid(passw->pw_uid)) {
593          Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), uid);
594       }
595    }
596 #endif
597
598 }
599
600
601 /* BSDI does not have this.  This is a *poor* simulation */
602 #ifndef HAVE_STRTOLL
603 long long int
604 strtoll(const char *ptr, char **endptr, int base)
605 {
606    return (long long int)strtod(ptr, endptr);
607 }
608 #endif
609
610 /*
611  * Bacula's implementation of fgets(). The difference is that it handles
612  *   being interrupted by a signal (e.g. a SIGCHLD).
613  */
614 #undef fgetc
615 char *bfgets(char *s, int size, FILE *fd)
616 {
617    char *p = s;
618    int ch;
619    *p = 0;
620    for (int i=0; i < size-1; i++) {
621       do {
622          errno = 0;
623          ch = fgetc(fd);
624       } while (ch == -1 && (errno == EINTR || errno == EAGAIN));
625       if (ch == -1) {
626          if (i == 0) {
627             return NULL;
628          } else {
629             return s;
630          }
631       }
632       *p++ = ch;
633       *p = 0;
634       if (ch == '\r') { /* Support for Mac/Windows file format */
635          ch = fgetc(fd);
636          if (ch == '\n') { /* Windows (\r\n) */
637             *p++ = ch;
638             *p = 0;
639          }
640          else { /* Mac (\r only) */
641             ungetc(ch, fd); /* Push next character back to fd */
642          }
643          break;
644       }
645       if (ch == '\n') {
646          break;
647       }
648    }
649    return s;
650 }
651
652 /*
653  * Make a "unique" filename.  It is important that if
654  *   called again with the same "what" that the result
655  *   will be identical. This allows us to use the file
656  *   without saving its name, and re-generate the name
657  *   so that it can be deleted.
658  */
659 void make_unique_filename(POOLMEM **name, int Id, char *what)
660 {
661    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
662 }