/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* Cherokee * * Authors: * Alvaro Lopez Ortega * * Copyright (C) 2001-2007 Alvaro Lopez Ortega * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * 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 */ #include "common-internal.h" #include "util.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H # include #else # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_FILIO_H # include /* defines FIONBIO and FIONREAD */ #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #if defined (HAVE_SYS_RESOURCE_H) # include #elif defined (HAVE_RESOURCE_H) # include #endif #ifdef HAVE_NETDB_H # include /* defines gethostbyname() */ #endif #ifdef HAVE_SYSLOG_H # include #endif #if defined(HAVE_GNUTLS) # include #elif defined(HAVE_OPENSSL) # include # include # include # include #if HAVE_OPENSSL_ENGINE_H # include #endif #endif #define ENTRIES "util" const char *cherokee_version = PACKAGE_VERSION; /* Given an error number (errno) it returns an error string. * Parameters "buf" and "bufsize" are passed by caller * in order to make the function "thread safe". * If the error number is unknown * then an "Unknown error nnn" string is returned. */ char * cherokee_strerror_r (int err, char *buf, size_t bufsize) { #ifdef _WIN32 return win_strerror (err, buf, bufsize); #else char *p; if (buf == NULL) return NULL; if (bufsize < ERROR_MIN_BUFSIZE) return NULL; p = strerror(err); if (p == NULL) { buf[0] = '\0'; snprintf (buf, bufsize, "Unknown error %d (errno)", err); buf[bufsize-1] = '\0'; return buf; } return p; #endif } /* This function is licenced under: * The Apache Software License, Version 1.1 * * Original name: apr_strfsize() * * Copyright (c) 2000-2003 The Apache Software Foundation. * All rights reserved. */ char * cherokee_strfsize (unsigned long long size, char *buf) { const char ord[] = "KMGTPE"; const char *o = ord; int remain; if (size < 0) { return strcpy(buf, " - "); } if (size < 973) { sprintf(buf, "%3d ", (int) size); return buf; } do { remain = (int)(size & 1023); size >>= 10; if (size >= 973) { ++o; continue; } if (size < 9 || (size == 9 && remain < 973)) { if ((remain = ((remain * 5) + 256) / 512) >= 10) ++size, remain = 0; sprintf(buf, "%d.%d%c", (int) size, remain, *o); return buf; } if (remain >= 512) ++size; sprintf(buf, "%3d%c", (int) size, *o); return buf; } while (1); } char * cherokee_min_str (char *s1, char *s2) { if ((s1 == NULL) && (s2 == NULL)) return NULL; if ((s1 != NULL) && (s2 == NULL)) return s1; if ((s2 != NULL) && (s1 == NULL)) return s2; return (s1s2) ? s1 : s2; } ret_t cherokee_sys_fdlimit_get (cuint_t *limit) { #ifdef HAVE_GETRLIMIT struct rlimit rlp; rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY; if (getrlimit(RLIMIT_NOFILE, &rlp)) return ret_error; *limit = rlp.rlim_cur; return ret_ok; #else #ifdef HAVE_GETDTABLESIZE int nfiles; nfiles = getdtablesize(); if (nfiles <= 0) return ret_error; *limit = nfiles; return ret_ok; #else #ifdef OPEN_MAX *limit = OPEN_MAX; /* need to include limits.h somehow */ return ret_ok; #else *limit = FD_SETSIZE; return ret_ok; #endif #endif #endif } ret_t cherokee_sys_fdlimit_set (cuint_t limit) { #ifndef _WIN32 int re; struct rlimit rl; rl.rlim_cur = limit; rl.rlim_max = limit; re = setrlimit (RLIMIT_NOFILE, &rl); if (re != 0) { return ret_error; } #endif return ret_ok; } #ifndef HAVE_STRSEP char * strsep (char** str, const char* delims) { char* token; if (*str == NULL) { /* No more tokens */ return NULL; } token = *str; while (**str!='\0') { if (strchr(delims,**str)!=NULL) { **str='\0'; (*str)++; return token; } (*str)++; } /* There is no other token */ *str=NULL; return token; } #endif #ifndef HAVE_STRCASESTR char * strcasestr (register char *s, register char *find) { register char c, sc; register size_t len; if ((c = *find++) != 0) { len = strlen(find); do { do { if ((sc = *s++) == 0) return NULL; } while (sc != c); } while (strncasecmp(s, find, len) != 0); s--; } return ((char *) s); } #endif /* Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t cherokee_strlcat (char *dst, const char *src, size_t siz) { #ifdef HAVE_STRLCAT return strlcat (dst, src, siz); #else /* The following few lines has been copy and pasted from Todd * C. Miller code. BSD licensed. */ register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but do not go * past end. */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; /* Count does not include NUL */ return(dlen + (s - src)); #endif } #ifndef HAVE_STRLCAT size_t strlcat (char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif #if defined(HAVE_PTHREAD) && !defined(HAVE_GMTIME_R) static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; #endif struct tm * cherokee_gmtime (const time_t *timep, struct tm *result) { #ifdef HAVE_GMTIME_R /* Use the thread safe version anyway (no data copy). */ return gmtime_r (timep, result); #else struct tm *tmp; CHEROKEE_MUTEX_LOCK (&gmtime_mutex); if (likely ((tmp = gmtime (timep)) != NULL)) memcpy (result, tmp, sizeof(struct tm)); CHEROKEE_MUTEX_UNLOCK (&gmtime_mutex); return (tmp == NULL ? NULL : result); #endif } #if defined(HAVE_PTHREAD) && !defined(HAVE_LOCALTIME_R) static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; #endif struct tm * cherokee_localtime (const time_t *timep, struct tm *result) { #ifdef HAVE_LOCALTIME_R /* Use the thread safe version anyway (no data copy). */ return localtime_r (timep, result); #else struct tm *tmp; CHEROKEE_MUTEX_LOCK (&localtime_mutex); if (likely ((tmp = localtime (timep)) != NULL)) memcpy (result, tmp, sizeof(struct tm)); CHEROKEE_MUTEX_UNLOCK (&localtime_mutex); return (tmp == NULL ? NULL : result); #endif } #if defined(HAVE_PTHREAD) && !defined(HAVE_READDIR_R) static pthread_mutex_t readdir_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /* The readdir subroutine is reentrant when an application program * uses different DirectoryPointer parameter values (returned from the * opendir subroutine). Use the readdir_r subroutine when multiple * threads use the same directory pointer. */ int cherokee_readdir (DIR *dirstream, struct dirent *entry, struct dirent **result) { #ifndef HAVE_READDIR # warning "readdir() unimplemented" return ENOSYS; #else # ifdef HAVE_READDIR_R_2 /* We cannot rely on the return value of readdir_r as it * differs between various platforms (HPUX returns 0 on * success whereas Solaris returns non-zero) */ entry->d_name[0] = '\0'; readdir_r (dirstream, entry); if (entry->d_name[0] != '\0') { *result = entry; return 0; } *result = NULL; return errno; # elif defined(HAVE_READDIR_R_3) return readdir_r (dirstream, entry, result); # else struct dirent *ptr; int ret = 0; CHEROKEE_MUTEX_LOCK (&readdir_mutex); errno = 0; ptr = readdir(dirstream); if (!ptr && errno != 0) ret = errno; if (ptr) memcpy(entry, ptr, sizeof(*ptr)); *result = ptr; CHEROKEE_MUTEX_UNLOCK (&readdir_mutex); return ret; # endif #endif } ret_t cherokee_split_pathinfo (cherokee_buffer_t *path, int init_pos, int allow_dirs, char **pathinfo, int *pathinfo_len) { char *cur; struct stat st; char *last_dir = NULL; if (init_pos > path->len) return ret_not_found; for (cur = path->buf + init_pos; *cur && (cur < path->buf + path->len); cur++) { if (*cur != '/') continue; *cur = '\0'; /* Handle not found case */ if (stat (path->buf, &st) == -1) { *cur = '/'; if ((allow_dirs) && (last_dir != NULL)) { *pathinfo = last_dir; *pathinfo_len = (path->buf + path->len) - last_dir; return ret_ok; } return ret_not_found; } /* Handle directory case */ if (S_ISDIR(st.st_mode)) { *cur = '/'; last_dir = cur; continue; } /* Build the PathInfo string */ *cur = '/'; *pathinfo = cur; *pathinfo_len = (path->buf + path->len) - cur; return ret_ok; } *pathinfo_len = 0; return ret_ok; } ret_t cherokee_split_arguments (cherokee_buffer_t *request, int init_pos, char **arguments, int *arguments_len) { char *tmp; char *p = request->buf + init_pos; char *end = request->buf + request->len; tmp = strchr (p, '?'); if (tmp == NULL) { *arguments = NULL; *arguments_len = 0; return ret_ok; } *arguments = tmp+1; *arguments_len = end - *arguments; return ret_ok; } int cherokee_estimate_va_length (char *fmt, va_list ap) { char *p; cuchar_t ch; cullong_t ul; cherokee_boolean_t lflag; cherokee_boolean_t llflag; cuint_t width; char padc; cuint_t len = 0; #define LEN_NUM(base) \ do { \ ul /= base; \ len++; \ } while (ul > 0); \ len++ for (;;) { width = 0; padc = ' '; while ((ch = *fmt++) != '%') { if (ch == '\0') return len+1; len++; } lflag = llflag = false; reswitch: switch (ch = *fmt++) { case 's': p = va_arg(ap, char *); len += strlen (p ? p : "(null)"); break; case 'd': ul = lflag ? va_arg(ap, culong_t) : va_arg(ap, int); if (ul < 0) { ul = -ul; len++; } LEN_NUM(10); break; case 'l': if (lflag == false) lflag = true; else llflag = true; goto reswitch; case 'u': if (llflag) { ul = va_arg(ap, cullong_t); } else { ul = lflag ? va_arg(ap, long) : va_arg(ap, int); } LEN_NUM(10); break; case '0': padc = '0'; goto reswitch; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (width = 0;; ++fmt) { width = width * 10 + ch - '0'; ch = *fmt; if (ch < '0' || ch > '9') break; } len += width; goto reswitch; case 'c': (void) va_arg(ap, int); len++; break; case 'o': ul = lflag ? va_arg(ap, culong_t) : va_arg(ap, int); LEN_NUM(8); break; case 'f': ul = va_arg(ap, double); /* FIXME: Add float numbers support */ len += 30; LEN_NUM(10); break; case 'p': len += 2; /* Pointer: "0x" + hex value */ case 'x': ul = lflag ? va_arg(ap, culong_t) : va_arg(ap, int); LEN_NUM(16); break; case '%': len++; default: len+=2; } } return -1; } /* gethostbyname_r () emulation */ #if defined(HAVE_PTHREAD) && !defined(HAVE_GETHOSTBYNAME_R) static pthread_mutex_t __global_gethostbyname_mutex = PTHREAD_MUTEX_INITIALIZER; #endif ret_t cherokee_gethostbyname (const char *hostname, void *_addr) { struct in_addr *addr = _addr; #if !defined(HAVE_PTHREAD) || (defined(HAVE_PTHREAD) && !defined(HAVE_GETHOSTBYNAME_R)) struct hostent *host; CHEROKEE_MUTEX_LOCK (&__global_gethostbyname_mutex); /* Resolv the host name */ host = gethostbyname (hostname); if (host == NULL) { CHEROKEE_MUTEX_UNLOCK (&__global_gethostbyname_mutex); return ret_error; } /* Copy the address */ memcpy (addr, host->h_addr, host->h_length); CHEROKEE_MUTEX_UNLOCK (&__global_gethostbyname_mutex); return ret_ok; #elif defined(HAVE_PTHREAD) && defined(HAVE_GETHOSTBYNAME_R) /* Maximum size that should use gethostbyname_r() function. * It will return ERANGE, if more space is needed. */ # define GETHOSTBYNAME_R_BUF_LEN 512 int r; int h_errnop; struct hostent hs; struct hostent *hp = NULL; char tmp[GETHOSTBYNAME_R_BUF_LEN]; # ifdef SOLARIS /* Solaris 10: * struct hostent *gethostbyname_r * (const char *, struct hostent *, char *, int, int *h_errnop); */ hp = gethostbyname_r (hostname, &hs, tmp, GETHOSTBYNAME_R_BUF_LEN - 1, &h_errnop); if (hp == NULL) return ret_error; # else /* Linux glibc2: * int gethostbyname_r (const char *name, * struct hostent *ret, char *buf, size_t buflen, * struct hostent **result, int *h_errnop); */ r = gethostbyname_r (hostname, &hs, tmp, GETHOSTBYNAME_R_BUF_LEN - 1, &hp, &h_errnop); if (r != 0) return ret_error; # endif /* Copy the address */ if (hp == NULL) return ret_not_found; memcpy (addr, hp->h_addr, hp->h_length); return ret_ok; #else /* Bad case ! */ SHOULDNT_HAPPEN; return ret_error; #endif } #ifdef HAVE_GNUTLS # ifdef GCRY_THREAD_OPTION_PTHREAD_IMPL GCRY_THREAD_OPTION_PTHREAD_IMPL; # endif #endif ret_t cherokee_tls_init (void) { #if HAVE_OPENSSL_ENGINE_H ENGINE *e; #endif #ifdef HAVE_GNUTLS int rc; # ifdef GCRY_THREAD_OPTION_PTHREAD_IMPL /* Although the GnuTLS library is thread safe by design, some * parts of the crypto backend, such as the random generator, * are not; hence, it needs to initialize some semaphores. */ gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); # endif /* Gnutls library-width initialization */ rc = gnutls_global_init(); if (rc < 0) { PRINT_ERROR_S ("Global GNUTLS state initialisation failed.\n"); return ret_error; } #endif #ifdef HAVE_OPENSSL # if HAVE_OPENSSL_ENGINE_H # if OPENSSL_VERSION_NUMBER >= 0x00907000L ENGINE_load_builtin_engines(); # endif e = ENGINE_by_id("pkcs11"); if (e != NULL) { if(!ENGINE_init(e)) { ENGINE_free(e); PRINT_ERROR_S ("could not init pkcs11 engine"); return ret_error; } if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { ENGINE_free(e); PRINT_ERROR_S ("could not set all defaults"); return ret_error; } ENGINE_finish(e); ENGINE_free(e); } # endif SSL_load_error_strings(); SSL_library_init(); SSLeay_add_all_algorithms (); SSLeay_add_ssl_algorithms (); #endif return ret_ok; } ret_t cherokee_fd_set_nonblocking (int fd) { int tmp = 1; #ifdef _WIN32 tmp = ioctlsocket (fd, FIONBIO, (u_long *)&tmp); #else tmp = ioctl (fd, FIONBIO, &tmp); #endif if (tmp < 0) { PRINT_ERROR ("ERROR: Setting 'FIONBIO' in socked fd=%d\n", fd); return ret_error; } return ret_ok; } /* Return 1 if big-endian (Motorola and Sparc), not little-endian * (Intel and Vax). We do this work at run-time, rather than at * configuration time so cross-compilation and general embedded system * support is simpler. */ int cherokee_isbigendian (void) { /* From Harbison & Steele. */ union { long l; char c[sizeof(long)]; } u; u.l = 1; return (u.c[sizeof(long) - 1] == 1); } ret_t cherokee_syslog (int priority, cherokee_buffer_t *buf) { char *p; char *nl, *end; if (cherokee_buffer_is_empty(buf)) return ret_ok; p = buf->buf; end = buf->buf + buf->len; do { nl = strchr (p, '\n'); if (nl != NULL) *nl = '\0'; syslog (priority, "%s", p); if (nl != NULL) *nl = '\n'; p = nl + 1; } while (p < end); return ret_ok; } #ifdef TRACE_ENABLED void cherokee_trace (const char *entry, const char *file, int line, const char *func, const char *fmt, ...) { static char *env = NULL; static cuint_t env_set = 0; static cuint_t use_syslog = 0; cherokee_boolean_t do_log = false; cherokee_buffer_t entries = CHEROKEE_BUF_INIT; cherokee_buffer_t output = CHEROKEE_BUF_INIT; char *lentry; char *lentry_end; va_list args; char *p; /* Read the environment variable in the first call */ if (env_set == 0) { env = getenv(TRACE_ENV); env_set = 1; if (env != NULL) use_syslog = (strstr (env, "syslog") != NULL); } /* Return quickly if there isn't anything to do */ if (env == NULL) { return; } cherokee_buffer_add (&entries, entry, strlen(entry)); for (lentry = entries.buf;;) { lentry_end = strchr (lentry, ','); if (lentry_end) *lentry_end = '\0'; /* Check for 'all' */ p = strstr (env, "all"); if (p) do_log = true; /* Check the type */ p = strstr (env, lentry); if (p) { char *tmp = p + strlen(lentry); if ((*tmp == '\0') || (*tmp == ',') || (*tmp == ' ')) do_log = true; } if (lentry_end == NULL) break; lentry = lentry_end + 1; } if (! do_log) goto out; /* Print the trace */ cherokee_buffer_add_va (&output, "%18s:%04d (%30s): ", file, line, func); va_start (args, fmt); cherokee_buffer_add_va_list (&output, (char *)fmt, args); va_end (args); if (use_syslog) { syslog (LOG_DEBUG, "%s", output.buf); } else { #ifdef HAVE_FLOCKFILE flockfile (stdout); #endif fprintf (stdout, "%s", output.buf); #ifdef HAVE_FUNLOCKFILE funlockfile (stdout); #endif } out: cherokee_buffer_mrproper (&output); cherokee_buffer_mrproper (&entries); } #endif ret_t cherokee_short_path (cherokee_buffer_t *path) { char *p = path->buf; char *end = path->buf + path->len; while (p < end) { char *dots_end; char *prev_slash; cuint_t len; if (p[0] != '.') { p++; continue; } if ((p[1] == '/') && (p > path->buf) && (*(p-1) == '/')) { cherokee_buffer_remove_chunk (path, p - path->buf, 2); p -= 1; continue; } if (end < p+2) { return ret_ok; } if (p[1] != '.') { p+=2; continue; } dots_end = p + 2; while ((dots_end < end) && (*dots_end == '.')) { dots_end++; } if (dots_end >= end) return ret_ok; prev_slash = p-1; if (prev_slash < path->buf) return ret_ok; if (*prev_slash != '/') { p = dots_end; continue; } if (prev_slash > path->buf) prev_slash--; while ((prev_slash > path->buf) && (*prev_slash != '/')) { prev_slash--; } len = dots_end - prev_slash; cherokee_buffer_remove_chunk (path, (prev_slash - path->buf), len); end = path->buf + path->len; p -= (len - (dots_end - p)); } return ret_ok; } long * cherokee_get_timezone_ref (void) { #ifdef HAVE_INT_TIMEZONE return &timezone; #else static long _faked_timezone = 0; return &_faked_timezone; #endif } ret_t cherokee_parse_query_string (cherokee_buffer_t *qstring, cherokee_avl_t *arguments) { char *string; char *token; if (cherokee_buffer_is_empty (qstring)) return ret_ok; string = qstring->buf; while ((token = (char *) strsep(&string, "&")) != NULL) { char *equ, *key, *val; if (*token == '\0') continue; if ((equ = strchr(token, '=')) != NULL) { *equ = '\0'; key = token; val = equ+1; cherokee_avl_add_ptr (arguments, key, strdup(val)); *equ = '='; } else { cherokee_avl_add_ptr (arguments, token, NULL); } /* UGLY hack, part 1: * It restore the string modified by the strtok() function */ token[strlen(token)] = '&'; } /* UGLY hack, part 2: */ qstring->buf[qstring->len] = '\0'; return ret_ok; } #if defined(HAVE_PTHREAD) && !defined(HAVE_GETPWNAM_R) static pthread_mutex_t __global_getpwnam_mutex = PTHREAD_MUTEX_INITIALIZER; #endif ret_t cherokee_getpwnam (const char *name, struct passwd *pwbuf, char *buf, size_t buflen) { #ifndef HAVE_GETPWNAM_R size_t pw_name_len = 0; size_t pw_passwd_len = 0; size_t pw_gecos_len = 0; size_t pw_dir_len = 0; size_t pw_shell_len = 0; char *ptr; struct passwd *tmp; CHEROKEE_MUTEX_LOCK (&__global_getpwnam_mutex); tmp = getpwnam (name); if (tmp == NULL) { CHEROKEE_MUTEX_UNLOCK (&__global_getpwnam_mutex); return ret_error; } if (tmp->pw_name) pw_name_len = strlen(tmp->pw_name); if (tmp->pw_passwd) pw_passwd_len = strlen(tmp->pw_passwd); if (tmp->pw_gecos) pw_gecos_len = strlen(tmp->pw_gecos); if (tmp->pw_dir) pw_dir_len = strlen(tmp->pw_dir); if (tmp->pw_shell) pw_shell_len = strlen(tmp->pw_shell); if ((pw_name_len + pw_passwd_len + pw_gecos_len + pw_dir_len + pw_shell_len + 5) >= buflen) { /* Buffer overflow. */ CHEROKEE_MUTEX_UNLOCK (&__global_getpwnam_mutex); return ret_error; } memset (buf, 0, buflen); ptr = buf; pwbuf->pw_uid = tmp->pw_uid; pwbuf->pw_gid = tmp->pw_gid; if (tmp->pw_dir) { memcpy (ptr, tmp->pw_dir, pw_dir_len); pwbuf->pw_dir = ptr; ptr += pw_dir_len + 1; } if (tmp->pw_passwd) { memcpy (ptr, tmp->pw_passwd, pw_passwd_len); pwbuf->pw_passwd = ptr; ptr += pw_passwd_len + 1; } if (tmp->pw_name) { memcpy (ptr, tmp->pw_name, pw_name_len); pwbuf->pw_name = ptr; ptr += pw_name_len + 1; } if (tmp->pw_gecos) { memcpy (ptr, tmp->pw_gecos, pw_gecos_len); pwbuf->pw_gecos = ptr; ptr += pw_gecos_len + 1; } if (tmp->pw_shell) { memcpy (ptr, tmp->pw_shell, pw_shell_len); pwbuf->pw_shell = ptr; ptr += pw_shell_len + 1; } CHEROKEE_MUTEX_UNLOCK (&__global_getpwnam_mutex); return ret_ok; #elif HAVE_GETPWNAM_R_5 int re; struct passwd *tmp; re = getpwnam_r (name, pwbuf, buf, buflen, &tmp); if (re != 0) return ret_error; return ret_ok; #elif HAVE_GETPWNAM_R_4 struct passwd * result; #ifdef _POSIX_PTHREAD_SEMANTICS int re; re = getpwnam_r (name, pwbuf, buf, buflen, &result); if (re != 0) return ret_error; #else result = getpwnam_r (name, pwbuf, buf, buflen); if (result == NULL) return ret_error; #endif return ret_ok; #endif return ret_no_sys; } #if defined(HAVE_PTHREAD) && !defined(HAVE_GETGRNAM_R) static pthread_mutex_t __global_getgrnam_mutex = PTHREAD_MUTEX_INITIALIZER; #endif ret_t cherokee_getgrnam (const char *name, struct group *grbuf, char *buf, size_t buflen) { #ifndef HAVE_GETGRNAM_R size_t gr_name_len = 0; size_t gr_passwd_len = 0; char *ptr; struct group *tmp; CHEROKEE_MUTEX_LOCK (&__global_getgrnam_mutex); tmp = getgrnam (name); if (tmp == NULL) { CHEROKEE_MUTEX_UNLOCK (&__global_getgrnam_mutex); return ret_error; } if (tmp->gr_name) gr_name_len = strlen(tmp->gr_name); if (tmp->gr_passwd) gr_passwd_len = strlen(tmp->gr_passwd); if ((gr_name_len + gr_passwd_len + 2) >= buflen) { CHEROKEE_MUTEX_UNLOCK (&__global_getgrnam_mutex); return ret_error; } memset (buf, 0, buflen); ptr = buf; grbuf->gr_gid = tmp->gr_gid; if (tmp->gr_name) { memcpy (ptr, tmp->gr_name, gr_name_len); grbuf->gr_name = ptr; ptr += gr_name_len + 1; } if (tmp->gr_passwd) { memcpy (ptr, tmp->gr_passwd, gr_passwd_len); grbuf->gr_passwd = ptr; ptr += gr_passwd_len + 1; } /* TODO: Duplicate char **tmp->gr_mem */ CHEROKEE_MUTEX_UNLOCK (&__global_getgrnam_mutex); return ret_ok; #elif HAVE_GETGRNAM_R_5 int re; struct group *tmp; re = getgrnam_r (name, grbuf, buf, buflen, &tmp); if (re != 0) return ret_error; return ret_ok; #elif HAVE_GETGRNAM_R_4 struct group *result; #ifdef _POSIX_PTHREAD_SEMANTICS int re; re = getgrnam_r (name, grbuf, buf, buflen, &result); if (re != 0) return ret_error; #else result = getgrnam_r (name, grbuf, buf, buflen); if (result == NULL) return ret_error; #endif return ret_ok; #endif return ret_no_sys; } ret_t cherokee_close_fd (cint_t fd) { int re; if (fd < 0) { return ret_error; } #ifdef _WIN32 re = closesocket (fd); #else re = close (fd); #endif TRACE (ENTRIES",close_fd", "fd=%d re=%d\n", fd, re); return (re == 0) ? ret_ok : ret_error; } ret_t cherokee_get_shell (const char **shell, const char **binary) { char *t1, *t2; /* Set the shell path */ #ifdef _WIN32 *shell = getenv("ComSpec"); #else *shell = "/bin/sh"; #endif /* Find the binary */ t1 = strrchr (*shell, '\\'); t2 = strrchr (*shell, '/'); t1 = cherokee_max_str (t1, t2); if (t1 == NULL) return ret_error; *binary = &t1[1]; return ret_ok; } void cherokee_print_errno (int error, char *format, ...) { va_list ap; char *errstr; char err_tmp[ERROR_MAX_BUFSIZE]; cherokee_buffer_t buffer = CHEROKEE_BUF_INIT; cherokee_buffer_add_str (&buffer, "ERROR: "); errstr = cherokee_strerror_r (error, err_tmp, sizeof(err_tmp)); va_start (ap, format); cherokee_buffer_add_va_list (&buffer, format, ap); va_end (ap); cherokee_buffer_add_str (&buffer, "\n"); cherokee_buffer_replace_string (&buffer, "${errno}", 8, errstr, strlen(errstr)); PRINT_MSG_S (buffer.buf); cherokee_buffer_mrproper (&buffer); } ret_t cherokee_mkstemp (cherokee_buffer_t *buffer, int *fd) { int re; #ifdef _WIN32 re = cherokee_win32_mkstemp (buffer); #else re = mkstemp (buffer->buf); #endif if (re < 0) return ret_error; *fd = re; return ret_ok; }