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