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