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