Logs: the error of opening a log returned, not passed in errno
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

On Windows proxy.h makes errno WSAGetLastError(), which cannot be
assigned, so the Windows build failed, and the error of fopen() would
not have been read there either. A type's init returns the errno value
(the C library's, read with _get_errno() on Windows), and logget() gives
it to its caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-23 17:20:56 +03:00
parent 30e2e34dd6
commit a3c417c82a
6 changed files with 34 additions and 23 deletions

View File

@ -384,13 +384,14 @@ static int h_external(int argc, unsigned char ** argv){
static int h_log(int argc, unsigned char ** argv){ static int h_log(int argc, unsigned char ** argv){
struct logger *lg; struct logger *lg;
ROTATION rotation = (argc > 2)? getrotate(*argv[2]) : NONE; ROTATION rotation = (argc > 2)? getrotate(*argv[2]) : NONE;
int err = 0;
/* the same log as before is not opened again */ /* the same log as before is not opened again */
lg = logget((argc > 1)? argv[1] : (unsigned char *)"", rotation); lg = logget((argc > 1)? argv[1] : (unsigned char *)"", rotation, &err);
if(!lg){ if(!lg){
fprintf(stderr, "Unable to open log %.*s: %s, line %d\n", fprintf(stderr, "Unable to open log %.*s: %s, line %d\n",
(int)logselen((argc > 1)? argv[1] : (unsigned char *)""), (int)logselen((argc > 1)? argv[1] : (unsigned char *)""),
(argc > 1)? (char *)argv[1] : "", strerror(errno), linenum); (argc > 1)? (char *)argv[1] : "", strerror(err), linenum);
return 1; return 1;
} }
if(conf->stacksize < lg->type->stacksize) conf->stacksize = lg->type->stacksize; if(conf->stacksize < lg->type->stacksize) conf->stacksize = lg->type->stacksize;

View File

@ -508,19 +508,29 @@ static int matchfile(const unsigned char *selector){
return 1; return 1;
} }
/* errno of the C library: on Windows proxy.h makes errno the socket error */
#ifdef _WIN32
static int crterrno(void){
int e = 0;
_get_errno(&e);
return e;
}
#else
#define crterrno() (errno)
#endif
static int fileinit(struct logger *lg){ static int fileinit(struct logger *lg){
unsigned char *name; unsigned char *name;
FILE *fp; FILE *fp = NULL;
int err; int err = 0;
if(!(name = malloc(LOGNAMESIZE))) return 21; if(!(name = malloc(LOGNAMESIZE))) return ENOMEM;
dologname(name, lg->selector, NULL, lg->rotation, lg->rotated); dologname(name, lg->selector, NULL, lg->rotation, lg->rotated);
errno = ENAMETOOLONG; if(!*name) err = ENAMETOOLONG;
fp = *name? fopen((char *)name, "a") : NULL; else if(!(fp = fopen((char *)name, "a")) && !(err = crterrno())) err = EIO;
err = errno;
free(name); free(name);
errno = err; if(err) return err;
if(!fp) return 1;
lg->data = fp; lg->data = fp;
return 0; return 0;
} }
@ -671,7 +681,7 @@ void loginit(void){
#ifndef _WIN32 #ifndef _WIN32
_3proxy_mutex_init(&syslog_mutex); _3proxy_mutex_init(&syslog_mutex);
/* kept for the life of the process, as every syslog logger is */ /* kept for the life of the process, as every syslog logger is */
(void)logget((const unsigned char *)"@3proxy", NONE); (void)logget((const unsigned char *)"@3proxy", NONE, NULL);
#endif #endif
} }
@ -701,9 +711,9 @@ static void logsetparams(struct logger *lg, const unsigned char *params){
} }
/* The logger named so, opened if none is: held until logput(). NULL, with /* The logger named so, opened if none is: held until logput(). NULL, with
errno set, if it cannot be opened. A logger found with other parameters the error in *errp (an errno value) unless it is NULL, if it cannot be
takes the new ones. */ opened. A logger found with other parameters takes the new ones. */
struct logger *logget(const unsigned char *selector, ROTATION rotation){ struct logger *logget(const unsigned char *selector, ROTATION rotation, int *errp){
struct logger *lg; struct logger *lg;
const struct logtype *type; const struct logtype *type;
const unsigned char *params; const unsigned char *params;
@ -730,7 +740,7 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){
free(lg); free(lg);
} }
_3proxy_mutex_unlock(&log_mutex); _3proxy_mutex_unlock(&log_mutex);
errno = ENOMEM; if(errp) *errp = ENOMEM;
return NULL; return NULL;
} }
memcpy(lg->selector, selector, len); memcpy(lg->selector, selector, len);
@ -745,13 +755,12 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){
lg->failtime = lg->rotated; lg->failtime = lg->rotated;
} }
else if(err){ else if(err){
err = errno;
_3proxy_mutex_unlock(&log_mutex); _3proxy_mutex_unlock(&log_mutex);
_3proxy_mutex_destroy(&lg->mutex); _3proxy_mutex_destroy(&lg->mutex);
if(lg->params) free(lg->params); if(lg->params) free(lg->params);
free(lg->selector); free(lg->selector);
free(lg); free(lg);
errno = err; if(errp) *errp = err;
return NULL; return NULL;
} }
lg->refs = 1; lg->refs = 1;

View File

@ -318,12 +318,13 @@ static int srvprepare(struct srvstart *s, int argc, char **argv){
case 'l': case 'l':
{ {
struct logger *lg; struct logger *lg;
int err = 0;
/* the same log the log command, or another service, /* the same log the log command, or another service,
opened is shared with it */ opened is shared with it */
if(!(lg = logget((unsigned char *)argv[i] + 2, NONE))){ if(!(lg = logget((unsigned char *)argv[i] + 2, NONE, &err))){
fprintf(stderr, "Unable to open log %.*s: %s\n", fprintf(stderr, "Unable to open log %.*s: %s\n",
(int)logselen((unsigned char *)argv[i] + 2), argv[i] + 2, strerror(errno)); (int)logselen((unsigned char *)argv[i] + 2), argv[i] + 2, strerror(err));
return 1; return 1;
} }
logput(srv->logger); logput(srv->logger);

View File

@ -346,7 +346,7 @@ void logdo(struct clientparam * param, const unsigned char *s);
void logerror(const unsigned char *s); void logerror(const unsigned char *s);
void loginit(void); void loginit(void);
void logtypeadd(const struct logtype *type); void logtypeadd(const struct logtype *type);
struct logger *logget(const unsigned char *selector, ROTATION rotation); struct logger *logget(const unsigned char *selector, ROTATION rotation, int *errp);
void logref(struct logger *lg); void logref(struct logger *lg);
void logput(struct logger *lg); void logput(struct logger *lg);
void logcommit(struct extparam *c); void logcommit(struct extparam *c);

View File

@ -101,7 +101,7 @@ static int odbcmatch(const unsigned char *selector){
/* A data source down is not an error of the configuration: the log /* A data source down is not an error of the configuration: the log
connects again later. */ connects again later. */
static int odbcinit(struct logger *lg){ static int odbcinit(struct logger *lg){
if(!lg->data && !(lg->data = calloc(1, sizeof(struct logodbc)))) return 21; if(!lg->data && !(lg->data = calloc(1, sizeof(struct logodbc)))) return ENOMEM;
return odbcconnect(lg)? 0 : -1; return odbcconnect(lg)? 0 : -1;
} }

View File

@ -635,8 +635,8 @@ struct hashtable {
struct logtype { struct logtype {
const char *name; const char *name;
int (*match)(const unsigned char *selector); int (*match)(const unsigned char *selector);
/* opens what it writes to, lg->data: 0, an error, or < 0 if it cannot /* opens what it writes to, lg->data: 0, an error (an errno value), or
be reached now but is to be tried again */ < 0 if it cannot be reached now but is to be tried again */
int (*init)(struct logger *lg); int (*init)(struct logger *lg);
/* the line for a connection into buf, CLIENTTMPBUFSIZE: its length, -1 /* the line for a connection into buf, CLIENTTMPBUFSIZE: its length, -1
for nothing to write; NULL if write() takes the connection itself */ for nothing to write; NULL if write() takes the connection itself */