X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fbsys.c;h=548ab97b2a6fbdb4ba562230f641f709ada893cd;hb=3f8a3a045ea058657030f588a10f786449d00e0d;hp=4ddb3f4c0029eb1c2fa931dcbd7aab1eef6f3f1f;hpb=8986602d8351602c965a71e82262e30a179788a9;p=bacula%2Fbacula diff --git a/bacula/src/lib/bsys.c b/bacula/src/lib/bsys.c index 4ddb3f4c00..548ab97b2a 100644 --- a/bacula/src/lib/bsys.c +++ b/bacula/src/lib/bsys.c @@ -1,29 +1,24 @@ /* * Miscellaneous Bacula memory and thread safe routines * Generally, these are interfaces to system or standard - * library routines. - * + * library routines. + * * Bacula utility functions are in util.c * * Version $Id$ */ /* - Copyright (C) 2000-2003 Kern Sibbald and John Walker + Copyright (C) 2000-2006 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as amended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -36,6 +31,55 @@ #include #endif +static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t timer = PTHREAD_COND_INITIALIZER; + +/* + * This routine will sleep (sec, microsec). Note, however, that if a + * signal occurs, it will return early. It is up to the caller + * to recall this routine if he/she REALLY wants to sleep the + * requested time. + */ +int bmicrosleep(time_t sec, long usec) +{ + struct timespec timeout; + struct timeval tv; + struct timezone tz; + int stat; + + timeout.tv_sec = sec; + timeout.tv_nsec = usec * 1000; + +#ifdef HAVE_NANOSLEEP + stat = nanosleep(&timeout, NULL); + if (!(stat < 0 && errno == ENOSYS)) { + return stat; + } + /* If we reach here it is because nanosleep is not supported by the OS */ +#endif + + /* Do it the old way */ + gettimeofday(&tv, &tz); + timeout.tv_nsec += tv.tv_usec * 1000; + timeout.tv_sec += tv.tv_sec; + while (timeout.tv_nsec >= 1000000000) { + timeout.tv_nsec -= 1000000000; + timeout.tv_sec++; + } + + Dmsg2(200, "pthread_cond_timedwait sec=%d usec=%d\n", sec, usec); + /* Note, this unlocks mutex during the sleep */ + P(timer_mutex); + stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout); + if (stat != 0) { + berrno be; + Dmsg2(200, "pthread_cond_timedwait stat=%d ERR=%s\n", stat, + be.strerror(stat)); + } + V(timer_mutex); + return stat; +} + /* * Guarantee that the string is properly terminated */ char *bstrncpy(char *dest, const char *src, int maxlen) @@ -45,6 +89,16 @@ char *bstrncpy(char *dest, const char *src, int maxlen) return dest; } +/* + * Guarantee that the string is properly terminated */ +char *bstrncpy(char *dest, POOL_MEM &src, int maxlen) +{ + strncpy(dest, src.c_str(), maxlen-1); + dest[maxlen-1] = 0; + return dest; +} + + char *bstrncat(char *dest, const char *src, int maxlen) { strncat(dest, src, maxlen-1); @@ -52,6 +106,75 @@ char *bstrncat(char *dest, const char *src, int maxlen) return dest; } +char *bstrncat(char *dest, POOL_MEM &src, int maxlen) +{ + strncat(dest, src.c_str(), maxlen-1); + dest[maxlen-1] = 0; + return dest; +} + +/* + * Allows one or both pointers to be NULL + */ +bool bstrcmp(const char *s1, const char *s2) +{ + if (s1 == s2) return true; + if (s1 == NULL || s2 == NULL) return false; + return strcmp(s1, s2) == 0; +} + +/* + * Get character length of UTF-8 string + * + * Valid UTF-8 codes + * U-00000000 - U-0000007F: 0xxxxxxx + * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx + * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx + * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ +int cstrlen(const char *str) +{ + uint8_t *p = (uint8_t *)str; + int len = 0; + while (*p) { + if ((*p & 0xC0) != 0xC0) { + p++; + len++; + continue; + } + if ((*p & 0xD0) == 0xC0) { + p += 2; + len++; + continue; + } + if ((*p & 0xF0) == 0xD0) { + p += 3; + len++; + continue; + } + if ((*p & 0xF8) == 0xF0) { + p += 4; + len++; + continue; + } + if ((*p & 0xFC) == 0xF8) { + p += 5; + len++; + continue; + } + if ((*p & 0xFE) == 0xFC) { + p += 6; + len++; + continue; + } + p++; /* Shouln't get here but must advance */ + } + return len; +} + + #ifndef DEBUG void *bmalloc(size_t size) @@ -60,7 +183,8 @@ void *bmalloc(size_t size) buf = malloc(size); if (buf == NULL) { - Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno)); + berrno be; + Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror()); } return buf; } @@ -76,7 +200,8 @@ void *b_malloc(const char *file, int line, size_t size) buf = malloc(size); #endif if (buf == NULL) { - e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno)); + berrno be; + e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror()); } return buf; } @@ -86,7 +211,8 @@ void *brealloc (void *buf, size_t size) { buf = realloc(buf, size); if (buf == NULL) { - Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno)); + berrno be; + Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror()); } return buf; } @@ -98,46 +224,28 @@ void *bcalloc (size_t size1, size_t size2) buf = calloc(size1, size2); if (buf == NULL) { - Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), strerror(errno)); + berrno be; + Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror()); } return buf; } +/* Code now in src/lib/bsnprintf.c */ +#ifndef USE_BSNPRINTF #define BIG_BUF 5000 /* * Implement snprintf */ -int bsnprintf(char *str, int32_t size, const char *fmt, ...) +int bsnprintf(char *str, int32_t size, const char *fmt, ...) { -#ifdef HAVE_VSNPRINTF va_list arg_ptr; int len; va_start(arg_ptr, fmt); - len = vsnprintf(str, size, fmt, arg_ptr); + len = bvsnprintf(str, size, fmt, arg_ptr); va_end(arg_ptr); - str[size-1] = 0; return len; - -#else - - va_list arg_ptr; - int len; - char *buf; - - buf = get_memory(BIG_BUF); - va_start(arg_ptr, fmt); - len = vsprintf(buf, fmt, arg_ptr); - va_end(arg_ptr); - if (len >= BIG_BUF) { - Emsg0(M_ABORT, 0, _("Buffer overflow.\n")); - } - memcpy(str, buf, size); - str[size-1] = 0; - free_memory(buf); - return len; -#endif } /* @@ -153,32 +261,29 @@ int bvsnprintf(char *str, int32_t size, const char *format, va_list ap) #else - int len; + int len, buflen; char *buf; - buf = get_memory(BIG_BUF); + buflen = size > BIG_BUF ? size : BIG_BUF; + buf = get_memory(buflen); len = vsprintf(buf, format, ap); - if (len >= BIG_BUF) { + if (len >= buflen) { Emsg0(M_ABORT, 0, _("Buffer overflow.\n")); } - memcpy(str, buf, size); - str[size-1] = 0; + memcpy(str, buf, len); + str[len] = 0; /* len excludes the null */ free_memory(buf); return len; #endif } +#endif /* USE_BSNPRINTF */ #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *timep, struct tm *tm) { - static pthread_mutex_t mutex; - static int first = 1; - struct tm *ltm; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + struct tm *ltm, - if (first) { - pthread_mutex_init(&mutex, NULL); - first = 0; - } P(mutex); ltm = localtime(timep); if (ltm) { @@ -195,15 +300,10 @@ struct tm *localtime_r(const time_t *timep, struct tm *tm) int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { - static pthread_mutex_t mutex; - static int first = 1; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; struct dirent *ndir; int stat; - if (first) { - pthread_mutex_init(&mutex, NULL); - first = 0; - } P(mutex); errno = 0; ndir = readdir(dirp); @@ -222,18 +322,13 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) #endif #endif /* HAVE_READDIR_R */ -#ifdef xxxxxxxxxx_STRERROR_R -int strerror_r(int errnum, char *buf, size_t bufsiz) + +int bstrerror(int errnum, char *buf, size_t bufsiz) { - static pthread_mutex_t mutex; - static int first = 1; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int stat = 0; - char *msg; + const char *msg; - if (first) { - pthread_mutex_init(&mutex, NULL); - first = 0; - } P(mutex); msg = strerror(errnum); @@ -245,7 +340,6 @@ int strerror_r(int errnum, char *buf, size_t bufsiz) V(mutex); return stat; } -#endif /* HAVE_STRERROR_R */ /* * These are mutex routines that do error checking @@ -259,12 +353,13 @@ void _p(char *file, int line, pthread_mutex_t *m) e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n")); /* We didn't get the lock, so do it definitely now */ if ((errstat=pthread_mutex_lock(m))) { + berrno be; e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"), - strerror(errstat)); + be.strerror(errstat)); } else { e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n")); } - + } } @@ -273,16 +368,54 @@ void _v(char *file, int line, pthread_mutex_t *m) int errstat; if ((errstat=pthread_mutex_trylock(m)) == 0) { + berrno be; e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"), - strerror(errstat)); + be.strerror(errstat)); } if ((errstat=pthread_mutex_unlock(m))) { + berrno be; e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"), - strerror(errstat)); + be.strerror(errstat)); } } + +#else + +void _p(pthread_mutex_t *m) +{ + int errstat; + if ((errstat=pthread_mutex_lock(m))) { + berrno be; + e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"), + be.strerror(errstat)); + } +} + +void _v(pthread_mutex_t *m) +{ + int errstat; + if ((errstat=pthread_mutex_unlock(m))) { + berrno be; + e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"), + be.strerror(errstat)); + } +} + #endif /* DEBUG_MUTEX */ +#ifdef DEBUG_MEMSET +/* These routines are not normally turned on */ +#undef memset +void b_memset(const char *file, int line, void *mem, int val, size_t num) +{ + /* Testing for 2000 byte zero at beginning of Volume block */ + if (num > 1900 && num < 3000) { + Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line); + } + memset(mem, val, num); +} +#endif + #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32) static int del_pid_file_ok = FALSE; #endif @@ -300,28 +433,28 @@ void create_pid_file(char *dir, const char *progname, int port) struct stat statp; Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port); - if (stat(mp_chr(fname), &statp) == 0) { + if (stat(fname, &statp) == 0) { /* File exists, see what we have */ *pidbuf = 0; - if ((pidfd = open(mp_chr(fname), O_RDONLY|O_BINARY, 0)) < 0 || - read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 || + if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 || + read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 || sscanf(pidbuf, "%d", &oldpid) != 1) { Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno)); } /* See if other Bacula is still alive */ if (kill(oldpid, 0) != -1 || errno != ESRCH) { Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"), - progname, oldpid, fname); + progname, oldpid, fname); } /* He is not alive, so take over file ownership */ - unlink(mp_chr(fname)); /* remove stale pid file */ + unlink(fname); /* remove stale pid file */ } /* Create new pid file */ - if ((pidfd = open(mp_chr(fname), O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0644)) >= 0) { + if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) { len = sprintf(pidbuf, "%d\n", (int)getpid()); write(pidfd, pidbuf, len); close(pidfd); - del_pid_file_ok = TRUE; /* we created it so we can delete it */ + del_pid_file_ok = TRUE; /* we created it so we can delete it */ } else { Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno)); } @@ -344,7 +477,7 @@ int delete_pid_file(char *dir, const char *progname, int port) } del_pid_file_ok = FALSE; Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port); - unlink(mp_chr(fname)); + unlink(fname); free_pool_memory(fname); #endif return 1; @@ -357,12 +490,27 @@ struct s_state_hdr { uint64_t reserved[20]; }; -static struct s_state_hdr state_hdr = { +static struct s_state_hdr state_hdr = { "Bacula State\n", 3, 0 }; +#ifdef HAVE_WIN32 +#undef open +#undef read +#undef write +#undef lseek +#undef close +#undef O_BINARY +#define open _open +#define read _read +#define write _write +#define lseek _lseeki64 +#define close _close +#define O_BINARY _O_BINARY +#endif + /* * Open and read the state file for the daemon */ @@ -370,6 +518,7 @@ void read_state_file(char *dir, const char *progname, int port) { int sfd; ssize_t stat; + bool ok = false; POOLMEM *fname = get_pool_memory(PM_FNAME); struct s_state_hdr hdr; int hdr_size = sizeof(hdr); @@ -377,19 +526,20 @@ void read_state_file(char *dir, const char *progname, int port) Mmsg(&fname, "%s/%s.%d.state", dir, progname, port); /* If file exists, see what we have */ // Dmsg1(10, "O_BINARY=%d\n", O_BINARY); - if ((sfd = open(mp_chr(fname), O_RDONLY|O_BINARY, 0)) < 0) { - Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n", - sfd, sizeof(hdr), strerror(errno)); - goto bail_out; + if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) { + Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n", + sfd, sizeof(hdr), strerror(errno)); + goto bail_out; } if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) { - Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n", - sfd, (int)stat, hdr_size, strerror(errno)); + Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n", + sfd, (int)stat, hdr_size, strerror(errno)); goto bail_out; } if (hdr.version != state_hdr.version) { - Dmsg2(010, "Bad hdr version. Wanted %d got %d\n", - state_hdr.version, hdr.version); + Dmsg2(010, "Bad hdr version. Wanted %d got %d\n", + state_hdr.version, hdr.version); + goto bail_out; } hdr.id[13] = 0; if (strcmp(hdr.id, state_hdr.id) != 0) { @@ -397,11 +547,17 @@ void read_state_file(char *dir, const char *progname, int port) goto bail_out; } // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr)); - read_last_jobs_list(sfd, hdr.last_jobs_addr); + if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) { + goto bail_out; + } + ok = true; bail_out: if (sfd >= 0) { close(sfd); } + if (!ok) { + unlink(fname); + } free_pool_memory(fname); } @@ -411,35 +567,46 @@ bail_out: void write_state_file(char *dir, const char *progname, int port) { int sfd; + bool ok = false; POOLMEM *fname = get_pool_memory(PM_FNAME); Mmsg(&fname, "%s/%s.%d.state", dir, progname, port); /* Create new state file */ - if ((sfd = open(mp_chr(fname), O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) { - Dmsg2(000, _("Could not create state file. %s ERR=%s\n"), fname, strerror(errno)); - Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, strerror(errno)); + unlink(fname); + if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) { + berrno be; + Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.strerror()); + Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.strerror()); goto bail_out; } if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) { - Dmsg1(000, "Write hdr error: ERR=%s\n", strerror(errno)); + berrno be; + Dmsg1(000, "Write hdr error: ERR=%s\n", be.strerror()); goto bail_out; } // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr)); state_hdr.last_jobs_addr = sizeof(state_hdr); - state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr); + state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr); // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]); if (lseek(sfd, 0, SEEK_SET) < 0) { - Dmsg1(000, "lseek error: ERR=%s\n", strerror(errno)); + berrno be; + Dmsg1(000, "lseek error: ERR=%s\n", be.strerror()); goto bail_out; - } + } if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) { - Dmsg1(000, "Write final hdr error: ERR=%s\n", strerror(errno)); + berrno be; + Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.strerror()); + goto bail_out; } + ok = true; // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr)); bail_out: if (sfd >= 0) { close(sfd); } + if (!ok) { + unlink(fname); + } free_pool_memory(fname); } @@ -478,60 +645,16 @@ void drop(char *uid, char *gid) } } #endif - -} - -static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t timer = PTHREAD_COND_INITIALIZER; - -/* - * This routine will sleep (sec, microsec). Note, however, that if a - * signal occurs, it will return early. It is up to the caller - * to recall this routine if he/she REALLY wants to sleep the - * requested time. - */ -int bmicrosleep(time_t sec, long usec) -{ - struct timespec timeout; - struct timeval tv; - struct timezone tz; - int stat; - - timeout.tv_sec = sec; - timeout.tv_nsec = usec * 1000; - -#ifdef HAVE_NANOSLEEP - stat = nanosleep(&timeout, NULL); - if (!(stat < 0 && errno == ENOSYS)) { - return stat; - } - /* If we reach here it is because nanosleep is not supported by the OS */ -#endif - /* Do it the old way */ - gettimeofday(&tv, &tz); - timeout.tv_nsec += tv.tv_usec * 1000; - timeout.tv_sec += tv.tv_sec; - while (timeout.tv_nsec >= 1000000000) { - timeout.tv_nsec -= 1000000000; - timeout.tv_sec++; - } - - Dmsg1(200, "pthread_cond_timedwait sec=%d\n", timeout.tv_sec); - /* Note, this unlocks mutex during the sleep */ - P(timer_mutex); - stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout); - Dmsg1(200, "pthread_cond_timedwait stat=%d\n", stat); - V(timer_mutex); - return stat; } + /* BSDI does not have this. This is a *poor* simulation */ #ifndef HAVE_STRTOLL long long int strtoll(const char *ptr, char **endptr, int base) { - return (long long int)strtod(ptr, endptr); + return (long long int)strtod(ptr, endptr); } #endif @@ -543,24 +666,35 @@ strtoll(const char *ptr, char **endptr, int base) char *bfgets(char *s, int size, FILE *fd) { char *p = s; - int ch; + int ch; *p = 0; for (int i=0; i < size-1; i++) { do { - errno = 0; - ch = fgetc(fd); + errno = 0; + ch = fgetc(fd); } while (ch == -1 && (errno == EINTR || errno == EAGAIN)); if (ch == -1) { - if (i == 0) { - return NULL; - } else { - return s; - } + if (i == 0) { + return NULL; + } else { + return s; + } } *p++ = ch; *p = 0; + if (ch == '\r') { /* Support for Mac/Windows file format */ + ch = fgetc(fd); + if (ch == '\n') { /* Windows (\r\n) */ + *p++ = ch; + *p = 0; + } + else { /* Mac (\r only) */ + (void)ungetc(ch, fd); /* Push next character back to fd */ + } + break; + } if (ch == '\n') { - break; + break; } } return s;