Annotation of src/usr.bin/rdist/message.c, Revision 1.23
1.23 ! guenther 1: /* $OpenBSD: message.c,v 1.22 2015/01/16 06:40:11 deraadt Exp $ */
1.4 deraadt 2:
1.1 dm 3: /*
4: * Copyright (c) 1983 Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.15 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 dm 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.23 ! guenther 32: #include <syslog.h>
1.14 millert 33: #include "defs.h"
1.1 dm 34:
35: /*
36: * Message handling functions for both rdist and rdistd.
37: */
38:
39:
40: #define MSGBUFSIZ 32*1024
41:
42: int debug = 0; /* Debugging level */
43: int nerrs = 0; /* Number of errors */
44:
45: /*
46: * Message Types
47: */
48: MSGTYPE msgtypes[] = {
49: { MT_CHANGE, "change" },
50: { MT_INFO, "info" },
51: { MT_NOTICE, "notice" },
52: { MT_NERROR, "nerror" },
53: { MT_FERROR, "ferror" },
54: { MT_WARNING, "warning" },
55: { MT_VERBOSE, "verbose" },
56: { MT_ALL, "all" },
57: { MT_DEBUG, "debug" },
58: { 0 },
59: };
60:
1.14 millert 61: static void msgsendstdout(MSGFACILITY *, int, int, char *);
62: static void msgsendsyslog(MSGFACILITY *, int, int, char *);
63: static void msgsendfile(MSGFACILITY *, int, int, char *);
64: static void msgsendnotify(MSGFACILITY *, int, int, char *);
1.1 dm 65:
66: /*
67: * Message Facilities
68: */
69: MSGFACILITY msgfacility[] = {
70: { MF_STDOUT, "stdout", msgsendstdout },
71: { MF_FILE, "file", msgsendfile },
72: { MF_SYSLOG, "syslog", msgsendsyslog },
73: { MF_NOTIFY, "notify", msgsendnotify },
74: { 0 },
75: };
76:
1.14 millert 77: static MSGFACILITY *getmsgfac(char *);
78: static MSGTYPE *getmsgtype(char *);
79: static char *setmsgtypes(MSGFACILITY *, char *);
80: static void _message(int, char *);
81: static void _debugmsg(int, char *);
1.19 guenther 82: static void _error(const char *);
83: static void _fatalerr(const char *);
1.14 millert 84:
1.1 dm 85: /*
86: * Print message logging usage message
87: */
1.14 millert 88: void
89: msgprusage(void)
1.1 dm 90: {
1.10 mpech 91: int i, x;
1.1 dm 92:
93: (void) fprintf(stderr, "\nWhere <msgopt> is of form\n");
94: (void) fprintf(stderr,
95: "\t<facility1>=<type1>,<type2>,...:<facility2>=<type1>,<type2>...\n");
96:
97: (void) fprintf(stderr, "Valid <facility> names:");
98:
99: for (i = 0; msgfacility[i].mf_name; ++i)
100: (void) fprintf(stderr, " %s", msgfacility[i].mf_name);
101:
102: (void) fprintf(stderr, "\nValid <type> names:");
103: for (x = 0; msgtypes[x].mt_name; ++x)
104: (void) fprintf(stderr, " %s", msgtypes[x].mt_name);
105:
106: (void) fprintf(stderr, "\n");
107: }
108:
109: /*
110: * Print enabled message logging info
111: */
1.14 millert 112: void
113: msgprconfig(void)
1.1 dm 114: {
1.10 mpech 115: int i, x;
1.1 dm 116: static char buf[MSGBUFSIZ];
117:
118: debugmsg(DM_MISC, "Current message logging config:");
119: for (i = 0; msgfacility[i].mf_name; ++i) {
1.14 millert 120: (void) snprintf(buf, sizeof(buf), " %.*s=",
121: (int)(sizeof(buf) - 7), msgfacility[i].mf_name);
1.1 dm 122: for (x = 0; msgtypes[x].mt_name; ++x)
123: if (IS_ON(msgfacility[i].mf_msgtypes,
124: msgtypes[x].mt_type)) {
125: if (x > 0)
1.14 millert 126: (void) strlcat(buf, ",", sizeof(buf));
1.12 deraadt 127: (void) strlcat(buf, msgtypes[x].mt_name,
1.14 millert 128: sizeof(buf));
1.1 dm 129: }
130: debugmsg(DM_MISC, "%s", buf);
131: }
132:
133: }
134:
135: /*
136: * Get the Message Facility entry "name"
137: */
1.14 millert 138: static MSGFACILITY *
139: getmsgfac(char *name)
1.1 dm 140: {
1.10 mpech 141: int i;
1.1 dm 142:
143: for (i = 0; msgfacility[i].mf_name; ++i)
144: if (strcasecmp(name, msgfacility[i].mf_name) == 0)
145: return(&msgfacility[i]);
146:
1.7 millert 147: return(NULL);
1.1 dm 148: }
149:
150: /*
151: * Get the Message Type entry named "name"
152: */
1.14 millert 153: static MSGTYPE *
154: getmsgtype(char *name)
1.1 dm 155: {
1.10 mpech 156: int i;
1.1 dm 157:
158: for (i = 0; msgtypes[i].mt_name; ++i)
159: if (strcasecmp(name, msgtypes[i].mt_name) == 0)
160: return(&msgtypes[i]);
161:
1.7 millert 162: return(NULL);
1.1 dm 163: }
164:
165: /*
166: * Set Message Type information for Message Facility "msgfac" as
167: * indicated by string "str".
168: */
1.14 millert 169: static char *
170: setmsgtypes(MSGFACILITY *msgfac, char *str)
1.1 dm 171: {
172: static char ebuf[BUFSIZ];
1.10 mpech 173: char *cp;
174: char *strptr, *word;
175: MSGTYPE *mtp;
1.1 dm 176:
177: /*
178: * MF_SYSLOG is the only supported message facility for the server
179: */
180: if (isserver && (msgfac->mf_msgfac != MF_SYSLOG &&
181: msgfac->mf_msgfac != MF_FILE)) {
1.5 millert 182: (void) snprintf(ebuf, sizeof(ebuf),
1.14 millert 183: "The \"%.*s\" message facility cannot be used by the server.",
184: 100, msgfac->mf_name);
1.1 dm 185: return(ebuf);
186: }
187:
188: strptr = str;
189:
190: /*
191: * Do any necessary Message Facility preparation
192: */
193: switch(msgfac->mf_msgfac) {
194: case MF_FILE:
195: /*
196: * The MF_FILE string should look like "<file>=<types>".
197: */
198: if ((cp = strchr(strptr, '=')) == NULL)
199: return(
200: "No file name found for \"file\" message facility");
201: *cp++ = CNULL;
202:
203: if ((msgfac->mf_fptr = fopen(strptr, "w")) == NULL)
204: fatalerr("Cannot open log file for writing: %s: %s.",
205: strptr, SYSERR);
1.8 millert 206: msgfac->mf_filename = xstrdup(strptr);
1.1 dm 207:
208: strptr = cp;
209: break;
210:
211: case MF_NOTIFY:
212: break;
213:
214: case MF_STDOUT:
215: msgfac->mf_fptr = stdout;
216: break;
217:
218: case MF_SYSLOG:
219: #if defined(LOG_OPTS)
220: #if defined(LOG_FACILITY)
221: openlog(progname, LOG_OPTS, LOG_FACILITY);
222: #else
223: openlog(progname, LOG_OPTS);
224: #endif /* LOG_FACILITY */
225: #endif /* LOG_OPTS */
226: break;
227: }
228:
229: /*
230: * Parse each type word
231: */
232: msgfac->mf_msgtypes = 0; /* Start from scratch */
233: while (strptr) {
234: word = strptr;
1.14 millert 235: if ((cp = strchr(strptr, ',')) != NULL)
1.1 dm 236: *cp++ = CNULL;
237: strptr = cp;
238:
1.14 millert 239: if ((mtp = getmsgtype(word)) != NULL) {
1.1 dm 240: msgfac->mf_msgtypes |= mtp->mt_type;
241: /*
242: * XXX This is really a kludge until we add real
243: * control over debugging.
244: */
245: if (!debug && isserver &&
246: strcasecmp(word, "debug") == 0)
247: debug = DM_ALL;
248: } else {
1.5 millert 249: (void) snprintf(ebuf, sizeof(ebuf),
1.14 millert 250: "Message type \"%.*s\" is invalid.",
251: 100, word);
1.1 dm 252: return(ebuf);
253: }
254: }
255:
1.7 millert 256: return(NULL);
1.1 dm 257: }
258:
259: /*
260: * Parse a message logging option string
261: */
1.14 millert 262: char *
263: msgparseopts(char *msgstr, int doset)
1.1 dm 264: {
265: static char ebuf[BUFSIZ], msgbuf[MSGBUFSIZ];
1.10 mpech 266: char *cp, *optstr;
267: char *word;
1.1 dm 268: MSGFACILITY *msgfac;
269:
270: if (msgstr == NULL)
271: return("NULL message string");
272:
273: /* strtok() is harmful */
1.14 millert 274: (void) strlcpy(msgbuf, msgstr, sizeof(msgbuf));
1.1 dm 275:
276: /*
1.9 provos 277: * Each <facility>=<types> list is separated by ":".
1.1 dm 278: */
279: for (optstr = strtok(msgbuf, ":"); optstr;
1.7 millert 280: optstr = strtok(NULL, ":")) {
1.1 dm 281:
282: if ((cp = strchr(optstr, '=')) == NULL)
283: return("No '=' found");
284:
285: *cp++ = CNULL;
286: word = optstr;
287: if ((int)strlen(word) <= 0)
288: return("No message facility specified");
289: if ((int)strlen(cp) <= 0)
290: return("No message type specified");
291:
292: if ((msgfac = getmsgfac(word)) == NULL) {
1.5 millert 293: (void) snprintf(ebuf, sizeof(ebuf),
1.14 millert 294: "%.*s is not a valid message facility",
295: 100, word);
1.1 dm 296: return(ebuf);
297: }
298:
299: if (doset) {
300: char *mcp;
301:
1.14 millert 302: if ((mcp = setmsgtypes(msgfac, cp)) != NULL)
1.1 dm 303: return(mcp);
304: }
305: }
306:
307: if (isserver && debug) {
308: debugmsg(DM_MISC, "%s", getversion());
309: msgprconfig();
310: }
311:
1.7 millert 312: return(NULL);
1.1 dm 313: }
314:
315: /*
316: * Send a message to facility "stdout".
317: * For rdistd, this is really the rdist client.
318: */
1.14 millert 319: static void
320: msgsendstdout(MSGFACILITY *msgfac, int mtype, int flags, char *msgbuf)
1.1 dm 321: {
322: char cmd;
323:
324: if (isserver) {
325: if (rem_w < 0 || IS_ON(flags, MT_NOREMOTE))
326: return;
327:
328: cmd = CNULL;
329:
330: switch(mtype) {
331: case MT_NERROR: cmd = C_ERRMSG; break;
332: case MT_FERROR: cmd = C_FERRMSG; break;
333: case MT_NOTICE: cmd = C_NOTEMSG; break;
334: case MT_REMOTE: cmd = C_LOGMSG; break;
335: }
336:
337: if (cmd != CNULL)
338: (void) sendcmd(cmd, "%s", msgbuf);
339: } else {
340: switch(mtype) {
341: case MT_FERROR:
342: case MT_NERROR:
343: if (msgbuf && *msgbuf) {
344: (void) fprintf(stderr, "%s\n", msgbuf);
345: (void) fflush(stderr);
346: }
347: break;
348:
349: case MT_DEBUG:
350: /*
351: * Only things that are strictly MT_DEBUG should
352: * be shown.
353: */
354: if (flags != MT_DEBUG)
355: return;
356: case MT_NOTICE:
357: case MT_CHANGE:
358: case MT_INFO:
359: case MT_VERBOSE:
360: case MT_WARNING:
361: if (msgbuf && *msgbuf) {
362: (void) printf("%s\n", msgbuf);
363: (void) fflush(stdout);
364: }
365: break;
366: }
367: }
368: }
369:
370: /*
371: * Send a message to facility "syslog"
372: */
1.14 millert 373: static void
374: msgsendsyslog(MSGFACILITY *msgfac, int mtype, int flags, char *msgbuf)
1.1 dm 375: {
376: int syslvl = 0;
377:
378: if (!msgbuf || !*msgbuf)
379: return;
380:
381: switch(mtype) {
382: #if defined(SL_NERROR)
383: case MT_NERROR: syslvl = SL_NERROR; break;
384: #endif
385: #if defined(SL_FERROR)
386: case MT_FERROR: syslvl = SL_FERROR; break;
387: #endif
388: #if defined(SL_WARNING)
389: case MT_WARNING: syslvl = SL_WARNING; break;
390: #endif
391: #if defined(SL_CHANGE)
392: case MT_CHANGE: syslvl = SL_CHANGE; break;
393: #endif
394: #if defined(SL_INFO)
395: case MT_SYSLOG:
396: case MT_VERBOSE:
397: case MT_INFO: syslvl = SL_INFO; break;
398: #endif
399: #if defined(SL_NOTICE)
400: case MT_NOTICE: syslvl = SL_NOTICE; break;
401: #endif
402: #if defined(SL_DEBUG)
403: case MT_DEBUG: syslvl = SL_DEBUG; break;
404: #endif
405: }
406:
407: if (syslvl)
408: syslog(syslvl, "%s", msgbuf);
409: }
410:
411: /*
412: * Send a message to a "file" facility.
413: */
1.14 millert 414: static void
415: msgsendfile(MSGFACILITY *msgfac, int mtype, int flags, char *msgbuf)
1.1 dm 416: {
417: if (msgfac->mf_fptr == NULL)
418: return;
419:
420: if (!msgbuf || !*msgbuf)
421: return;
422:
423: (void) fprintf(msgfac->mf_fptr, "%s\n", msgbuf);
424: (void) fflush(msgfac->mf_fptr);
425: }
426:
427: /*
428: * Same method as msgsendfile()
429: */
1.14 millert 430: static void
431: msgsendnotify(MSGFACILITY *msgfac, int mtype, int flags, char *msgbuf)
1.1 dm 432: {
1.13 millert 433: char *tempfile;
434:
1.1 dm 435: if (IS_ON(flags, MT_DEBUG))
436: return;
437:
438: if (!msgbuf || !*msgbuf)
439: return;
440:
441: if (!msgfac->mf_fptr) {
1.10 mpech 442: char *cp;
1.7 millert 443: int fd;
1.11 deraadt 444: size_t len;
1.1 dm 445:
446: /*
447: * Create and open a new temporary file
448: */
1.14 millert 449: if ((cp = getenv("TMPDIR")) == NULL || *cp == '\0')
1.1 dm 450: cp = _PATH_TMP;
1.13 millert 451: len = strlen(cp) + 1 + sizeof(_RDIST_TMP);
1.20 guenther 452: tempfile = xmalloc(len);
1.11 deraadt 453: (void) snprintf(tempfile, len, "%s/%s", cp, _RDIST_TMP);
1.1 dm 454:
455: msgfac->mf_filename = tempfile;
1.14 millert 456: if ((fd = mkstemp(msgfac->mf_filename)) < 0 ||
457: (msgfac->mf_fptr = fdopen(fd, "w")) == NULL)
458: fatalerr("Cannot open notify file for writing: %s: %s.",
459: msgfac->mf_filename, SYSERR);
1.1 dm 460: debugmsg(DM_MISC, "Created notify temp file '%s'",
461: msgfac->mf_filename);
462: }
463:
464: if (msgfac->mf_fptr == NULL)
465: return;
466:
467: (void) fprintf(msgfac->mf_fptr, "%s\n", msgbuf);
468: (void) fflush(msgfac->mf_fptr);
469: }
470:
471: /*
472: * Insure currenthost is set to something reasonable.
473: */
1.14 millert 474: void
475: checkhostname(void)
1.1 dm 476: {
1.22 deraadt 477: static char mbuf[HOST_NAME_MAX+1];
1.1 dm 478: char *cp;
479:
480: if (!currenthost) {
481: if (gethostname(mbuf, sizeof(mbuf)) == 0) {
482: if ((cp = strchr(mbuf, '.')) != NULL)
483: *cp = CNULL;
1.8 millert 484: currenthost = xstrdup(mbuf);
1.1 dm 485: } else
486: currenthost = "(unknown)";
487: }
488: }
489:
490: /*
491: * Print a message contained in "msgbuf" if a level "lvl" is set.
492: */
1.14 millert 493: static void
494: _message(int flags, char *msgbuf)
1.1 dm 495: {
1.10 mpech 496: int i, x;
1.1 dm 497: static char mbuf[2048];
498:
499: if (msgbuf && *msgbuf) {
500: /*
501: * Ensure no stray newlines are present
502: */
1.16 gilles 503: msgbuf[strcspn(msgbuf, "\n")] = CNULL;
1.1 dm 504:
505: checkhostname();
506: if (strncmp(currenthost, msgbuf, strlen(currenthost)) == 0)
1.14 millert 507: (void) strlcpy(mbuf, msgbuf, sizeof(mbuf));
1.1 dm 508: else
1.14 millert 509: (void) snprintf(mbuf, sizeof(mbuf),
510: "%s: %s", currenthost, msgbuf);
1.1 dm 511: } else
1.14 millert 512: mbuf[0] = '\0';
1.1 dm 513:
514: /*
515: * Special case for messages that only get
516: * logged to the system log facility
517: */
518: if (IS_ON(flags, MT_SYSLOG)) {
1.7 millert 519: msgsendsyslog(NULL, MT_SYSLOG, flags, mbuf);
1.1 dm 520: return;
521: }
522:
523: /*
524: * Special cases
525: */
1.5 millert 526: if (isserver && IS_ON(flags, MT_NOTICE)) {
1.7 millert 527: msgsendstdout(NULL, MT_NOTICE, flags, mbuf);
1.5 millert 528: return;
529: } else if (isserver && IS_ON(flags, MT_REMOTE))
1.7 millert 530: msgsendstdout(NULL, MT_REMOTE, flags, mbuf);
1.1 dm 531: else if (isserver && IS_ON(flags, MT_NERROR))
1.7 millert 532: msgsendstdout(NULL, MT_NERROR, flags, mbuf);
1.1 dm 533: else if (isserver && IS_ON(flags, MT_FERROR))
1.7 millert 534: msgsendstdout(NULL, MT_FERROR, flags, mbuf);
1.1 dm 535:
536: /*
537: * For each Message Facility, check each Message Type to see
538: * if the bits in "flags" are set. If so, call the appropriate
539: * Message Facility to dispatch the message.
540: */
541: for (i = 0; msgfacility[i].mf_name; ++i)
542: for (x = 0; msgtypes[x].mt_name; ++x)
543: /*
544: * XXX MT_ALL should not be used directly
545: */
546: if (msgtypes[x].mt_type != MT_ALL &&
547: IS_ON(flags, msgtypes[x].mt_type) &&
548: IS_ON(msgfacility[i].mf_msgtypes,
549: msgtypes[x].mt_type))
550: (*msgfacility[i].mf_sendfunc)(&msgfacility[i],
551: msgtypes[x].mt_type,
552: flags,
553: mbuf);
554: }
555:
556: /*
1.21 guenther 557: * Front-end to _message()
1.1 dm 558: */
1.14 millert 559: void
1.19 guenther 560: message(int lvl, const char *fmt, ...)
1.1 dm 561: {
562: static char buf[MSGBUFSIZ];
563: va_list args;
564:
565: va_start(args, fmt);
1.14 millert 566: (void) vsnprintf(buf, sizeof(buf), fmt, args);
1.1 dm 567: va_end(args);
568:
569: _message(lvl, buf);
570: }
571:
572: /*
573: * Display a debugging message
574: */
1.14 millert 575: static void
576: _debugmsg(int lvl, char *buf)
1.1 dm 577: {
578: if (IS_ON(debug, lvl))
579: _message(MT_DEBUG, buf);
580: }
581:
582: /*
1.21 guenther 583: * Front-end to _debugmsg()
1.1 dm 584: */
1.14 millert 585: void
1.19 guenther 586: debugmsg(int lvl, const char *fmt, ...)
1.1 dm 587: {
588: static char buf[MSGBUFSIZ];
589: va_list args;
590:
591: va_start(args, fmt);
1.14 millert 592: (void) vsnprintf(buf, sizeof(buf), fmt, args);
1.1 dm 593: va_end(args);
594:
595: _debugmsg(lvl, buf);
596: }
597:
598: /*
599: * Print an error message
600: */
1.14 millert 601: static void
1.19 guenther 602: _error(const char *msg)
1.1 dm 603: {
604: static char buf[MSGBUFSIZ];
605:
606: nerrs++;
607: buf[0] = CNULL;
608:
609: if (msg) {
610: if (isserver)
1.14 millert 611: (void) snprintf(buf, sizeof(buf),
612: "REMOTE ERROR: %s", msg);
1.1 dm 613: else
1.14 millert 614: (void) snprintf(buf, sizeof(buf),
615: "LOCAL ERROR: %s", msg);
1.1 dm 616: }
617:
618: _message(MT_NERROR, (buf[0]) ? buf : NULL);
619: }
620:
621: /*
1.21 guenther 622: * Frontend to _error()
1.1 dm 623: */
1.14 millert 624: void
1.19 guenther 625: error(const char *fmt, ...)
1.1 dm 626: {
627: static char buf[MSGBUFSIZ];
628: va_list args;
629:
630: buf[0] = CNULL;
631: va_start(args, fmt);
632: if (fmt)
1.14 millert 633: (void) vsnprintf(buf, sizeof(buf), fmt, args);
1.1 dm 634: va_end(args);
635:
636: _error((buf[0]) ? buf : NULL);
637: }
638:
639: /*
640: * Display a fatal message
641: */
1.14 millert 642: static void
1.19 guenther 643: _fatalerr(const char *msg)
1.1 dm 644: {
645: static char buf[MSGBUFSIZ];
646:
647: ++nerrs;
648:
649: if (isserver)
1.14 millert 650: (void) snprintf(buf, sizeof(buf), "REMOTE ERROR: %s", msg);
1.1 dm 651: else
1.14 millert 652: (void) snprintf(buf, sizeof(buf), "LOCAL ERROR: %s", msg);
1.1 dm 653:
654: _message(MT_FERROR, buf);
655:
656: exit(nerrs);
657: }
658:
659: /*
1.21 guenther 660: * Front-end to _fatalerr()
1.1 dm 661: */
1.14 millert 662: void
1.19 guenther 663: fatalerr(const char *fmt, ...)
1.1 dm 664: {
665: static char buf[MSGBUFSIZ];
666: va_list args;
667:
668: va_start(args, fmt);
1.14 millert 669: (void) vsnprintf(buf, sizeof(buf), fmt, args);
1.1 dm 670: va_end(args);
671:
672: _fatalerr(buf);
673: }
674:
675: /*
676: * Get the name of the file used for notify.
677: * A side effect is that the file pointer to the file
678: * is closed. We assume this function is only called when
679: * we are ready to read the file.
680: */
1.14 millert 681: char *
682: getnotifyfile(void)
1.1 dm 683: {
1.10 mpech 684: int i;
1.1 dm 685:
686: for (i = 0; msgfacility[i].mf_name; i++)
687: if (msgfacility[i].mf_msgfac == MF_NOTIFY &&
688: msgfacility[i].mf_fptr) {
689: (void) fclose(msgfacility[i].mf_fptr);
690: msgfacility[i].mf_fptr = NULL;
691: return(msgfacility[i].mf_filename);
692: }
693:
1.7 millert 694: return(NULL);
1.1 dm 695: }