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