rlm_detail and radrelay concurrence
Michael Chernyakhovsky
magmike at mail.ru
Thu Jun 15 08:40:13 CEST 2006
hello, everyone
i use radrelay
there are errors in log from rlm_detail like
Error: rlm_detail: Couldn't open file /var/log/radius/radacct/detail-relay: Bad file descriptor
while examine rlm_detail.c i found two places in it.
first while open (create if need) detail-file (line 204 rlm_detail.c).
second while do converting the FD to FP (line 243) after aquiring
filelock of detail file.
Bad file description error appear because radrelay
can remove detail file while rad_detail trying to aquire filelock, I
think (line 655 of radrelay.c).
rlm_detail.c:
201: if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT,
202: inst->detailperm)) < 0) {
203: radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
204: buffer, strerror(errno));
205: return RLM_MODULE_FAIL;
206: }
208: /*
209: * If we're not using locking, we'll just pass straight though
210: * the while loop.
211: * If we fail to aquire the filelock in 80 tries (approximately
212: * two seconds) we bail out.
213: */
214: locked = 0;
215: lock_count = 0;
216: do {
....
231: } while (!locked && inst->locking && lock_count < 80);
...
239: /*
240: * Convert the FD to FP. The FD is no longer valid
241: * after this operation.
242: */
243: if ((outfp = fdopen(outfd, "a")) == NULL) {
244: radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
245: buffer, strerror(errno));
246: if (inst->locking) {
247: lseek(outfd, 0L, SEEK_SET);
248: rad_unlockfd(outfd, 0);
249: DEBUG("rlm_detail: Released filelock");
250: }
251: close(outfd);
253: return RLM_MODULE_FAIL;
254: }
radrelay.c:
655: if (detail_move(r_args->detail, work) == 0) {
656: if (debug_flag > 0)
657: fprintf(stderr, "Moving %s to %s\n",
658: r_args->detail, work);
659: /*
660: * rlm_detail might still write
661: * something to <detail>.work if
662: * it opens <detail> before it is
663: * renamed (race condition)
664: */
665: ms_sleep(1000);
666: state = STATE_BACKLOG;
667: }
668: fpos = ftell(fp);
669: fseek(fp, 0L, SEEK_SET);
670: rad_unlockfd(fileno(fp), 0);
671: fseek(fp, fpos, SEEK_SET);
so detail_move can be called by radrelay while rad_detail already
opens detail (line 201) have outfd and try to aquire lock. after radrelay made
rad_unlockfd(fileno(fp), 0) (line 670), rlm_detail try to fdopen (line
243) and will get error.
As workaround we can give to rlm_detail recreate detail...
--- rlm_detail.c-orig 2006-06-15 12:09:43.000000000 +0600
+++ rlm_detail.c 2006-06-15 12:22:49.000000000 +0600
@@ -119,6 +119,7 @@
struct stat st;
int locked;
int lock_count;
+ int opencount=0;
struct timeval tv;
REALM *proxy_realm;
char proxy_buffer[16];
@@ -195,6 +196,8 @@
*p = '/';
} /* else there was no directory delimiter. */
+
+reopen:
/*
* Open & create the file, with the given permissions.
*/
@@ -241,8 +244,9 @@
* after this operation.
*/
if ((outfp = fdopen(outfd, "a")) == NULL) {
- radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
- buffer, strerror(errno));
+ radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s. %s",
+ buffer, strerror(errno),
+ (opencount==0)?"try reopen to create":"return MODULE_FAIL");
if (inst->locking) {
lseek(outfd, 0L, SEEK_SET);
rad_unlockfd(outfd, 0);
@@ -250,7 +254,10 @@
}
close(outfd);
- return RLM_MODULE_FAIL;
+ if (opencount++ == 0)
+ goto reopen;
+ else
+ return RLM_MODULE_FAIL;
}
/*
btw, why to sleep 1000ms on 665 at radrelay.c?
how rlm_detail can write something to detail.work, while file is locked
by radreplay?
Mike.
More information about the Freeradius-Users
mailing list