|
|
1.1 root 1: /*
2: * This software is Copyright (c) 1986 by Rick Adams.
3: *
4: * Permission is hereby granted to copy, reproduce, redistribute or
5: * otherwise use this software as long as: there is no monetary
6: * profit gained specifically from the use or reproduction or this
7: * software, it is not sold, rented, traded or otherwise marketed, and
8: * this copyright notice is included prominently in any copy
9: * made.
10: *
11: * The author make no claims as to the fitness or correctness of
12: * this software for any use whatsoever, and it is provided as is.
13: * Any use of this software is at the user's own risk.
14: *
15: * inews - insert, receive, and transmit news articles.
16: *
17: */
18:
19: #ifdef SCCSID
20: static char *SccsId = "@(#)inews.c 2.82 10/15/87";
21: #endif /* SCCSID */
22:
23: #include "iparams.h"
24:
25: # ifdef LOCKF
26: # include <unistd.h>
27: # include <fcntl.h>
28:
29: # if defined(F_RDLCK) && defined(F_SETLK)
30: struct flock news_lock;
31: # endif /* F_RDLCK && F_SETLK */
32: # endif /* LOCKF */
33:
34: #ifdef BSD4_2
35: # include <sys/file.h>
36: #else /* !BSD4_2 */
37: # if defined(USG) && !defined(LOCKF)
38: # include <fcntl.h>
39: # endif /* USG */
40: #endif /* !BSD4_2 */
41: /* local defines for inews */
42:
43: #define OPTION 0 /* pick up an option string */
44: #define STRING 1 /* pick up a string of arguments */
45:
46: #define UNKNOWN 0001 /* possible modes for news program */
47: #define UNPROC 0002 /* Unprocessed input */
48: #define PROC 0004 /* Processed input */
49: #define CONTROL 0010 /* Control Message */
50: #define CREATENG 0020 /* Create a new newsgroup */
51:
52: #define DONT_SPOOL 0
53: #define DO_SPOOL 1
54: #define EXPIRE_RUNNING 2
55: int spool_news = DONT_SPOOL;
56:
57: extern char histline[];
58: char forgedname[NAMELEN]; /* A user specified -f option. */
59: /* Fake sys line in case they forget their own system */
60: struct srec dummy_srec = { "MEMEME", "", "all", "", "" };
61:
62: char *Progname = "inews"; /* used by xerror to identify failing program */
63:
64: struct { /* options table. */
65: char optlet; /* option character. */
66: char filchar; /* if to pickup string, fill character. */
67: int flag; /* TRUE if have seen this opt. */
68: int oldmode; /* OR of legal input modes. */
69: int newmode; /* output mode. */
70: char *buf; /* string buffer */
71: } *optpt, options[] = { /*
72: optlet filchar flag oldmode newmode buf */
73: 't', ' ', FALSE, UNPROC, UNKNOWN, header.title,
74: 'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf,
75: 'd', '\0', FALSE, UNPROC, UNKNOWN, header.distribution,
76: 'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate,
77: 'p', '\0', FALSE, UNKNOWN|PROC, PROC, filename,
78: 'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname,
79: 'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid,
80: 'c', ' ', FALSE, UNKNOWN,UNKNOWN, header.ctlmsg,
81: 'C', ' ', FALSE, UNKNOWN,CREATENG, header.ctlmsg,
82: #define hflag options[9].flag
83: 'h', '\0', FALSE, UNPROC, UNKNOWN, filename,
84: #define oflag options[10].flag
85: 'o', '\0', FALSE, UNPROC, UNKNOWN, header.organization,
86: #define Mflag options[11].flag
87: 'M', '\0', FALSE, UNPROC, UNKNOWN, filename,
88: 'a', '\0', FALSE, UNPROC, UNKNOWN, header.approved,
89: 'U', '\0', FALSE, PROC, PROC, filename,
90: #define Sflag options[14].flag
91: 'S', '\0', FALSE, UNKNOWN|PROC, UNPROC, filename,
92: 'x', '\0', FALSE, UNPROC, UNKNOWN, not_here,
93: 'r', '\0', FALSE, UNPROC, UNKNOWN, header.replyto,
94: '\0', '\0', 0, 0, 0, (char *)NULL
95: };
96:
97: FILE *mailhdr();
98: extern int errno;
99:
100: struct timeb Now;
101:
102: /*
103: * Authors:
104: * Matt Glickman [email protected]
105: * Mark Horton [email protected]
106: * Stephen Daniels [email protected]
107: * Tom Truscott [email protected]
108: * Rick Adams [email protected]
109: * IHCC version adapted by:
110: * Larry Marek [email protected]
111: */
112: main(argc, argv)
113: int argc;
114: register char **argv;
115: {
116: int state; /* which type of argument to pick up */
117: int tlen, len; /* temps for string processing routine */
118: register char *ptr; /* pointer to rest of buffer */
119: int filchar; /* fill character (state = STRING) */
120: char *user = NULL, *home = NULL; /* environment temps */
121: struct passwd *pw; /* struct for pw lookup */
122: struct group *gp; /* struct for group lookup */
123: register int i;
124: FILE *mfd; /* mail file file-descriptor */
125:
126: /* uuxqt doesn't close all its files */
127: for (i = 3; !close(i); i++)
128: ;
129: /* set up defaults and initialize. */
130: mode = UNKNOWN;
131: infp = stdin;
132: pathinit();
133: savmask = umask(N_UMASK); /* set up mask */
134: ptr = rindex(*argv, '/');
135: if (!ptr)
136: ptr = *argv - 1;
137: actfp = xfopen(ACTIVE, "r+");
138: #ifdef LOCKF
139: # if defined(F_RDLCK) && defined(F_SETLK)
140: news_lock.l_type = F_RDLCK;
141: if (fcntl(fileno(actfp), F_SETLK, &news_lock) < 0) {
142: # else /* !F_RDLCK */
143: if (lockf(fileno(actfp), F_TLOCK, 0L) < 0) {
144: # endif /* !F_RDLCK */
145: if (errno != EAGAIN && errno != EACCES)
146: #else /* !LOCKF */
147: #ifdef BSD4_2
148: if (flock(fileno(actfp), LOCK_SH|LOCK_NB) < 0) {
149: if (errno != EWOULDBLOCK)
150: #else /* !BSD4_2 */
151: sprintf(bfr, "%s.lock", ACTIVE);
152: if (LINK(ACTIVE, bfr) < 0) {
153: if (errno != EEXIST)
154: #endif /* V7 */
155: #endif /* !BSD4_2 */
156: xerror("Can't lock %s: %s", ACTIVE, errmsg(errno));
157: spool_news = EXPIRE_RUNNING;
158: } else {
159: #ifdef SPOOLNEWS
160: if (argc > 1 && !strcmp(*(argv+1), "-S")) {
161: argc--;
162: argv++;
163: Sflag = 1;
164: } else
165: spool_news = DO_SPOOL;
166:
167: #endif /* SPOOLNEWS */
168: }
169: if (spool_news != EXPIRE_RUNNING) {
170: /* only unlock if we locked */
171: #ifdef LOCKF
172: (void) lockf(fileno(actfp), F_ULOCK, 0L);
173: #else /* !LOCKF */
174: #ifdef BSD4_2
175: (void) flock(fileno(actfp), LOCK_UN);
176: #else /* !BSD4_2 */
177: (void) UNLINK(bfr);
178: #endif /* V7 */
179: #endif /* !BSD4_2 */
180: } else { /* expire is running */
181: if (argc > 1 && !strcmp(*(argv+1), "-S"))
182: exit(42); /* inform rnews -U by exit status */
183: }
184: if (argc > 1 && !strcmp(*(argv+1), "-U")) {
185: /* can't unspool while things are locked */
186: if (spool_news == EXPIRE_RUNNING)
187: xxit(0);
188: dounspool();
189: /* NOT REACHED */
190: }
191:
192: if (!STRNCMP(ptr+1, "rnews", 5)) {
193: mode = PROC;
194: if (spool_news != DONT_SPOOL) {
195: dospool((char *)NULL, FALSE);
196: /* NOT REACHED */
197: }
198: #ifdef NICENESS
199: if (nice(0) < NICENESS)
200: (void) nice(NICENESS);
201: #endif /* NICENESS */
202: } else {
203: /* it's not rnews, so it must be inews */
204: if (argc < 2)
205: goto usage;
206: #ifndef SPOOLINEWS
207: if (spool_news == DO_SPOOL)
208: spool_news = DONT_SPOOL;
209: #endif /* SPOOLINEWS */
210: }
211:
212: state = OPTION;
213: header.title[0] = header.nbuf[0] = filename[0] = '\0';
214:
215: /* check for existence of special files */
216: #ifdef DBM
217: chkfile(ARTFILE);
218: #else
219: chkdir(ARTFILE);
220: #endif /* DBM */
221: chkfile(ACTIVE);
222: SigTrap = FALSE; /* true if a signal has been caught */
223: if (mode != PROC) {
224: (void) signal(SIGHUP, onsig);
225: (void) signal(SIGINT, onsig);
226: }
227: /*
228: * Catch "filesize exceeded" signals on 4.2BSD systems
229: * - the history files may exceed this limit.
230: */
231: #ifdef SIGXFSZ
232: (void) signal(SIGXFSZ, SIG_IGN);
233: #endif /* SIGXFSZ */
234: uid = getuid();
235: gid = getgid();
236: duid = geteuid();
237: dgid = getegid();
238: (void) ftime(&Now);
239: if (uid == 0 && duid == 0) {
240: /*
241: * Must go through with this kludge since
242: * some systems do not honor the setuid bit
243: * when root invokes a setuid program.
244: */
245: if ((pw = getpwnam(NEWSUSR)) == NULL)
246: xerror("Cannot get NEWSU pw entry");
247:
248: duid = pw->pw_uid;
249: if ((gp = getgrnam(NEWSGRP)) == NULL)
250: xerror("Cannot get NEWSG gr entry");
251: dgid = gp->gr_gid;
252: (void) setgid(dgid);
253: (void) setuid(duid);
254: }
255:
256: #ifndef DOGETUSER
257: /*
258: * Force the use of 'getuser()' to prevent forgery of articles
259: * by just changing $LOGNAME
260: */
261: if (isatty(fileno(stderr))) {
262: if ((user = getenv("USER")) == NULL)
263: user = getenv("LOGNAME");
264: if ((home = getenv("HOME")) == NULL)
265: home = getenv("LOGDIR");
266: }
267: #endif /* !DOGETUSER */
268: if (user == NULL || home == NULL)
269: getuser();
270: else {
271: if (STRCMP(username, "Unknown") == 0 || username[0] == 0) {
272: username = AllocCpy(user);
273: }
274: userhome = AllocCpy(home);
275: }
276: getuser();
277:
278: /* loop once per arg. */
279:
280: ++argv; /* skip first arg, which is prog name. */
281:
282: while (--argc) {
283: if (state == OPTION) {
284: if (**argv != '-') {
285: xerror("Bad option string \"%s\"", *argv);
286: }
287: while (*++*argv != '\0') {
288: for (optpt = options; optpt->optlet != '\0'; ++optpt) {
289: if (optpt->optlet == **argv)
290: goto found;
291: }
292: /* unknown option letter */
293: usage:
294: fprintf(stderr, "usage: inews -t title");
295: fprintf(stderr, " [ -n newsgroups ]");
296: fprintf(stderr, " [ -e expiration date ]\n");
297: fprintf(stderr, "\t[ -f sender]\n\n");
298: xxit(1);
299:
300: found:;
301: if (optpt->flag == TRUE || (mode != UNKNOWN &&
302: (mode&optpt->oldmode) == 0)) {
303: xerror("Bad %c option", **argv);
304: }
305: if (mode == UNKNOWN)
306: mode = optpt->newmode;
307: filchar = optpt->filchar;
308: optpt->flag = TRUE;
309: state = STRING;
310: ptr = optpt->buf;
311: len = BUFLEN;
312: }
313:
314: argv++; /* done with this option arg. */
315:
316: } else {
317:
318: /*
319: * Pick up a piece of a string and put it into
320: * the appropriate buffer.
321: */
322: if (**argv == '-') {
323: state = OPTION;
324: argc++; /* uncount this arg. */
325: continue;
326: }
327:
328: if ((tlen = strlen(*argv)) >= len)
329: xerror("Argument string too long");
330: (void) strcpy(ptr, *argv++);
331: ptr += tlen;
332: if (*(ptr-1) != filchar)
333: *ptr++ = filchar;
334: len -= tlen + 1;
335: *ptr = '\0';
336: }
337: }
338:
339: /*
340: * ALL of the command line has now been processed. (!)
341: */
342:
343: if (*filename) {
344: infp = freopen(filename, "r", stdin);
345: if (infp == NULL)
346: xerror("freopen(%s): %s", filename, errmsg(errno));
347: } else
348: infp = stdin;
349:
350: tty = isatty(fileno(infp));
351:
352: if (mode == CREATENG)
353: createng();
354:
355: if (header.ctlmsg[0] != '\0' && header.title[0] == '\0')
356: (void) strcpy(header.title, header.ctlmsg);
357:
358: if (*header.nbuf) {
359: lcase(header.nbuf);
360: ptr = index(header.nbuf, '\0');
361: if (ptr[-1] == NGDELIM)
362: *--ptr = '\0';
363: }
364: (void) nstrip(header.title);
365: (void) nstrip(header.expdate);
366: (void) nstrip(header.followid);
367: if (mode != PROC) {
368: if (hflag) {
369: header.path[0] = '\0';
370: (void) hread(&header, infp, FALSE);
371: /* there are certain fields we won't let him specify. */
372: if (header.from[0]) {
373: (void) fixfrom(&header);
374: if (Sflag && !Mflag && !header.approved[0] &
375: !header.sender[0]) {
376: register char *p;
377: strcpy(bfr, header.from);
378: p = strpbrk(bfr, "@ !");
379: if (p)
380: *p = '\0';
381: if ((pw = getpwnam(bfr)) != NULL) {
382: uid = pw->pw_uid;
383: gid = pw->pw_gid;
384: username = AllocCpy(bfr);
385: }
386: } else {
387: (void) strcpy(forgedname, header.from);
388: header.from[0] = '\0';
389: }
390: }
391: if (!header.approved[0])
392: Mflag = FALSE;
393: header.sender[0] = '\0';
394: if (header.subdate[0] && cgtdate(header.subdate) < 0)
395: header.subdate[0] = '\0';
396: }
397:
398: if (header.ident[0] == '\0')
399: getident(&header);
400:
401: if (forgedname[0]) {
402: register char *p1;
403: if (Mflag)
404: sprintf(header.path, "%s!%s",
405: PATHSYSNAME, username);
406: else if (!header.path[0]) {
407: (void) strcpy(header.path, forgedname);
408:
409: if ((p1 = strpbrk(header.path, " (<")) != NULL)
410: *p1 = '\0';
411: }
412: if (!Mflag && !strpbrk(forgedname, "@ (<"))
413: (void) sprintf(header.from,"%s@%s",
414: forgedname, FROMSYSNAME);
415: else
416: (void) strncpy(header.from, forgedname, BUFLEN);
417:
418: (void) sprintf(header.sender, "%s@%s",
419: username, FROMSYSNAME);
420: } else {
421: gensender(&header, username);
422: }
423: #ifdef MYORG
424: if (header.organization[0] == '\0' && !Mflag &&
425: header.sender[0] == '\0') {
426: strncpy(header.organization, MYORG, BUFLEN);
427: if (STRNCMP(header.organization, "Frobozz", 7) == 0)
428: header.organization[0] = '\0';
429: if (ptr = getenv("ORGANIZATION"))
430: strncpy(header.organization, ptr, BUFLEN);
431: /*
432: * Note that the organization can also be turned off by
433: * setting it to the null string, either in MYORG or
434: * $ORGANIZATION in the environment.
435: */
436: if (header.organization[0] == '/') {
437: mfd = fopen(header.organization, "r");
438: if (mfd) {
439: (void) fgets(header.organization, sizeof header.organization, mfd);
440: (void) fclose(mfd);
441: } else {
442: logerr("Couldn't open %s",
443: header.organization);
444: header.organization[0] = '\0';
445: }
446: ptr = index(header.organization, '\n');
447: if (ptr)
448: *ptr = '\0';
449: }
450: }
451: #endif /* MYORG */
452: }
453:
454: /* Authorize newsgroups. */
455: if (mode == PROC) {
456: checkbatch();
457: (void) signal(SIGHUP, SIG_IGN);
458: (void) signal(SIGINT, SIG_IGN);
459: (void) signal(SIGQUIT, SIG_IGN);
460: header.ident[0] = '\0';
461: if (hread(&header, infp, TRUE) == NULL)
462: xerror("%s: Inbound news is garbled", filename);
463: input(bfr[0] != '\n');
464: }
465: /* always check history */
466:
467: if (history(&header)) {
468: log("Duplicate article %s rejected. Path: %s",
469: header.ident, header.path);
470: xxit(0);
471: }
472:
473: /* Easy way to make control messages, since all.all.ctl is unblessed */
474: if (mode != PROC && PREFIX(header.title, "cmsg ") && header.ctlmsg[0] == 0)
475: (void) strcpy(header.ctlmsg, &header.title[5]);
476: is_ctl = mode != CREATENG &&
477: (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]);
478: #ifdef DEBUG
479: fprintf(stderr,"is_ctl set to %d\n", is_ctl);
480: #endif
481:
482: if (mode != CREATENG) {
483: if (!*header.title)
484: error("No title, ng %s from %s", header.nbuf,
485: header.from);
486: if (!*header.nbuf)
487: (void) strcpy(header.nbuf, DFLTNG);
488: }
489:
490: if (mode <= UNPROC) {
491: #ifdef FASCIST
492: if (uid && uid != ROOTID && fascist(username, header.nbuf))
493: xerror("User %s is not authorized to post to newsgroup %s",
494: username, header.nbuf);
495: #endif /* FASCIST */
496: ctlcheck();
497: }
498:
499: if (mode == CREATENG)
500: createng();
501:
502: /* Determine input. */
503: if (mode != PROC)
504: input(FALSE);
505: if (header.intnumlines == 0 && !is_ctl)
506: error("%s rejected: no text lines", header.ident);
507:
508: dates(&header);
509:
510: /* Do the actual insertion. */
511: insert();
512: /* NOTREACHED */
513: }
514:
515: /* check for existence of file */
516: static chkfile(f)
517: char *f;
518: {
519: FILE *mfd; /* mail file file-descriptor */
520: char cbuf[BUFLEN]; /* command buffer */
521:
522: if (rwaccess(f))
523: return; /* everything is ok */
524: mfd = mailhdr((struct hbuf *)NULL,
525: exists(f) ? "Unwritable files!" : "Missing files!");
526: if (mfd == NULL)
527: return;
528: putc('\n', mfd);
529: fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n",
530: LOCALSYSNAME, f);
531: (void) sprintf(cbuf, "touch %s;chmod 666 %s", f, f);
532: (void) system(cbuf);
533: if (rwaccess(f))
534: fprintf(mfd, "The problem has been taken care of.\n");
535: else
536: fprintf(mfd, "Corrective action failed - check suid bits.\n");
537: (void) mclose(mfd);
538: }
539:
540: #ifndef DBM
541: /* check for existence of directory */
542: static chkdir(d)
543: char *d;
544: {
545: FILE *mfd; /* mail file file-descriptor */
546: char dir[BUFLEN]; /* holds directory name */
547:
548: sprintf(dir, "%s.d", d);
549: if (eaccess(dir, 07) == 0)
550: return; /* everything is ok */
551: mfd = mailhdr((struct hbuf *)NULL,
552: exists(dir) ? "Unwritable directories" : "Missing directories");
553: if (mfd == NULL)
554: return;
555: putc('\n', mfd);
556: fprintf(mfd, "System: %s\n\nThere was a problem with %s!\n",
557: LOCALSYSNAME, dir);
558: (void) mkdir(dir, 0775);
559: if (eaccess(dir, 07) == 0)
560: fprintf(mfd, "The problem has been taken care of.\n");
561: else
562: fprintf(mfd, "Corrective action failed - check suid bits.\n");
563: (void) mclose(mfd);
564: }
565:
566: /*
567: * This version of access checks against effective uid and effective gid
568: */
569: eaccess(name, mode)
570: register char *name;
571: register int mode;
572: {
573: struct stat statb;
574: int euserid = geteuid();
575: int egroupid = getegid();
576:
577: if (stat(name, &statb) == 0) {
578: if (euserid == 0) {
579: if ((statb.st_mode&S_IFMT) != S_IFREG || mode != 1)
580: return 0;
581: /* root needs execute permission for someone */
582: mode = (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
583: }
584: else if (euserid == statb.st_uid)
585: mode <<= 6;
586: else if (egroupid == statb.st_gid)
587: mode <<= 3;
588: #ifdef BSD4_2
589: /* in BSD4_2 you can be in several groups */
590: else {
591: int groups[NGROUPS];
592: register int n;
593: n = getgroups(NGROUPS,groups);
594: while(--n >= 0) {
595: if(groups[n] == statb.st_gid) {
596: mode <<= 3;
597: break;
598: }
599: }
600: }
601: #endif /* BSD4_2 */
602:
603: if (statb.st_mode & mode)
604: return 0;
605: }
606: return -1;
607: }
608: #endif /* DBM */
609:
610: dospool(batchcmd, dolhwrite)
611: char *batchcmd;
612: int dolhwrite;
613: {
614: register int c;
615: register FILE *sp;
616: register struct tm *tp;
617: time_t t;
618: char buf[BUFLEN], sfile[BUFLEN];
619: extern struct tm *gmtime();
620:
621: (void) sprintf(sfile, "%s/.spXXXXXX", SPOOL);
622: sp = xfopen(mktemp(sfile), "w");
623: if (batchcmd != NULL) {
624: if (not_here[0] != '\0')
625: fprintf(sp, "%s -x %s\n", batchcmd, not_here);
626: else
627: fprintf(sp, "%s\n", batchcmd);
628: } else
629: if (not_here[0] != '\0')
630: fprintf(sp, "#! inews -x %s -p\n", not_here);
631: if (dolhwrite)
632: lhwrite(&header, sp);
633: while ((c = getc(infp)) != EOF)
634: putc(c, sp);
635: fclose(sp);
636:
637: (void) time(&t);
638: tp = gmtime(&t);
639: /* This file name "has to" be unique (right?) */
640: #ifdef USG
641: (void) sprintf(buf, "%s/.rnews/%2.2d%2.2d%2.2d%2.2d%2.2d%x",
642: #else
643: #ifdef VMS
644: /* Eunice doesn't like dots in directory names */
645: (void) sprintf(buf, "%s/+rnews/%02d%02d%02d%02d%02d%x",
646: #else /* V7 */
647: (void) sprintf(buf, "%s/.rnews/%02d%02d%02d%02d%02d%x",
648: #endif /* V7 */
649: #endif /* VMS */
650: SPOOL,
651: tp->tm_year, tp->tm_mon+1, tp->tm_mday,
652: tp->tm_hour, tp->tm_min, getpid());
653:
654: #ifdef IHCC
655: log("Spooling %s into %s", header.ident, (rindex(buf,'/') + 1));
656: #endif /* IHCC */
657:
658: if (LINK(sfile, buf) < 0) {
659: char dbuf[BUFLEN];
660: #ifdef VMS
661: sprintf(dbuf, "%s/+rnews", SPOOL);
662: #else /* !VMS */
663: sprintf(dbuf, "%s/.rnews", SPOOL);
664: #endif /* !VMS */
665: if (mkdir(dbuf, 0777&~N_UMASK) < 0)
666: xerror("Cannot mkdir %s: %s", dbuf, errmsg(errno));
667: if (LINK(sfile, buf) < 0)
668: xerror("Cannot link(%s,%s): %s", sfile, buf,
669: errmsg(errno));
670: }
671: (void) UNLINK(sfile);
672: xxit(0);
673: /* NOTREACHED */
674: }
675:
676: /*
677: * Create a newsgroup
678: */
679: createng()
680: {
681: register char *cp;
682:
683: /*
684: * Only certain users are allowed to create newsgroups
685: */
686: if (uid != ROOTID && uid != duid && uid) {
687: logerr("Please contact one of the local netnews people");
688: xerror("to create group \"%s\" for you", header.ctlmsg);
689: }
690: if (header.distribution[0] == '\0')
691: #ifdef ORGDISTRIB
692: strcpy(header.distribution, ORGDISTRIB);
693: #else /* !ORGDISTRIB */
694: strcpy(header.distribution, "local");
695: #endif /* !ORGDISTRIB */
696:
697: (void) strcpy(header.nbuf, header.ctlmsg);
698: if ((cp=index(header.nbuf, ' ')) != NULL)
699: *cp = '\0';
700:
701: if (header.approved[0] == '\0')
702: (void) sprintf(header.approved, "%s@%s",
703: username, FROMSYSNAME);
704: (void) sprintf(bfr, "%s/inews -n %s.ctl -c newgroup %s -d %s -a \"%s\"",
705: LIB, header.nbuf, header.ctlmsg, header.distribution,
706: header.approved);
707: if (tty) {
708: printf("Please type in a paragraph describing the new newsgroup.\n");
709: printf("End with control D as usual.\n");
710: }
711: printf("%s\n", bfr);
712: (void) fflush(stdout);
713: (void) system(bfr);
714: exit(0);
715: /*NOTREACHED*/
716: }
717:
718: char firstbufname[BUFLEN];
719: /*
720: * Link ARTICLE into dir for ngname and update active file.
721: */
722: long
723: localize(ngname)
724: char *ngname;
725: {
726: char afline[BUFLEN];
727: long ngsize;
728: long fpos;
729: int e;
730: char *cp;
731:
732: lock();
733: (void) rewind(actfp); clearerr(actfp);
734:
735: for(;;) {
736: fpos = ftell(actfp);
737: if (fgets(afline, sizeof afline, actfp) == NULL) {
738: unlock();
739: logerr("Can't find \"%s\" in active file", ngname);
740: return FALSE; /* No such newsgroup locally */
741: }
742: if (PREFIX(afline, ngname)) {
743: (void) sscanf(afline, "%s %ld", bfr, &ngsize);
744: if (STRCMP(bfr, ngname) == 0) {
745: if (ngsize < 0 || ngsize > 99998) {
746: logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr);
747: ngsize = 1;
748: }
749: break;
750: }
751: }
752: }
753: for (;;) {
754: cp = dirname(ngname);
755:
756: (void) sprintf(bfr, "%s/%ld", cp, ngsize+1);
757: #ifdef VMS
758: /*
759: * The effect of this code is to store the article in the first
760: * newsgroup's directory and to put symbolic links elsewhere.
761: * If this is the first group, firstbufname is not yet filled
762: * in. It should be portable to other link-less systems.
763: * epimass!jbuck
764: */
765: if (firstbufname[0]) {
766: if (vmslink(firstbufname, bfr) == 0)
767: break;
768: } else if (rename(ARTICLE, bfr) == 0)
769: break;
770: #else /* !VMS */
771: if (link(ARTICLE, bfr) == 0)
772: break;
773: #endif /* !VMS */
774: if (!exists(cp))
775: mknewsg(cp, ngname);
776: #ifdef VMS
777: if (firstbufname[0]) {
778: if (vmslink(firstbufname, bfr) == 0)
779: break;
780: } else if (rename(ARTICLE, bfr) == 0)
781: break;
782: #else /* !VMS */
783: if (link(ARTICLE, bfr) == 0)
784: break;
785: #endif /* !VMS */
786: e = errno; /* keep log from clobbering it */
787: log("Cannot install article as %s: %s", bfr, errmsg(errno));
788: if (e != EEXIST) {
789: logerr("Link into %s failed (%s); check dir permissions.",
790: bfr, errmsg(e));
791: unlock();
792: return FALSE;
793: }
794: ngsize++;
795: }
796:
797: /*
798: * This works around a bug in the 4.1bsd stdio
799: * on fseeks to non even offsets in r+w files
800: */
801: if (fpos&1)
802: (void) rewind(actfp);
803:
804: (void) fseek(actfp, fpos, 0);
805: /*
806: * Has to be same size as old because of %05d.
807: * This will overflow with 99999 articles.
808: */
809: fprintf(actfp, "%s %05ld", ngname, ngsize+1);
810: #if defined(USG) || defined(MG1)
811: /*
812: * U G L Y K L U D G E
813: * This utter piece of tripe is the only way I know of to get
814: * around the fact that ATT BROKE standard IO in System 5.2.
815: * Basically, you can't open a file for "r+" and then try and
816: * write to it. This works on all "real" USGUnix systems, It will
817: * probably break on some obscure look alike that doesnt use the
818: * real ATT stdio.h
819: * Don't blame me, blame ATT. stdio should have already done the
820: * following line for us, but it doesn't
821: * also broken in WCW MG-1 42nix 2.0
822: */
823: actfp->_flag |= _IOWRT;
824: #endif /* USG */
825: (void) fflush(actfp);
826: if (ferror(actfp))
827: xerror("Active file write failed");
828: unlock();
829: if (firstbufname[0] == '\0')
830: (void) strcpy(firstbufname, bfr);
831: (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
832: addhist(bfr);
833: return ngsize+1;
834: }
835:
836: /*
837: * Localize for each newsgroup and broadcast.
838: */
839: insert()
840: {
841: register char *ptr;
842: register FILE *tfp;
843: register int c;
844: struct srec srec; /* struct for sys file lookup */
845: struct tm *tm, *gmtime();
846: int is_invalid = FALSE;
847: int exitcode = 0;
848: long now;
849: #ifdef DOXREFS
850: register char *nextref = header.xref;
851: #endif /* DOXREFS */
852:
853: /* Clean up Newsgroups: line */
854: if (!is_ctl && mode != CREATENG)
855: is_invalid = ngfcheck(mode == PROC);
856:
857: (void) time(&now);
858: tm = gmtime(&now);
859: if (header.expdate[0])
860: addhist(" ");
861: #ifdef USG
862: sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t",
863: #else /* !USG */
864: sprintf(bfr,"%02d/%02d/%d %02d:%02d\t",
865: #endif /* !USG */
866: tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min);
867: addhist(bfr);
868: log("%s %s ng %s subj '%s' from %s", spool_news != DONT_SPOOL
869: ? "queued" : (mode==PROC ? "received" : "posted"),
870: header.ident, header.nbuf, header.title, header.from);
871:
872: /* Write article to temp file. */
873: tfp = xfopen(mktemp(ARTICLE), "w");
874:
875: if (is_invalid) {
876: logerr("No valid newsgroups found, moved to junk");
877: if (localize("junk"))
878: savehist(histline);
879: exitcode = 1;
880: goto writeout;
881: }
882:
883: #ifdef ZAPNOTES
884: if (STRNCMP(header.title, "Re: Orphaned Response", 21) == 0) {
885: logerr("Orphaned Response, moved to junk");
886: if (localize("junk"))
887: savehist(histline);
888: exitcode = 1;
889: goto writeout;
890: }
891: #endif /* ZAPNOTES */
892:
893: if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){
894: logerr("Article too old, moved to junk");
895: if (localize("junk"))
896: savehist(histline);
897: exitcode = 1;
898: goto writeout;
899: }
900:
901: if (is_mod[0] != '\0' /* one of the groups is moderated */
902: && header.approved[0] == '\0') { /* and unapproved */
903: struct hbuf mhdr;
904: FILE *mfd, *mhopen();
905: register char *p;
906: char modadd[BUFLEN], *replyname();
907: #ifdef DONTFOWARD
908: if(mode == PROC) {
909: logerr("Unapproved article in moderated group %s",
910: is_mod);
911: if (localize("junk"))
912: savehist(histline);
913: goto writeout;
914: }
915: #endif /* DONTFORWARD */
916: fprintf(stderr,"%s is moderated and may not be posted to",
917: is_mod);
918: fprintf(stderr," directly.\nYour article is being mailed to");
919: fprintf(stderr," the moderator who will post it for you.\n");
920: /* Let's find a path to the backbone */
921: sprintf(bfr, "%s/mailpaths", LIB);
922: mfd = xfopen(bfr, "r");
923: do {
924: if (fscanf(mfd, "%s %s", bfr, modadd) != 2)
925: xerror("Can't find backbone in %s/mailpaths",
926: LIB);
927: } while (STRCMP(bfr, "backbone") != 0 && !ngmatch(is_mod, bfr));
928: (void) fclose(mfd);
929: /* fake a header for mailhdr */
930: mhdr.from[0] = '\0';
931: mhdr.replyto[0] = '\0';
932: p = is_mod;
933: while (*++p)
934: if (*p == '.')
935: *p = '-';
936: sprintf(mhdr.path, modadd, is_mod);
937: mfd = mhopen(&mhdr);
938: if (mfd == NULL)
939: xerror("Can't send mail to %s", mhdr.path);
940: fprintf(mfd, "To: %s\n", replyname(&mhdr));
941: lhwrite(&header, mfd);
942: putc('\n', mfd);
943: while ((c = getc(infp)) != EOF)
944: putc(c, mfd);
945: mclose(mfd);
946: log("Article mailed to %s", mhdr.path);
947: xxit(0);
948: }
949:
950: if (mode != PROC && spool_news != DONT_SPOOL) {
951: if (spool_news != EXPIRE_RUNNING
952: && ngmatch(header.nbuf,"to.all.ctl"))
953: spool_news = DONT_SPOOL;
954: if (spool_news != DONT_SPOOL) {
955: fprintf(stderr,
956: "Your article has been spooled for later processing.\n");
957: dospool("#! inews -S -h", TRUE);
958: /* NOT REACHED */
959: }
960: }
961:
962: if (is_ctl) {
963: exitcode = control(&header);
964: if (localize("control") && exitcode != 0)
965: savehist(histline);
966: } else {
967: if (s_find(&srec, LOCALPATHSYSNAME) == FALSE) {
968: logerr("Cannot find my name '%s' in %s",
969: LOCALPATHSYSNAME, SUBFILE);
970: srec = dummy_srec;
971: }
972: #ifdef DOXREFS
973: (void) strncpy(nextref, PATHSYSNAME, BUFLEN);
974: #endif /* DOXREFS */
975: for (ptr = nbuf; *ptr;) {
976: if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){
977: #ifdef DOXREFS
978: while (*nextref++)
979: ;
980: (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr));
981: #else /* !DOXREFS */
982: (void) localize(ptr);
983: #endif /* !DOXREFS */
984: }
985: while (*ptr++)
986: ;
987: }
988: if (firstbufname[0] == '\0') {
989: logerr("Newsgroups in active, but not sys");
990: (void) localize("junk");
991: }
992: }
993: #ifdef DOXREFS
994: if (index(header.nbuf, NGDELIM) == NULL)
995: header.xref[0] = '\0';
996: #endif /* DOXREFS */
997:
998: writeout:
999: /* Part 1 of kludge to get around article truncation problem */
1000: if ( (c=getc(infp)) != EOF) {
1001: ungetc(c, infp);
1002: if (c == ' ' || c == '\t') {
1003: header.intnumlines++;
1004: (void) sprintf(header.numlines, "%d",
1005: header.intnumlines);
1006: }
1007: }
1008: /* End of part 1 */
1009: if (header.expdate[0] != '\0' && mode != PROC) {
1010: /* Make sure it's fully qualified */
1011: long t = cgtdate(header.expdate);
1012: strcpy(header.expdate, arpadate(&t));
1013: }
1014:
1015: lhwrite(&header, tfp);
1016: if ((c = getc(infp)) != EOF) {
1017: /* Part 2 of kludge to get around article truncation problem */
1018: if (c == ' ' || c == '\t' )
1019: putc('\n', tfp);
1020: /* End of part 2 */
1021: ungetc(c, infp);
1022: while (fgets(bfr, BUFLEN, infp) != NULL)
1023: fputs(bfr, tfp);
1024: if (bfr[strlen(bfr)-1] != '\n')
1025: putc('\n',tfp);
1026: }
1027: if (ferror(tfp))
1028: xerror("Write failed for temp file");
1029: (void) fclose(tfp);
1030: (void) fclose(infp);
1031: if(exitcode == 0) {
1032: /* article has passed all the checks, so work in background */
1033: if (mode != PROC) {
1034: int pid;
1035: if ((pid=fork()) < 0)
1036: xerror("Can't fork");
1037: else if (pid > 0)
1038: _exit(0);
1039: }
1040: #ifdef SIGTTOU
1041: (void) signal(SIGTTOU, SIG_IGN);
1042: #endif /* SIGTTOU */
1043: savehist(histline);
1044: if (header.supersedes[0] != '\0') {
1045: char *av[2];
1046:
1047: av[0] = "cancel";
1048: av[1] = header.supersedes;
1049: c_cancel(2, av);
1050: }
1051: broadcast(mode==PROC);
1052: }
1053: xxit((mode == PROC && filename[0] == '\0') ? 0 :
1054: (exitcode < 0 ? 0 : exitcode));
1055: }
1056:
1057: input(usegunk)
1058: {
1059: register char *cp;
1060: register int c;
1061: register int empty = TRUE;
1062: FILE *tmpfp;
1063: int consec_newlines = 0;
1064: int linecount = 0;
1065: int linserted = 0;
1066:
1067: tmpfp = xfopen(mktemp(INFILE), "w");
1068: for ( ; ; ) {
1069: if (SigTrap)
1070: break;
1071: if (usegunk)
1072: usegunk = FALSE;
1073: else if (fgets(bfr, BUFLEN, infp) != bfr)
1074: break;
1075: if (mode == PROC) { /* zap trailing empty lines */
1076: #ifdef ZAPNOTES
1077: if (empty && bfr[0] == '#' && bfr[2] == ':'
1078: && header.nf_id[0] == '\0'
1079: && header.nf_from[0] == '\0' ) {
1080: (void) strcpy(header.nf_id, bfr);
1081: (void) nstrip(header.nf_id);
1082: (void) fgets(bfr, BUFLEN, infp);
1083: (void) strcpy(header.nf_from, bfr);
1084: (void) nstrip(header.nf_from);
1085: (void) fgets(bfr, BUFLEN, infp);
1086:
1087: if (header.numlines[0]) {
1088: header.intnumlines -= 2;
1089: (void) sprintf(header.numlines, "%d", header.intnumlines);
1090: }
1091:
1092: /* Strip trailing " - (nf)" */
1093: if ((cp = rindex(header.title, '-')) != NULL
1094: && !strcmp(--cp, " - (nf)"))
1095: *cp = '\0';
1096: log("Stripped notes header on %s", header.ident);
1097: continue;
1098: }
1099: #endif /* ZAPNOTES */
1100: if (bfr[0] == '\n' ||
1101: /* Bandage for older versions of inews */
1102: bfr[1] == '\n' && !isascii(bfr[0])) {
1103: consec_newlines++; /* count it, in case */
1104: continue; /* but don't write it*/
1105: }
1106: /* foo! a non-empty line. write out all saved lines. */
1107: while (consec_newlines > 0) {
1108: putc('\n', tmpfp);
1109: consec_newlines--;
1110: linecount++;
1111: }
1112: }
1113: if (mode != PROC && tty && STRCMP(bfr, ".\n") == 0)
1114: break;
1115: for (cp = bfr; c = toascii(*cp); cp++) {
1116: if (isprint(c) || isspace(c) || c == '\b')
1117: putc(c, tmpfp);
1118: if (c == '\n')
1119: linecount++;
1120: }
1121: if (bfr[0] == '>')
1122: linserted++;
1123: if (bfr[0] == '<') /* kludge to allow diff's to be posted */
1124: linserted--;
1125: empty = FALSE;
1126: }
1127: if (*filename)
1128: (void) fclose(infp);
1129: if (mode != PROC &&
1130: linecount > LNCNT && linserted > (linecount-linserted))
1131: error("Article rejected: %s included more text than new text",
1132: username);
1133:
1134: if (mode != PROC && !is_ctl && header.sender[0] == '\0' && !Sflag) {
1135: int siglines = 0;
1136: char sbuf[BUFLEN];
1137: (void) sprintf(bfr, "%s/%s", userhome, ".signature");
1138: if (access(bfr, 4) == 0) {
1139: if ((infp = fopen(bfr, "r")) == NULL) {
1140: (void) fprintf(stderr,
1141: "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr);
1142: goto finish;
1143: }
1144:
1145: while (fgets(sbuf, sizeof sbuf, infp) != NULL)
1146: if (++siglines > 4)
1147: break;
1148: if (siglines > 4)
1149: fprintf(stderr,".signature not included (> 4 lines)\n");
1150: else {
1151: rewind(infp);
1152: fprintf(tmpfp, "-- \n"); /* To separate */
1153: linecount++;
1154: while ((c = getc(infp)) != EOF) {
1155: putc(c, tmpfp);
1156: if (c == '\n')
1157: linecount++;
1158: }
1159: }
1160: (void) fclose(infp);
1161: }
1162: }
1163:
1164: finish:
1165: if (ferror(tmpfp))
1166: xerror("write failed to temp file");
1167: (void) fclose(tmpfp);
1168: if (SigTrap) {
1169: if (tty)
1170: fprintf(stderr, "Interrupt\n");
1171: if (tty && !empty)
1172: fwait(fsubr(newssave, (char *) NULL, (char *) NULL));
1173: if (!tty)
1174: log("Blown away by an interrupt %d", SigTrap);
1175: xxit(1);
1176: }
1177: if (tty)
1178: fprintf(stderr, "EOT\n");
1179: fflush(stdout);
1180: infp = fopen(INFILE, "r");
1181: if (header.numlines[0]) {
1182: /*
1183: * Check line count if there's already one attached to
1184: * the article. Could make this a fatal error -
1185: * throwing it away if it got chopped, in hopes that
1186: * another copy will come in later with a correct
1187: * line count. But that seems a bit much for now.
1188: */
1189: if (linecount != header.intnumlines) {
1190: if (linecount == 0)
1191: error("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines);
1192: if (linecount > header.intnumlines ||
1193: linecount+consec_newlines < header.intnumlines)
1194: log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines);
1195: }
1196: /* adjust count for blank lines we stripped off */
1197: if (consec_newlines) {
1198: header.intnumlines -= consec_newlines;
1199: if (header.intnumlines < 0 )
1200: header.intnumlines = 0; /* paranoia */
1201: (void) sprintf(header.numlines, "%d", header.intnumlines);
1202: }
1203:
1204: } else {
1205: /* Attach a line count to the article. */
1206: header.intnumlines = linecount;
1207: (void) sprintf(header.numlines, "%d", linecount);
1208: }
1209: }
1210:
1211: /*
1212: * Make the directory for a new newsgroup. ngname should be the
1213: * full pathname of the directory. Do the other stuff too.
1214: * The various games with setuid and chown are to try to make sure
1215: * the directory is owned by NEWSUSR and NEWSGRP, which is tough to
1216: * do if you aren't root. This will work on a UCB system (which allows
1217: * setuid(geteuid()) or a USG system (which allows you to give away files
1218: * you own with chown), otherwise you have to change your kernel to allow
1219: * one of these things or run with your dirs 777 so that it doesn't matter
1220: * who owns them.
1221: */
1222: mknewsg(fulldir, ngname)
1223: char *fulldir;
1224: char *ngname;
1225: {
1226: #ifdef USG
1227: register char *p;
1228: char parent[200];
1229: char sysbuf[200];
1230: struct stat sbuf;
1231: #endif /* USG */
1232:
1233: if (ngname == NULL || !isalpha(ngname[0]))
1234: xerror("Tried to make illegal newsgroup %s", ngname);
1235:
1236: #ifdef USG
1237: /*
1238: * If the parent is 755 the setuid(getuid)
1239: * will fail, and since mkdir is suid, and our real uid is random,
1240: * the mkdir will fail. So we have to temporarily chmod it to 777.
1241: */
1242: (void) strcpy(parent, fulldir);
1243: while (p = rindex(parent, '/')) {
1244: *p = '\0';
1245: if (stat(parent, &sbuf) == 0) {
1246: (void) chmod(parent, 0777);
1247: break;
1248: }
1249: }
1250: #endif /* USG */
1251:
1252: /* Create the directory */
1253: mkparents(fulldir);
1254: if (mkdir(fulldir, 0777) < 0)
1255: xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
1256:
1257: #ifdef USG
1258: /*
1259: * Give away the directories we just created which were assigned
1260: * our real uid.
1261: */
1262: (void) setuid(uid);
1263: (void) chown(fulldir, duid, dgid);
1264:
1265: (void) strcpy(sysbuf, fulldir);
1266: while (p = rindex(sysbuf, '/')) {
1267: *p = '\0';
1268: /* stop when get to last known good parent */
1269: if (strcmp(sysbuf, parent) == 0)
1270: break;
1271: (void) chown(sysbuf, duid, dgid);
1272: }
1273: (void) setuid(duid);
1274: (void) chmod(parent, (int)sbuf.st_mode); /* put it back */
1275: #endif /* USG */
1276:
1277: log("make newsgroup %s in dir %s", ngname, fulldir);
1278: }
1279:
1280: /*
1281: * If any parent directories of this dir don't exist, create them.
1282: */
1283: mkparents(dname)
1284: char *dname;
1285: {
1286: char buf[200];
1287: register char *p;
1288:
1289: (void) strcpy(buf, dname);
1290: p = rindex(buf, '/');
1291: if (p)
1292: *p = '\0';
1293: if (exists(buf))
1294: return;
1295: mkparents(buf);
1296: if (mkdir(buf, 0777) < 0)
1297: xerror("Can not mkdir %s: %s", buf, errmsg(errno));
1298: }
1299:
1300: dounspool()
1301: {
1302: register DIR *dirp;
1303: register struct direct *dir;
1304: register int foundsome;
1305: int pid, status, ret;
1306: char spbuf[BUFLEN];
1307: #ifdef LOCKF
1308: FILE* LockFd;
1309: #endif /* LOCKF */
1310: #ifdef VMS
1311: sprintf(spbuf, "%s/+rnews", SPOOL);
1312: #else /* !VMS */
1313: sprintf(spbuf, "%s/.rnews", SPOOL);
1314: #endif /* !VMS */
1315:
1316: if (chdir(spbuf) < 0)
1317: xerror("chdir(%s):%s", spbuf, errmsg(errno));
1318:
1319: dirp = opendir(".");
1320: if (dirp == NULL) /* Boy are things screwed up */
1321: xerror("opendir can't open .:%s", errmsg(errno));
1322: #ifdef LOCKF
1323: LockFd = xfopen(SEQFILE, "r+w");
1324: if (lockf(fileno(LockFd), F_TLOCK, 0L) < 0) {
1325: if (errno != EAGAIN && errno != EACCES)
1326: #else /* !LOCKF */
1327: #ifdef BSD4_2
1328: if (flock(dirp->dd_fd, LOCK_EX|LOCK_NB) < 0) {
1329: if (errno != EWOULDBLOCK)
1330: #else /* V7 */
1331: strcat(spbuf, ".lock");
1332: sprintf(bfr, "%s.tmp", spbuf);
1333: (void) close(creat(bfr, 0666));
1334: ret = LINK(bfr, spbuf);
1335: status = errno;
1336: (void) UNLINK(bfr);
1337: errno = status;
1338: if (ret < 0) {
1339: if (errno != EEXIST)
1340: #endif /* V7 */
1341: #endif /* !LOCKF */
1342: xerror("Can't lock %s: %s", spbuf, errmsg(errno));
1343: xxit(3); /* another rnews -U is running */
1344: }
1345:
1346: do {
1347: foundsome = 0;
1348:
1349: while ((dir=readdir(dirp)) != NULL) {
1350: if (dir->d_name[0] == '.')
1351: continue;
1352:
1353: #ifdef IHCC
1354: log("Unspooling from %s", dir->d_name);
1355: #endif /* IHCC */
1356:
1357: if ((pid=vfork()) == -1)
1358: xerror("Can't fork: %s", errmsg(errno));
1359: if (pid == 0) {
1360: #ifdef LOGDIR
1361: char bufr[BUFSIZ];
1362: sprintf(bufr, "%s/%s", logdir(HOME), RNEWS);
1363: execl(bufr, "rnews", "-S", "-p", dir->d_name,
1364: (char *) NULL);
1365: #else /* !LOGDIR */
1366: execl(RNEWS, "rnews", "-S", "-p", dir->d_name,
1367: (char *) NULL);
1368: #endif /* !LOGDIR */
1369: _exit(1);
1370: }
1371:
1372: while ((ret=wait(&status)) != pid && ret != -1)
1373: /* continue */;
1374:
1375: if (((status>>8)&0177) == 42) {
1376: /* expire has started up, shutdown rnews -U */
1377: break;
1378: }
1379:
1380: if (status != 0) {
1381: sprintf(bfr, "../%s", dir->d_name);
1382: (void) LINK(dir->d_name, bfr);
1383: logerr("rnews failed, status %ld. Batch saved in %s/%s",
1384: (long)status, SPOOL, dir->d_name);
1385: }
1386: (void) unlink(dir->d_name);
1387: foundsome++;
1388: }
1389: rewinddir(dirp);
1390: } while (foundsome); /* keep rereading the directory until it's empty */
1391: #ifndef LOCKF
1392: #ifndef BSD4_2
1393: (void) UNLINK(spbuf);
1394: #endif
1395: #endif
1396:
1397: xxit(0);
1398: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.