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