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