From a3c417c82aeaefe38a1045ca46209f9c766ebe6e Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Fri, 23 Oct 2026 17:20:56 +0300 Subject: [PATCH] Logs: the error of opening a log returned, not passed in errno 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 --- src/conf.c | 5 +++-- src/log.c | 39 ++++++++++++++++++++++++--------------- src/mainconf.c | 5 +++-- src/proxy.h | 2 +- src/sql.c | 2 +- src/structures.h | 4 ++-- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/conf.c b/src/conf.c index 7811d14..2b29750 100644 --- a/src/conf.c +++ b/src/conf.c @@ -384,13 +384,14 @@ static int h_external(int argc, unsigned char ** argv){ static int h_log(int argc, unsigned char ** argv){ struct logger *lg; ROTATION rotation = (argc > 2)? getrotate(*argv[2]) : NONE; + int err = 0; /* 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){ fprintf(stderr, "Unable to open log %.*s: %s, line %d\n", (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; } if(conf->stacksize < lg->type->stacksize) conf->stacksize = lg->type->stacksize; diff --git a/src/log.c b/src/log.c index 4f649dc..47102b2 100644 --- a/src/log.c +++ b/src/log.c @@ -508,19 +508,29 @@ static int matchfile(const unsigned char *selector){ 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){ unsigned char *name; - FILE *fp; - int err; + FILE *fp = NULL; + int err = 0; - if(!(name = malloc(LOGNAMESIZE))) return 21; + if(!(name = malloc(LOGNAMESIZE))) return ENOMEM; dologname(name, lg->selector, NULL, lg->rotation, lg->rotated); - errno = ENAMETOOLONG; - fp = *name? fopen((char *)name, "a") : NULL; - err = errno; + if(!*name) err = ENAMETOOLONG; + else if(!(fp = fopen((char *)name, "a")) && !(err = crterrno())) err = EIO; free(name); - errno = err; - if(!fp) return 1; + if(err) return err; lg->data = fp; return 0; } @@ -671,7 +681,7 @@ void loginit(void){ #ifndef _WIN32 _3proxy_mutex_init(&syslog_mutex); /* 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 } @@ -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 - errno set, if it cannot be opened. A logger found with other parameters - takes the new ones. */ -struct logger *logget(const unsigned char *selector, ROTATION rotation){ + the error in *errp (an errno value) unless it is NULL, if it cannot be + opened. A logger found with other parameters takes the new ones. */ +struct logger *logget(const unsigned char *selector, ROTATION rotation, int *errp){ struct logger *lg; const struct logtype *type; const unsigned char *params; @@ -730,7 +740,7 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){ free(lg); } _3proxy_mutex_unlock(&log_mutex); - errno = ENOMEM; + if(errp) *errp = ENOMEM; return NULL; } memcpy(lg->selector, selector, len); @@ -745,13 +755,12 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){ lg->failtime = lg->rotated; } else if(err){ - err = errno; _3proxy_mutex_unlock(&log_mutex); _3proxy_mutex_destroy(&lg->mutex); if(lg->params) free(lg->params); free(lg->selector); free(lg); - errno = err; + if(errp) *errp = err; return NULL; } lg->refs = 1; diff --git a/src/mainconf.c b/src/mainconf.c index 3dc1ea6..12d365d 100644 --- a/src/mainconf.c +++ b/src/mainconf.c @@ -318,12 +318,13 @@ static int srvprepare(struct srvstart *s, int argc, char **argv){ case 'l': { struct logger *lg; + int err = 0; /* the same log the log command, or another service, 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", - (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; } logput(srv->logger); diff --git a/src/proxy.h b/src/proxy.h index 8acc4a8..08cda2b 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -346,7 +346,7 @@ void logdo(struct clientparam * param, const unsigned char *s); void logerror(const unsigned char *s); void loginit(void); 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 logput(struct logger *lg); void logcommit(struct extparam *c); diff --git a/src/sql.c b/src/sql.c index 4a92e0d..3289a37 100644 --- a/src/sql.c +++ b/src/sql.c @@ -101,7 +101,7 @@ static int odbcmatch(const unsigned char *selector){ /* A data source down is not an error of the configuration: the log connects again later. */ 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; } diff --git a/src/structures.h b/src/structures.h index c932db2..4f40749 100644 --- a/src/structures.h +++ b/src/structures.h @@ -635,8 +635,8 @@ struct hashtable { struct logtype { const char *name; int (*match)(const unsigned char *selector); - /* opens what it writes to, lg->data: 0, an error, or < 0 if it cannot - be reached now but is to be tried again */ + /* opens what it writes to, lg->data: 0, an error (an errno value), or + < 0 if it cannot be reached now but is to be tried again */ int (*init)(struct logger *lg); /* the line for a connection into buf, CLIENTTMPBUFSIZE: its length, -1 for nothing to write; NULL if write() takes the connection itself */