]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
Restore JobIds in right order + Tru64 porting
[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 #ifdef xxxxxxxxxx_STRERROR_R
205 int strerror_r(int errnum, char *buf, size_t bufsiz)
206 {
207     static pthread_mutex_t mutex;
208     static int first = 1;
209     int stat = 0;
210     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 #endif /* HAVE_STRERROR_R */
228
229 /*
230  * These are mutex routines that do error checking
231  *  for deadlock and such.  Normally not turned on.
232  */
233 #ifdef DEBUG_MUTEX
234 void _p(char *file, int line, pthread_mutex_t *m)
235 {
236    int errstat;
237    if ((errstat = pthread_mutex_trylock(m))) {
238       e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n"));
239       /* We didn't get the lock, so do it definitely now */
240       if ((errstat=pthread_mutex_lock(m))) {
241          e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
242                strerror(errstat));
243       } else {
244          e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n"));
245       }
246          
247    }
248 }
249
250 void _v(char *file, int line, pthread_mutex_t *m)
251 {
252    int errstat;
253
254    if ((errstat=pthread_mutex_trylock(m)) == 0) {
255       e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"),
256            strerror(errstat));
257     }
258     if ((errstat=pthread_mutex_unlock(m))) {
259        e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
260               strerror(errstat));
261     }
262 }
263 #endif /* DEBUG_MUTEX */
264
265 #ifdef DEBUG_MEMSET
266 /* These routines are not normally turned on */
267 #undef memset
268 void b_memset(const char *file, int line, void *mem, int val, size_t num)
269 {
270    /* Testing for 2000 byte zero at beginning of Volume block */
271    if (num > 1900 && num < 3000) {
272       Pmsg3(000, "Memset for %d bytes at %s:%d\n", (int)num, file, line);
273    }
274    memset(mem, val, num);
275 }
276 #endif
277
278 #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
279 static int del_pid_file_ok = FALSE;
280 #endif
281
282 /*
283  * Create a standard "Unix" pid file.
284  */
285 void create_pid_file(char *dir, const char *progname, int port)
286 {
287 #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32)
288    int pidfd, len;
289    int oldpid;
290    char  pidbuf[20];
291    POOLMEM *fname = get_pool_memory(PM_FNAME);
292    struct stat statp;
293
294    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
295    if (stat(mp_chr(fname), &statp) == 0) {
296       /* File exists, see what we have */
297       *pidbuf = 0;
298       if ((pidfd = open(mp_chr(fname), O_RDONLY|O_BINARY, 0)) < 0 || 
299            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
300            sscanf(pidbuf, "%d", &oldpid) != 1) {
301          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno));
302       }
303       /* See if other Bacula is still alive */
304       if (kill(oldpid, 0) != -1 || errno != ESRCH) {
305          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
306                progname, oldpid, fname);
307       }
308       /* He is not alive, so take over file ownership */
309       unlink(mp_chr(fname));                  /* remove stale pid file */
310    }
311    /* Create new pid file */
312    if ((pidfd = open(mp_chr(fname), O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
313       len = sprintf(pidbuf, "%d\n", (int)getpid());
314       write(pidfd, pidbuf, len);
315       close(pidfd);
316       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
317    } else {
318       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno));
319    }
320    free_pool_memory(fname);
321 #endif
322 }
323
324
325 /*
326  * Delete the pid file if we created it
327  */
328 int delete_pid_file(char *dir, const char *progname, int port)
329 {
330 #if !defined(HAVE_CYGWIN)  && !defined(HAVE_WIN32)
331    POOLMEM *fname = get_pool_memory(PM_FNAME);
332
333    if (!del_pid_file_ok) {
334       free_pool_memory(fname);
335       return 0;
336    }
337    del_pid_file_ok = FALSE;
338    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
339    unlink(mp_chr(fname));
340    free_pool_memory(fname);
341 #endif
342    return 1;
343 }
344
345 struct s_state_hdr {
346    char id[14];
347    int32_t version;
348    uint64_t last_jobs_addr;
349    uint64_t reserved[20];
350 };
351
352 static struct s_state_hdr state_hdr = { 
353    "Bacula State\n",
354    3,
355    0
356 };
357
358 /*
359  * Open and read the state file for the daemon
360  */
361 void read_state_file(char *dir, const char *progname, int port)
362 {
363    int sfd;
364    ssize_t stat;
365    POOLMEM *fname = get_pool_memory(PM_FNAME);
366    struct s_state_hdr hdr;
367    int hdr_size = sizeof(hdr);
368
369    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
370    /* If file exists, see what we have */
371 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
372    if ((sfd = open(mp_chr(fname), O_RDONLY|O_BINARY, 0)) < 0) {
373       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n", 
374                     sfd, sizeof(hdr), strerror(errno));
375            goto bail_out;
376    }
377    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
378       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n", 
379                     sfd, (int)stat, hdr_size, strerror(errno));
380       goto bail_out;
381    }
382    if (hdr.version != state_hdr.version) {
383       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n", 
384          state_hdr.version, hdr.version);
385    }
386    hdr.id[13] = 0;
387    if (strcmp(hdr.id, state_hdr.id) != 0) {
388       Dmsg0(000, "State file header id invalid.\n");
389       goto bail_out;
390    }
391 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
392    read_last_jobs_list(sfd, hdr.last_jobs_addr);
393 bail_out:
394    if (sfd >= 0) {
395       close(sfd);
396    }
397    free_pool_memory(fname);
398 }
399
400 /*
401  * Write the state file
402  */
403 void write_state_file(char *dir, const char *progname, int port)
404 {
405    int sfd;
406    POOLMEM *fname = get_pool_memory(PM_FNAME);
407
408    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
409    /* Create new state file */
410    if ((sfd = open(mp_chr(fname), O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
411       Dmsg2(000, _("Could not create state file. %s ERR=%s\n"), fname, strerror(errno));
412       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, strerror(errno));
413       goto bail_out;
414    }
415    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
416       Dmsg1(000, "Write hdr error: ERR=%s\n", strerror(errno));
417       goto bail_out;
418    }
419 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
420    state_hdr.last_jobs_addr = sizeof(state_hdr);
421    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);   
422 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
423    if (lseek(sfd, 0, SEEK_SET) < 0) {
424       Dmsg1(000, "lseek error: ERR=%s\n", strerror(errno));
425       goto bail_out;
426    }  
427    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
428       Pmsg1(000, "Write final hdr error: ERR=%s\n", strerror(errno));
429    }
430 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
431 bail_out:
432    if (sfd >= 0) {
433       close(sfd);
434    }
435    free_pool_memory(fname);
436 }
437
438
439 /*
440  * Drop to privilege new userid and new gid if non-NULL
441  */
442 void drop(char *uid, char *gid)
443 {
444 #ifdef HAVE_GRP_H
445    if (gid) {
446       struct group *group;
447       gid_t gr_list[1];
448
449       if ((group = getgrnam(gid)) == NULL) {
450          Emsg1(M_ERROR_TERM, 0, _("Could not find specified group: %s\n"), gid);
451       }
452       if (setgid(group->gr_gid)) {
453          Emsg1(M_ERROR_TERM, 0, _("Could not set specified group: %s\n"), gid);
454       }
455       gr_list[0] = group->gr_gid;
456       if (setgroups(1, gr_list)) {
457          Emsg1(M_ERROR_TERM, 0, _("Could not set specified group: %s\n"), gid);
458       }
459    }
460 #endif
461
462 #ifdef HAVE_PWD_H
463    if (uid) {
464       struct passwd *passw;
465       if ((passw = getpwnam(uid)) == NULL) {
466          Emsg1(M_ERROR_TERM, 0, _("Could not find specified userid: %s\n"), uid);
467       }
468       if (setuid(passw->pw_uid)) {
469          Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), uid);
470       }
471    }
472 #endif
473           
474 }
475
476 static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
477 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
478
479 /*
480  * This routine will sleep (sec, microsec).  Note, however, that if a 
481  *   signal occurs, it will return early.  It is up to the caller
482  *   to recall this routine if he/she REALLY wants to sleep the
483  *   requested time.
484  */
485 int bmicrosleep(time_t sec, long usec)
486 {
487    struct timespec timeout;
488    struct timeval tv;
489    struct timezone tz;
490    int stat;
491
492    timeout.tv_sec = sec;
493    timeout.tv_nsec = usec * 1000;
494
495 #ifdef HAVE_NANOSLEEP
496    stat = nanosleep(&timeout, NULL);
497    if (!(stat < 0 && errno == ENOSYS)) {
498       return stat;                   
499    }
500    /* If we reach here it is because nanosleep is not supported by the OS */
501 #endif
502
503    /* Do it the old way */
504    gettimeofday(&tv, &tz);
505    timeout.tv_nsec += tv.tv_usec * 1000;
506    timeout.tv_sec += tv.tv_sec;
507    while (timeout.tv_nsec >= 1000000000) {
508       timeout.tv_nsec -= 1000000000;
509       timeout.tv_sec++;
510    }
511
512    Dmsg2(200, "pthread_cond_timedwait sec=%d usec=%d\n", sec, usec);
513    /* Note, this unlocks mutex during the sleep */
514    P(timer_mutex);
515    stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout);
516    if (stat != 0) {
517       Dmsg2(200, "pthread_cond_timedwait stat=%d ERR=%s\n", stat,
518          strerror(stat));
519    }
520    V(timer_mutex);
521    return stat;
522 }
523
524 /* BSDI does not have this.  This is a *poor* simulation */
525 #ifndef HAVE_STRTOLL
526 long long int
527 strtoll(const char *ptr, char **endptr, int base)
528 {
529    return (long long int)strtod(ptr, endptr);   
530 }
531 #endif
532
533 /*
534  * Bacula's implementation of fgets(). The difference is that it handles
535  *   being interrupted by a signal (e.g. a SIGCHLD).
536  */
537 #undef fgetc
538 char *bfgets(char *s, int size, FILE *fd)
539 {
540    char *p = s;
541    int ch;       
542    *p = 0;
543    for (int i=0; i < size-1; i++) {
544       do {
545          errno = 0;
546          ch = fgetc(fd);
547       } while (ch == -1 && (errno == EINTR || errno == EAGAIN));
548       if (ch == -1) {
549          if (i == 0) {
550             return NULL;
551          } else {
552             return s;
553          }
554       }
555       *p++ = ch;
556       *p = 0;
557       if (ch == '\r') { /* Support for Mac/Windows file format */
558          ch = fgetc(fd);
559          if (ch == '\n') { /* Windows (\r\n) */
560             *p++ = ch;
561             *p = 0;
562          }
563          else { /* Mac (\r only) */
564             ungetc(ch, fd); /* Push next character back to fd */
565          }
566          break;
567       }      
568       if (ch == '\n') {
569          break;
570       }
571    }
572    return s;
573 }
574
575 /*
576  * Make a "unique" filename.  It is important that if
577  *   called again with the same "what" that the result
578  *   will be identical. This allows us to use the file
579  *   without saving its name, and re-generate the name
580  *   so that it can be deleted.
581  */
582 void make_unique_filename(POOLMEM **name, int Id, char *what)
583 {
584    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
585 }