home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume1 / xfernews < prev    next >
Internet Message Format  |  1986-11-30  |  46KB

  1. Date: Wed, 30 Jan 85 16:20:06 est
  2. From: allegra!gatech!spaf
  3. Subject: xfernews software
  4. Newsgroups: mod.sources
  5.  
  6. The following software package is the "xfernews" suite for handling
  7. batched transmission of news articles directly from the source directories.
  8. These programs were written by Kenneth Almquist and have been used
  9. by many sites around the net with much success for quite a while.
  10.  
  11. Everything should be documented as to what you need to do to install
  12. these programs.  I will note that there is rumor that these may be
  13. included as part of the standard 2.10.3 news release, so you may
  14. want to wait until then to play with these.
  15.  
  16. A couple of suggestions:
  17. 1) there is a naming conflict between the 2.10.2 sendnews and the
  18. xfernews sendnews.  I renamed the latter to be xsendnews.  Don't
  19. get bitten by this one.
  20. 2) Don't run recvnews too often.  The locking mechanism has a bug and
  21. you'll get multiple versions tromping on each other.  We have great
  22. success running sendnews every 4 hours, and recvnews every 2 or 3 hours.
  23.  
  24. If you find any bugs, please mail them to me, to ka@hou3c, hokey@plus5 and to
  25. rick@seismo.
  26.  
  27. Enjoy!
  28.  
  29.  
  30. : to unbundle, "sh" this file -- DO NOT use csh
  31. :  SHAR archive format.  Archive created Tue Jan 29 15:00:06 EST 1985
  32. echo x - NROFFME
  33. sed 's/^X//' > NROFFME <<'+FUNKY+STUFF+'
  34. X.hy
  35. X.de p
  36. X.sp
  37. X.ti +5
  38. X..
  39. X.de Np
  40. X'bp
  41. X'sp 5
  42. X.ns
  43. X..
  44. X.wh 61 Np
  45. X.de h
  46. X.sp 2
  47. X.ne 4
  48. X.nr h +1
  49. X\\nh)\ \ \\$1
  50. X.p
  51. X..
  52. X.h "What is xfernews?"
  53. XXfernews is a package of software for transporting news,
  54. Xand optionally mail, between machines.
  55. XIt is designed to be efficient, reliable, and to run on top of
  56. Xvanilla uucp.
  57. X.p
  58. XThe memo is divided into five sections.
  59. XSection 2 documents the protocal used by xfernews.
  60. XSection 3 gives an overview of how the xfernews software works.
  61. XSection 4 and 5 discuss the compilation and installation of xfernews.
  62. XFinally, section 6 talks about error messages.
  63. X.h "The xfernews protocal"
  64. XThe two news transport methods described in the
  65. X.ul
  66. XUSENET Interchange Standard
  67. Xare based upon remote execution and mail, respectively.
  68. XXfernews is based upon file transfer,
  69. Xwhich is handled better by uucp and many other networks.
  70. X.p
  71. XAssuming that two systems communicate using the xfernews
  72. Xprotocal, each systems has an input directory which the other
  73. Xsystem sends files to.
  74. XEach system periodicly checks its input directory and processes
  75. Xany files which it may find there.
  76. XThe name of the file identifies its contents.
  77. XThe first character of the name is the type;
  78. Xa list of types is given below.
  79. XThe next 9 characters contain the value in decimal returned by time(2)
  80. Xwhen the file was queued for transfer.
  81. XThis should be used by the receiving system to process
  82. Xnews in the same order that it was queued.
  83. XThe final character of the filename is a letter chosen to make the
  84. Xfile name unique.
  85. X.p
  86. XThere are three file types currently defined.
  87. XType 'n' files contain news articles.
  88. X.p
  89. XType 'm' files contain mail.
  90. XThe use of this protocal for mail is optional,
  91. Xbut is recomended for links which carry large amounts of mail.
  92. XThe first line of the file contains the three characters "To "
  93. Xfollowed by the destination of the mail.
  94. XThe rest of the file contains the letter.
  95. XType 'a' files are acknowledgement files.
  96. XAn acknowledgement file contains a list of files received
  97. Xby the system which sent the acknowledgement file.
  98. XIf a system fails to acknowledge a file,
  99. Xthe file should be resent.
  100. X.h "The Xfernews Software"
  101. XThis gives an overview of the implementation of the xfernews protocal
  102. Xfor use with uucp.
  103. XThree programs are provided.
  104. XQnews queues news for transmission to another system.
  105. XSendnews sends the news which has been queued up
  106. Xto another system.
  107. XRecvnews processes news files sent from another system.
  108. X.p
  109. XFor each system talked to using xfernews,
  110. Xthere is a spool directory.
  111. XThe contents of this directory are:
  112. X.de l
  113. X.sp
  114. X.ti 0
  115. X.ta 16
  116. X\\$1    \c
  117. X.ta 8,16,24,32,40,48,56,64,72,80
  118. X..
  119. X.in 16
  120. X.l in
  121. XThe input directory used by the remote system (see section 2).
  122. X.l out
  123. XNews to be sent to the remote system is placed here by queuenews.
  124. X.l sent
  125. XWhen sendnews sends news to the remote system, it moves it from
  126. Xthe out directory to the sent directory.
  127. XThe news remains in the sent directory
  128. Xuntil the remote system acknowledges it.
  129. X.l ackfile
  130. XThis file contains a list of input files
  131. Xwhich have been processed.
  132. XSendnews sends the contents of this file
  133. Xto the remote system
  134. Xas an acknowledgement file.
  135. X.l lastack
  136. XThis file contains the time of the last file acknowledged
  137. Xby the remote system.
  138. XIt is used to avoid resending files which haven't been acknowledged
  139. Xbecause the remote system is down.
  140. X.l resentflag
  141. XWhen sendnews resends some news,
  142. Xit creates this file.
  143. XThe next time sendnews is invoked, it will not resned any news
  144. Xin order to give the remote system time to acknowledge the files
  145. Xalready resent.
  146. X.l bad
  147. XWhen a file is found in one of the directories "in", "out", or "sent"
  148. Xwhich cannot be processed,
  149. Xit is moved to this directory
  150. Xand you are informed of the fact by mail.
  151. X.in 0
  152. X.h "Compiling the Xfernews Software"
  153. XCompiling the xfernews software is simple:  all you have to do
  154. Xis to type "make".
  155. XHowever, you will probably want to modify
  156. Xsome compile time parameters first.
  157. X.p
  158. XIf you are not running System 3 or System 5,
  159. Xyou should remove the "#define USG 1" line
  160. Xfrom common.h.
  161. XThis will get you code which should run using Version 6 system calls.
  162. XThe version of the library routines provided with 4.1 BSD should
  163. Xwork with this code.
  164. XIf you have 4.2 BSD, the directory format is different;
  165. Xeliminate the 4.2 compatability routines in dir.c and dir.h,
  166. Xand use the real routines provided by Berkeley.
  167. X.p
  168. XThere are several compile time parameters which you may want to change:
  169. X.in 16
  170. X.l RNEWS
  171. Xis the path name of the rnews program
  172. Xused for processing news.
  173. XBe warned that no path search will be performed.
  174. XFurthermore, the rnews program cannot be a
  175. Xshell procedure.
  176. XThe default is "/usr/bin/rnews".
  177. X.l RMAIL
  178. Xis the path name of a program for processing mail.
  179. XIf you don't use xfernews for transferring mail,
  180. Xthis isn't used.
  181. XThe default is "/bin/rmail".
  182. X.l UUCP
  183. Xis the path name of the uucp command.
  184. XThe default is "/usr/bin/uucp".
  185. X.l MAILCMD
  186. Xis the command passed to popen to inform the system administrator
  187. Xof problems.
  188. XThe default is "mail\ usenet".
  189. X.l RECVLOCK
  190. Xis the name of the lock file used to prevent two copies of recvnews
  191. Xfrom running simultaneously.
  192. XHaving two copies of recvnews running simultaneously in the same directory
  193. Xwill cause problems.
  194. XWe have one system wide lock rather than one lock per directory
  195. Xbecause inews running multiple copies of inews
  196. Xseems to result in "news system locked up" messages.
  197. X.l NETNEWS
  198. Xis the numeric user id which is to be used by sendnews
  199. Xand recvnews when they are invoked as root.
  200. XIf they are not invoked as root then this has no effect.
  201. X.l DESTLEN
  202. Xis the maximum length of a mail destination.
  203. X.l MAXARGS
  204. Xis the maximum number of files which can be processed
  205. Xby a given invokation of sendnews or recvnews.
  206. X.l MINACK
  207. Xspecifies the minimum number of files needing to be acknowledged
  208. Xbefore an acknowledgement file will be sent.
  209. XSetting this to zero causes the systems to keep trading acknowledgements
  210. Xeven when the link is idle.  (Each acknowledgement has to be acked.)  Note
  211. Xthat any pending acknowledgements are always sent if a connection has
  212. Xto be established to transfer news or mail anyway.
  213. XMINACK is specified as the number of bytes; since each file currently
  214. Xtakes 12 bytes, divide by 12 to get the number of files.
  215. X.in 0
  216. X.h " Installing Xfernews"
  217. XOnce xfernews is compiled,
  218. Xyou can set up links to other machines using the xfernews protocal.
  219. X.p
  220. XThe first step is to create xfernews spool directories
  221. Xfor the systems you want to talk to.
  222. XThe shell procedure mkspool creates xfernews spool directories.
  223. XBy default, these are created as subdirectories of /usr/spool.  This
  224. Xmay be changed by editing the mkspool script.
  225. X.p
  226. XRecvnews is invoked as "recvnews directory...".
  227. XEach directory is the name of an xfernews spool directory.
  228. XIt is recomended that xfernews be invoked from cron
  229. Xquite frequently, say once every 15 minutes,
  230. Xso that news will be processed as quickly as possible.
  231. X.p
  232. XSendnews is invoked as "sendnews [\ -r\ ][\ -c\ ] directory to".
  233. XDirectory is the name of an xfernews spool directory.
  234. XTo is the name of the input directory on the remote system
  235. Xin uucp format (see example below).
  236. XThe -r and -c options are passed directly to uucp;
  237. X-r tells uucp not to start up the uucp daemon, and -c tells it
  238. Xto transfer directly from the source files without making copies in
  239. Xthe spool directory.  This can be particularly beneficial if the
  240. Xnews and uucp spool directories are on the same file system since
  241. Xit allows news to be passed on to other systems with practically no
  242. Xdisk overhead.
  243. X.p
  244. XIt is recomended that both systems using xfernews
  245. Xinvoke sendnews simultaneously.
  246. XTo avoid extra phone calls, one system should specify
  247. Xthe -r option.
  248. XNormally you will want to alternate specifying the -r option
  249. Xin order to share the phone bill.
  250. XFor example, if a link exists between spanky and tpsa,
  251. Xthe crontab entries on spanky might look like
  252. X.in +4
  253. X.nf
  254. X
  255. X0  * * * * /usr/lib/news/sendnews -c /usr/spool/tpsa tpsa!/usr/spool/spanky/in
  256. X30 * * * * /usr/lib/news/sendnews -r -c /usr/spool/tpsa tpsa!/usr/spool/spanky/in
  257. X
  258. X.fi
  259. X.in -4
  260. Xand the corresponding entries on tpsa would be
  261. X.in +4
  262. X.nf
  263. X
  264. X0 * * * * /usr/lib/news/sendnews -r -c /usr/spool/spanky spanky!/usr/spool/tpsa/in
  265. X30 * * * * /usr/lib/news/sendnews -c /usr/spool/spanky spanky!/usr/spool/tpsa/in
  266. X
  267. X.fi
  268. X.in -4
  269. XThis arranges systems to alternate the job of calling each other.
  270. XIn this example, news is transferred every half hour;
  271. Xover a long distance telephone connection you would want to
  272. Xtransfer it less frequently.
  273. X.p
  274. XOnce the connection is set up, you can begin feeding news into it
  275. Xusing the qnews program.
  276. XFor a normal interface with netnews, place the command
  277. X"qnews directory/out" in the fourth field of the sys file entry
  278. Xfor the system you wish to talk to.
  279. XDirectory should be replaced by the name of the spool directory
  280. Xfor the system you wish to talk to. For example, if you send news
  281. Xto a system named spanky, the sys entry might look like this:
  282. X.in +4
  283. X.nf
  284. X
  285. Xspanky:mod,net,to.spanky:B:/usr/lib/news/qnews /usr/spool/spanky
  286. X
  287. X.fi
  288. X.in -4
  289. XThis will cause qnews to read its standard input
  290. Xand copy it to a file in the directory specified as its argument.
  291. X.p
  292. XIn version 2.10 of netnews, it is possible to reference the name
  293. Xof the article as it is stored in the netnews spool directory,
  294. Xthereby allowing the article to be linked into the spool directory
  295. Xrather than being copied there.
  296. XTo use this feature, the netnews spool directory and the xfernews
  297. Xspool directory must be in the same file system.
  298. XAdd the U flag to the third field of the entry in the sys file,
  299. Xand in the fourth field say:  "qnews directory/out %s":
  300. X.in +4
  301. X.nf
  302. X
  303. Xspanky:mod,net,to.spanky:BU:/usr/lib/news/qnews /usr/spool/spanky %s
  304. X
  305. X.fi
  306. X.in -4
  307. XInews will replace the %s with the name of the article in the spool
  308. Xdirectory before invoking qnews.
  309. XIf the article is a control message, the article is not placed in
  310. Xthe netnews spool directory and the %s is passed to qnews unchanged.
  311. XQnews checks for this case and reads the article from its standard input.
  312. XNote that even in this case, inews copies the article to a file,
  313. Xso you may want to modify inews to pass the name of the file to qnews
  314. Xeven when it is a control message.
  315. X.p
  316. XIf the cost of a phone connection is very high, or you are
  317. Xhaving problems with mail being lost, you may want to transfer mail
  318. Xas well as news using xfernews.
  319. XYou will probably have to modify your mailer code.
  320. XThe basic idea is you first figure out how your mail system transfers
  321. Xmail using uux.
  322. XIt will invoke uux by saying something like:
  323. X.nf
  324. X
  325. X      sprintf(cmd, "uux - %s!rnews \\(%s\\)", system, dest) ;
  326. X      fp = popen(cmd, "w") ;
  327. X
  328. X.fi
  329. XAssuming spanky is the system you want to send mail to using xfernews,
  330. Xchange this to:
  331. X.nf
  332. X
  333. X      if (strcmp(system, "spanky") == 0) {
  334. X            sprintf(cmd, "qnews -tm %s /usr/spool/spanky", dest) ;
  335. X            fp = popen(cmd, "w") ;
  336. X            if (fp != NULL)
  337. X                  fprintf(fp, "To %s\\n", dest) ;
  338. X      } else {
  339. X            sprintf(cmd, "uux - %s!rnews \\(%s\\)", system, dest) ;
  340. X            fp = popen(cmd) ;
  341. X      }
  342. X
  343. X.fi
  344. XThe -t option to qnews specifies the type of file to be created;
  345. Xin this case 'm' or mail.
  346. X.h "Administration of xfernews"
  347. XWhen an error occurs in the xfernews package,
  348. Xyou will be informed by mail.
  349. XIt is important that the mail command work;
  350. Xtry invoking sendnews without any arguments and see if an error message
  351. Xis mailed to you.
  352. XMost error messages refer to errors which "can't happen" (i. e.
  353. Xthe problem is either a bug in the package or an error in installation).
  354. XYou may have to grep through the code or contact the aouthor to identify these.
  355. XYou are also informed when the RNEWS or RMAIL programs exit with non-zero
  356. Xstatus.
  357. XWhen one of these programs fails, the mail or news is still acknowledged
  358. Xand the file is linked into the directory "bad" where you can fix the
  359. Xproblem manually.
  360. XThe exit status of the program and any error messages generated by the program
  361. Xare included in in the message.
  362. XSometimes the problem is transient, so just running rnews again will fix
  363. Xthe problem.
  364. XIf you run 2.10, you may want to inews to exit with an error indication
  365. Xwhen an unknown newsgroup is received.
  366. XThis way you can fix the problem and resubmit the article.
  367. XThe following version of the routine getapproval (in inews.c)
  368. Xdoes the trick, at least for the beta release:
  369. X.nf
  370. X
  371. Xgetapproval(ng)
  372. Xchar    *ng;
  373. X{
  374. X    char buf[128] ;
  375. X    sprintf(buf, "inews:  unrecognized newsgroup %s\n", ng) ;
  376. X    log(buf) ;
  377. X    printf("%s", buf) ;
  378. X    xxit(4) ;
  379. X}
  380. X
  381. X.fi
  382. XFiles in the directories "in", "out", and "sent" with unrecognized names
  383. Xwill also be moved to the directory "bad".
  384. XIf rnews dies with a core dump, the core file will be left in "in",
  385. Xand the next invocation of recvnews will move it to "bad".
  386. +FUNKY+STUFF+
  387. echo '-rw-r--r-- 1 wan       12678 Nov 29  1983 NROFFME    (as sent)'
  388. chmod u=rw,g=r,o=r NROFFME
  389. ls -l NROFFME
  390. echo x - README
  391. sed 's/^X//' > README <<'+FUNKY+STUFF+'
  392. XSee NROFFME.OUT for an explanation of how this "batching" scheme
  393. Xworks.
  394. X
  395. XModify common.h and mkspool to suit your configuration.  NROFFME
  396. Xcontains explanations of what various parameters mean.
  397. X
  398. XModify the makefile to reference the appropriate directories and
  399. Xuser/group names, then as root type make install.
  400. X
  401. Xnews.send and news.recv are sample shell procedures to be invoked
  402. Xfrom cron periodically.  The applicable crontab entries at gatech
  403. Xare
  404. X
  405. X    4,14,24,34,44,54 * * * *    /usr/lib/news/news.recv
  406. X    18 * * * *            /usr/lib/news/news.send
  407. X
  408. XNote that the news.send script should be scheduled a few minutes
  409. Xbefore a uucp contact is expected to minimize the latency of
  410. Xarticles waiting in the batching queue.
  411. +FUNKY+STUFF+
  412. echo '-rw-r--r-- 1 wan         702 Nov 29  1983 README    (as sent)'
  413. chmod u=rw,g=r,o=r README
  414. ls -l README
  415. echo x - common.h
  416. sed 's/^X//' > common.h <<'+FUNKY+STUFF+'
  417. X#include <stdio.h>
  418. X#include <sys/types.h>
  419. X#ifdef USG
  420. X#define u_short ushort
  421. X#endif
  422. X#include "dir.h"
  423. X#include <sys/stat.h>
  424. X#include <signal.h>
  425. X#include <errno.h>
  426. X#ifdef USG
  427. X#include <fcntl.h>
  428. X#endif
  429. X
  430. X#define FNLEN    15    /* max file name length (including nul) */
  431. X#define PATHLEN    100    /* max path name length */
  432. X#define DESTLEN 256    /* max length of mail destination */
  433. X#define MAXARGS    200    /* max number of args to uucp */
  434. X#define SETIN    01    /* flag to run:  reset stdin */
  435. X#define RNEWS    "/usr/bin/rnews"
  436. X#define RMAIL    "/bin/rmail"
  437. X#define UUCP    "/usr/bin/uucp"
  438. X#define MAILCMD    "/bin/csmail usenet"
  439. X#define RECVLOCK "/usr/tmp/recv.lock"
  440. X#define MINACK (10 * 12)
  441. X#define NETNEWS    65    /* netnews user id */
  442. X
  443. X
  444. X#ifndef USG
  445. X#define strchr index
  446. X#endif
  447. X
  448. X/* routine to determine if a process exists */
  449. X#define procexists(pid)    (kill(pid, 0) >= 0 || errno == EPERM)
  450. X
  451. Xlong time(), atol() ;
  452. Xchar *strcpy(), *strchr() ;
  453. Xchar *malloc() ;
  454. XFILE *popen() ;
  455. Xint comp() ;
  456. X
  457. Xextern int errno ;
  458. +FUNKY+STUFF+
  459. echo '-rw-r--r-- 1 wan         962 Nov 22  1983 common.h    (as sent)'
  460. chmod u=rw,g=r,o=r common.h
  461. ls -l common.h
  462. echo x - dir.c
  463. sed 's/^X//' > dir.c <<'+FUNKY+STUFF+'
  464. X#include <sys/types.h>
  465. X#include "dir.h"
  466. X
  467. X/*
  468. X * close a directory.
  469. X */
  470. Xvoid
  471. Xclosedir(dirp)
  472. X    register DIR *dirp;
  473. X{
  474. X    close(dirp->dd_fd);
  475. X    dirp->dd_fd = -1;
  476. X    dirp->dd_loc = 0;
  477. X    free(dirp);
  478. X}
  479. X
  480. X
  481. X
  482. X/*
  483. X * open a directory.
  484. X */
  485. XDIR *
  486. Xopendir(name)
  487. X    char *name;
  488. X{
  489. X    register DIR *dirp;
  490. X    register int fd;
  491. X
  492. X    if ((fd = open(name, 0)) == -1)
  493. X        return NULL;
  494. X    if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
  495. X        close (fd);
  496. X        return NULL;
  497. X    }
  498. X    dirp->dd_fd = fd;
  499. X    dirp->dd_loc = 0;
  500. X    return dirp;
  501. X}
  502. X
  503. X
  504. X
  505. X/*
  506. X * read an old style directory entry and present it as a new one
  507. X */
  508. X
  509. X#define    ODIRSIZ    14
  510. X
  511. Xstruct    olddirect {
  512. X    ino_t    od_ino;
  513. X    char    od_name[ODIRSIZ];
  514. X};
  515. X
  516. X/*
  517. X * get next entry in a directory.
  518. X */
  519. Xstruct direct *
  520. Xreaddir(dirp)
  521. X    register DIR *dirp;
  522. X{
  523. X    register struct olddirect *dp;
  524. X    static struct direct dir;
  525. X
  526. X    for (;;) {
  527. X        if (dirp->dd_loc == 0) {
  528. X            dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
  529. X                DIRBLKSIZ);
  530. X            if (dirp->dd_size <= 0)
  531. X                return NULL;
  532. X        }
  533. X        if (dirp->dd_loc >= dirp->dd_size) {
  534. X            dirp->dd_loc = 0;
  535. X            continue;
  536. X        }
  537. X        dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
  538. X        dirp->dd_loc += sizeof(struct olddirect);
  539. X        if (dp->od_ino == 0)
  540. X            continue;
  541. X        dir.d_ino = dp->od_ino;
  542. X        strncpy(dir.d_name, dp->od_name, ODIRSIZ);
  543. X        dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
  544. X        dir.d_namlen = strlen(dir.d_name);
  545. X        dir.d_reclen = DIRBLKSIZ;
  546. X        return (&dir);
  547. X    }
  548. X}
  549. +FUNKY+STUFF+
  550. echo '-rw-r--r-- 1 wan        1382 Nov 22  1983 dir.c    (as sent)'
  551. chmod u=rw,g=r,o=r dir.c
  552. ls -l dir.c
  553. echo x - dir.h
  554. sed 's/^X//' > dir.h <<'+FUNKY+STUFF+'
  555. X/*    dir.h    4.4    82/07/25    */
  556. X
  557. X/*
  558. X * A directory consists of some number of blocks of DIRBLKSIZ
  559. X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
  560. X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
  561. X *
  562. X * Each DIRBLKSIZ byte block contains some number of directory entry
  563. X * structures, which are of variable length.  Each directory entry has
  564. X * a struct direct at the front of it, containing its inode number,
  565. X * the length of the entry, and the length of the name contained in
  566. X * the entry.  These are followed by the name padded to a 4 byte boundary
  567. X * with null bytes.  All names are guaranteed null terminated.
  568. X * The maximum length of a name in a directory is MAXNAMLEN.
  569. X *
  570. X * The macro DIRSIZ(dp) gives the amount of space required to represent
  571. X * a directory entry.  Free space in a directory is represented by
  572. X * entries which have dp->d_reclen >= DIRSIZ(dp).  All DIRBLKSIZ bytes
  573. X * in a directory block are claimed by the directory entries.  This
  574. X * usually results in the last entry in a directory having a large
  575. X * dp->d_reclen.  When entries are deleted from a directory, the
  576. X * space is returned to the previous entry in the same directory
  577. X * block by increasing its dp->d_reclen.  If the first entry of
  578. X * a directory block is free, then its dp->d_ino is set to 0.
  579. X * Entries other than the first in a directory do not normally have
  580. X * dp->d_ino set to 0.
  581. X */
  582. X#define DIRBLKSIZ    512
  583. X#define    MAXNAMLEN    255
  584. X
  585. X#ifdef pdp11
  586. X#define u_long long
  587. X#endif
  588. X
  589. Xstruct    direct {
  590. X    u_long    d_ino;            /* inode number of entry */
  591. X    u_short    d_reclen;        /* length of this record */
  592. X    u_short    d_namlen;        /* length of string in d_name */
  593. X    char    d_name[MAXNAMLEN + 1];    /* name must be no longer than this */
  594. X};
  595. X
  596. X/*
  597. X * The DIRSIZ macro gives the minimum record length which will hold
  598. X * the directory entry.  This requires the amount of space in struct direct
  599. X * without the d_name field, plus enough space for the name with a terminating
  600. X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
  601. X */
  602. X#undef DIRSIZ
  603. X#define DIRSIZ(dp) \
  604. X    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
  605. X
  606. X#ifndef KERNEL
  607. X/*
  608. X * Definitions for library routines operating on directories.
  609. X */
  610. Xtypedef struct _dirdesc {
  611. X    int    dd_fd;
  612. X    long    dd_loc;
  613. X    long    dd_size;
  614. X    char    dd_buf[DIRBLKSIZ];
  615. X} DIR;
  616. X#ifndef NULL
  617. X#define NULL 0
  618. X#endif
  619. Xextern    DIR *opendir();
  620. Xextern    struct direct *readdir();
  621. Xextern    long telldir();
  622. Xextern    void seekdir();
  623. X#define rewinddir(dirp)    seekdir((dirp), (long)0)
  624. Xextern    void closedir();
  625. X#endif KERNEL
  626. +FUNKY+STUFF+
  627. echo '-rw-r--r-- 1 wan        2546 Nov 22  1983 dir.h    (as sent)'
  628. chmod u=rw,g=r,o=r dir.h
  629. ls -l dir.h
  630. echo x - makefile
  631. sed 's/^X//' > makefile <<'+FUNKY+STUFF+'
  632. Xall: recvnews xsendnews qnews
  633. X
  634. Xrecvnews: recvnews.o dir.o
  635. X    $(CC) -o $@ recvnews.o dir.o
  636. X
  637. Xxsendnews: sendnews.o dir.o
  638. X    $(CC) -o $@ sendnews.o dir.o
  639. X
  640. Xqnews: qnews.c common.h
  641. X    $(CC) -o $@ $(CFLAGS) qnews.c
  642. X
  643. Xsendnews.o recvnews.o: common.h
  644. X
  645. Xinstall: all
  646. X    cp mkspool xsendnews recvnews qnews /usr/lib/news
  647. X    cd /usr/lib/news; chown news xsendnews recvnews qnews
  648. X    cd /usr/lib/news; chgrp news xsendnews recvnews qnews
  649. X    chmod ug+s /usr/lib/news/xsendnews /usr/lib/news/recvnews /usr/lib/news/qnews
  650. +FUNKY+STUFF+
  651. echo '-rw-r--r-- 1 wan         490 Oct  1 21:52 makefile    (as sent)'
  652. chmod u=rw,g=r,o=r makefile
  653. ls -l makefile
  654. echo x - mkspool
  655. sed 's/^X//' > mkspool <<'+FUNKY+STUFF+'
  656. X#! /bin/sh
  657. X# Create an xfernews spool directory
  658. X
  659. Xif [ $# = 0 ]
  660. Xthen
  661. X    echo usage: mkspool sysname ...
  662. X    exit 1
  663. Xfi
  664. X
  665. Xcd /usr/spool
  666. Xumask 022
  667. X
  668. Xfor sys do
  669. X    if [ -z "$sys" -o "$sys" != "`basename \"$sys\"`" ]
  670. X    then
  671. X        echo $sys: bad system name
  672. X        continue
  673. X    elif [ -f $sys -o -d $sys ]
  674. X    then
  675. X        echo $sys: conflicts with existing file or directory
  676. X        continue
  677. X    fi
  678. X    if mkdir $sys
  679. X    then
  680. X        mkdir $sys/in
  681. X        mkdir $sys/sent
  682. X        mkdir $sys/out
  683. X        mkdir $sys/bad
  684. X        echo 0 > $sys/lastack
  685. X        chown news $sys $sys/in $sys/sent $sys/out $sys/bad $sys/lastack
  686. X        chgrp news $sys $sys/in $sys/sent $sys/out $sys/bad $sys/lastack
  687. X        chmod a+w $sys/in
  688. X        ls -ld $sys $sys/*
  689. X    fi
  690. Xdone
  691. +FUNKY+STUFF+
  692. echo '-rwxr-xr-x 1 wan         650 Dec 15  1983 mkspool    (as sent)'
  693. chmod u=rwx,g=rx,o=rx mkspool
  694. ls -l mkspool
  695. echo x - news.recv
  696. sed 's/^X//' > news.recv <<'+FUNKY+STUFF+'
  697. X#! /bin/sh
  698. X
  699. X    PATH=/usr/lib/news:/bin:/usr/bin
  700. X
  701. X    cd /usr/spool
  702. X    umask 022
  703. X    recvnews akgua emory >> /usr/lib/news/recv.log 2>&1
  704. +FUNKY+STUFF+
  705. echo '-rwxr-xr-x 1 wan         126 Dec 19  1983 news.recv    (as sent)'
  706. chmod u=rwx,g=rx,o=rx news.recv
  707. ls -l news.recv
  708. echo x - news.send
  709. sed 's/^X//' > news.send <<'+FUNKY+STUFF+'
  710. X#! /bin/sh
  711. X
  712. X    PATH=/usr/lib/news:/bin:/usr/bin
  713. X
  714. X    cd /usr/spool
  715. X    umask 022
  716. X    sendnews -c -r akgua akgua!/usr/spool/gatech/in
  717. X    sendnews -c -r emory emory!/usr/spool/gatech/in
  718. +FUNKY+STUFF+
  719. echo '-rwxr-xr-x 1 wan         171 Dec 19  1983 news.send    (as sent)'
  720. chmod u=rwx,g=rx,o=rx news.send
  721. ls -l news.send
  722. echo x - qnews.c
  723. sed 's/^X//' > qnews.c <<'+FUNKY+STUFF+'
  724. X#include "common.h"
  725. X
  726. X
  727. Xchar *directory ;
  728. Xchar *file ;
  729. X
  730. X
  731. Xmain(argc, argv)
  732. X      char **argv ;
  733. X      {
  734. X      long t ;
  735. X      char *from, *lastc ;
  736. X      char to[PATHLEN] ;
  737. X      char **ap ;
  738. X      char prefix ;
  739. X      int fd ;
  740. X
  741. X      prefix = 'n' ;
  742. X      ap = argv + 1 ;
  743. X      if (ap[0][0] == '-' && ap[0][1] == 't') {
  744. X            if ((prefix = ap[0][2]) == '\0')
  745. Xusage:            fatal("usage: qnews [ -tc ] directory [ file ]") ;
  746. X            ap++ ;
  747. X      }
  748. X      if ((directory = *ap++) == NULL)
  749. X            goto usage ;
  750. X      from = *ap ;
  751. X      if (from != NULL && strcmp(from, "%s") == 0)
  752. X            from = NULL ;
  753. X      time(&t) ;
  754. X      sprintf(to, "%s/%c%lda", directory, prefix, t) ;
  755. X      lastc = to + strlen(to) - 1 ;
  756. X      signal(SIGTERM, SIG_IGN) ;
  757. X      for (;;) {
  758. X            if (from != NULL)
  759. X                  fd = link(from, to) ;
  760. X            else {
  761. X#ifdef USG
  762. X                  fd = open(to, O_WRONLY | O_CREAT | O_EXCL, 0444) ;
  763. X#else
  764. X                  fd = creat(to, 0444) ;
  765. X#endif
  766. X            }
  767. X            if (fd >= 0)
  768. X                  break ;
  769. X            if (errno != EEXIST && errno != EPERM || *lastc == 'z')
  770. X                  fatal("can't create %s", to) ;
  771. X            *lastc += 1 ;
  772. X      }
  773. X      if (from == NULL) {
  774. X            char buf[BUFSIZ] ;
  775. X            int count ;
  776. X
  777. X            file = to ;
  778. X            while ((count = read(0, buf, BUFSIZ)) > 0) {
  779. X                  if (write(fd, buf, count) != count) {
  780. X                        fatal("write error") ;
  781. X                  }
  782. X            }
  783. X            if (count < 0) {
  784. X                  fatal("read error") ;
  785. X            }
  786. X      }
  787. X      exit(0) ;
  788. X}
  789. X
  790. X
  791. X
  792. X/*
  793. X * Fatal error.
  794. X * Print error message and send mail to administrator.
  795. X */
  796. X
  797. Xfatal(fmt, a1, a2, a3, a4)
  798. X      char *fmt ;
  799. X      {
  800. X      static int reentered = 0 ;
  801. X
  802. X      if (reentered) {
  803. X            fprintf(stderr, "fatal entered recursively\n") ;
  804. X            fprintf(stderr, fmt, a1, a2, a3, a4) ;
  805. X            if (file != NULL)
  806. X                  unlink(file) ;
  807. X            exit(3) ;
  808. X      }
  809. X      reentered = 1 ;
  810. X      msg(fmt, a1, a2, a3, a4) ;
  811. X      if (file != NULL)
  812. X            if (unlink(file) < 0)
  813. X                  msg("unlink failed: %s", file) ;
  814. X      exit(2) ;
  815. X}
  816. X
  817. X
  818. X/*
  819. X * Send mail to administrator.  Flag is set to indicate fatal error.
  820. X */
  821. X
  822. Xmsg(fmt, a1, a2, a3, a4)
  823. X      char *fmt ;
  824. X      {
  825. X      FILE *fp ;
  826. X      int e = errno ;
  827. X
  828. X      fprintf(stderr, fmt, a1, a2, a3, a4) ;
  829. X      putc('\n', stderr) ;
  830. X      if ((fp = popen(MAILCMD, "w")) == NULL)
  831. X            fatal("popen failed") ;
  832. X      fputs("Subject:  error in qnews\n\n", fp) ;
  833. X      fprintf(fp, fmt, a1, a2, a3, a4) ;
  834. X      if (directory != NULL) {
  835. X            fputs("\nprocessing ", fp) ;
  836. X            fputs(directory, fp) ;
  837. X      }
  838. X      putc('\n', fp) ;
  839. X      fprintf(fp, "errno = %d\n", e) ;
  840. X      if (pclose(fp) != 0)
  841. X            fatal("msg failed") ;
  842. X}
  843. +FUNKY+STUFF+
  844. echo '-rw-r--r-- 1 wan        2853 Sep  9  1983 qnews.c    (as sent)'
  845. chmod u=rw,g=r,o=r qnews.c
  846. ls -l qnews.c
  847. echo x - recvnews.c
  848. sed 's/^X//' > recvnews.c <<'+FUNKY+STUFF+'
  849. X#define RECVNEWS 1
  850. X#include "common.h"
  851. X
  852. X#ifdef USG
  853. X#include <setjmp.h>
  854. X#define setexit() setjmp(nextdir)
  855. X#define reset() longjmp(nextdir, 1)
  856. Xjmp_buf nextdir ;    /* label to jump to on major error */
  857. X#endif
  858. X
  859. Xstruct arglist {
  860. X      int nargs ;
  861. X      char *arg[MAXARGS] ;
  862. X} ;
  863. X
  864. Xchar *directory ;    /* directory currently being processed */
  865. Xint errflag ;        /* set if any errors */
  866. Xchar lockfile[] = RECVLOCK ;
  867. X
  868. X
  869. X
  870. Xmain(argc, argv)
  871. Xchar **argv ;
  872. X{
  873. X      char **ap ;
  874. X
  875. X      nice(10) ;
  876. X      setuid(NETNEWS) ;        /* in case invoked as root by cron */
  877. X      if (setlock(lockfile) == 0) {
  878. X            printf("recvnews locked\n") ;
  879. X            exit(0) ;
  880. X      }
  881. X      ap = argv + 1 ;
  882. X      setexit() ;
  883. X      while (*ap != NULL) {
  884. X            directory = *ap++ ;
  885. X            if (chdir(directory) < 0)
  886. X                  fatal("directory nonexistant") ;
  887. X            inputnews() ;
  888. X            if (chdir("..") < 0) {
  889. X                  printf("can't chdir to %s/..\n", directory) ;
  890. X                  break ;
  891. X        }
  892. X      }
  893. X      if (unlink(lockfile) < 0)
  894. X            msg("can't unlink lock") ;
  895. X      exit(errflag) ;
  896. X}
  897. X
  898. X
  899. X
  900. Xinputnews() {
  901. X      struct arglist in ;
  902. X      DIR *dp ;
  903. X      struct direct *d ;
  904. X      int oflow ;
  905. X      int i ;
  906. X
  907. X      in.nargs = 0 ;
  908. X      oflow = 0 ;
  909. X      if (chdir("in") < 0)
  910. X            fatal("in missing") ;
  911. X      dp = opendir(".") ;
  912. X      if (dp == NULL)
  913. X            fatal("no .") ;
  914. X      while ((d = readdir(dp)) != NULL) {
  915. X            if (d->d_name[0] != '.') {
  916. X                  if (in.nargs < MAXARGS)
  917. X                        addarg(d->d_name, &in) ;
  918. X                  else
  919. X                        oflow++ ;
  920. X            }
  921. X      }
  922. X      if (oflow > 0)
  923. X            msg("%d articles not processed", oflow) ;
  924. X      closedir(dp) ;
  925. X      if (in.nargs == 0)
  926. X            goto out ;
  927. X      qsort((char *)in.arg, in.nargs, sizeof(char *), comp) ;
  928. X      sleep(5) ;        /* in case any files half written */
  929. X      for (i = 0 ; i < in.nargs ; i++) {
  930. X            procfile(in.arg[i]) ;
  931. X            free(in.arg[i]) ;
  932. X      }
  933. Xout:
  934. X      if (chdir("..") < 0)
  935. X            fatal("can't chdir ..") ;
  936. X}
  937. X
  938. X
  939. X
  940. Xprocfile(name)
  941. X      char *name ;
  942. X      {
  943. X      FILE *fp ;
  944. X      int rc ;
  945. X
  946. X      if (badname(name)) {
  947. X            msg("bad input file name %s", name) ;
  948. X            movebad(name) ;
  949. X            return ;
  950. X      }
  951. X      if ((fp = fopen(name, "r")) == NULL) {
  952. X            msg("unreadable file %s", name) ;
  953. X            movebad(name) ;
  954. X            return ;
  955. X      }
  956. X      switch (name[0]) {
  957. X      case 'a':
  958. X            rc = procack(name, fp) ;
  959. X            break ;
  960. X      case 'n':
  961. X            rc = procnews(name, fp) ;
  962. X            break ;
  963. X      case 'm':
  964. X            rc = procmail(name, fp) ;
  965. X            break ;
  966. X      default:
  967. X            fatal("can't happen %s", name) ;
  968. X            break ;
  969. X      }
  970. X      if (rc < 0)
  971. X            movebad(name) ;
  972. X      else if (unlink(name) < 0)
  973. X            msg("can't unlink %s", name) ;
  974. X      fclose(fp) ;
  975. X      if ((fp = fopen("../ackfile", "a")) == NULL)
  976. X            fatal("Can't open ackfile") ;
  977. X      fprintf(fp, "%s\n", name) ;
  978. X      fclose(fp) ;
  979. X}
  980. X
  981. X
  982. X
  983. Xprocnews(name, fp)
  984. X      char *name ;
  985. X      FILE *fp ;
  986. X      {
  987. X      char *arg[2] ;
  988. X
  989. X      arg[0] = RNEWS, arg[1] = NULL ;
  990. X      return chkrun(arg, name, fp) ;
  991. X}
  992. X
  993. X
  994. Xprocmail(name, fp)
  995. X      char *name ;
  996. X      FILE *fp ;
  997. X      {
  998. X      char *arg[4] ;
  999. X      char buf[DESTLEN] ;
  1000. X      char *p ;
  1001. X
  1002. X      setbuf(fp, NULL) ;        /* turn off buffering */
  1003. X      if (fgets(buf, DESTLEN, fp) == NULL) {
  1004. X            msg("%s: empty file", name) ;
  1005. X            return -1 ;
  1006. X      }
  1007. X      if (strncmp(buf, "To ", 3) != 0) {
  1008. X            msg("corrupted mail %s", name) ;
  1009. X            return -1 ;
  1010. X      }
  1011. X      if ((p = strchr(buf, '\n')) == NULL) {
  1012. X            msg("destination too long, file %s", name) ;
  1013. X            return -1 ;
  1014. X      }
  1015. X      *p = '\0' ;
  1016. X      arg[0] = RMAIL, arg[1] = buf + 3, arg[2] = NULL ;
  1017. X      return chkrun(arg, name, fp) ;
  1018. X}
  1019. X
  1020. X
  1021. X
  1022. Xprocack(name, fp)
  1023. X      char *name ;
  1024. X      FILE *fp ;
  1025. X      {
  1026. X      char line[FNLEN+2] ;
  1027. X      char *p ;
  1028. X
  1029. X      if (chdir("../sent") < 0)
  1030. X            fatal("no sent dir") ;
  1031. X      while (fgets(line, FNLEN + 2, fp) != NULL) {
  1032. X            if ((p = strchr(line, '\n')) == NULL) {
  1033. X                  msg("line too long, file %s", name) ;
  1034. Xbad:              if (chdir("../in") < 0)
  1035. X                        fatal("return to in") ;
  1036. X                  return -1 ;
  1037. X            }
  1038. X            *p = '\0' ;
  1039. X            if (badname(line)) {
  1040. X                  msg("bad file %s acked in %s", line, name) ;
  1041. X                  goto bad ;
  1042. X            }
  1043. X            if (unlink(line) < 0)
  1044. X                  printf("Can't unlink %s/in/%s, ack file %s\n",
  1045. X                        directory, line, name) ;
  1046. X      }
  1047. X      if (chdir("../in") < 0)
  1048. X            fatal("return to in") ;
  1049. X      if ((fp = fopen("../lastack", "w")) == NULL)
  1050. X            fatal("can't open lastack") ;
  1051. X      fprintf(fp, "%.9s\n", line + 1) ;
  1052. X      fclose(fp) ;
  1053. X      return 0 ;
  1054. X}
  1055. X
  1056. X
  1057. X
  1058. Xbadname(fname)
  1059. X      char *fname ;
  1060. X      {
  1061. X      register c ;
  1062. X
  1063. X      if ((c = *fname++) != 'a' && c != 'n' && c != 'm')
  1064. X            return -1 ;
  1065. X      if ((c = *fname++) < '0' || c > '9')
  1066. X            return -1 ;
  1067. X      return 0 ;
  1068. X}
  1069. X
  1070. X
  1071. X
  1072. Xmovebad(fname)
  1073. X      char *fname ;
  1074. X      {
  1075. X      char bad[PATHLEN] ;
  1076. X
  1077. X      sprintf(bad, "../bad/%s", fname) ;
  1078. X      unlink(bad) ;
  1079. X      if (link(fname, bad) < 0)
  1080. X            fatal("link to bad failed for %s", fname) ;
  1081. X      if (unlink(fname) < 0)
  1082. X            fatal("unlink bad file %s failed", fname) ;
  1083. X}
  1084. X
  1085. X
  1086. X
  1087. Xcomp(a, b)
  1088. X      char **a, **b ;
  1089. X      {
  1090. X      return strcmp(*a, *b) ;
  1091. X}
  1092. X
  1093. X
  1094. X
  1095. Xaddarg(fname, argl)
  1096. X      struct arglist *argl ;
  1097. X      char *fname ;
  1098. X      {
  1099. X      char *p ;
  1100. X
  1101. X      if (argl->nargs >= MAXARGS)
  1102. X            fatal("too many articles") ;
  1103. X      if (fname == NULL)
  1104. X            p = NULL ;
  1105. X      else {
  1106. X            if ((p = malloc(strlen(fname) + 1)) == NULL)
  1107. X                  fatal("out of space") ;
  1108. X            strcpy(p, fname) ;
  1109. X      }
  1110. X      argl->arg[argl->nargs++] = p ;
  1111. X}
  1112. X
  1113. X
  1114. X
  1115. X/*
  1116. X * Run a program, informing the system administrator if it fails.
  1117. X */
  1118. X
  1119. Xchkrun(arg, name, fp)
  1120. X      char *arg[] ;
  1121. X      char *name ;
  1122. X      FILE *fp ;
  1123. X      {
  1124. X      char *p ;
  1125. X      int outfd ;
  1126. X      int rc ;
  1127. X      FILE *mailfp ;
  1128. X      static char outfile[24] ;
  1129. X
  1130. X      if (outfile[0] == '\0')
  1131. X            sprintf(outfile, "/tmp/recvnews%d", getpid()) ;
  1132. X      if ((outfd = creat(outfile, 0666)) < 0)
  1133. X            fatal("Can't create %s", outfile) ;
  1134. X      rc = run(arg, fileno(fp), outfd) ;
  1135. X      close(outfd) ;
  1136. X      if (rc != 0) {
  1137. X            if ((mailfp = popen(MAILCMD, "w")) == NULL)
  1138. X                  fatal("Can't popen MAILCMD") ;
  1139. X            fprintf(mailfp, "Subject:  error in recvnews\n\n") ;
  1140. X            if ((rc & 0177) == 0) {
  1141. X                  fprintf(mailfp, "exit status %d from %s", rc >> 8, arg[0]) ;
  1142. X            } else {
  1143. X                  fprintf(mailfp, "%s died with signal %d", arg[0], rc & 0177) ;
  1144. X                  if (rc & 0200)
  1145. X                        fprintf(mailfp, " - core dumped") ;
  1146. X            }
  1147. X            fprintf(mailfp, "\nfile %s/bad/%s\n", directory, name) ;
  1148. X            if ((fp = fopen(outfile, "r")) == NULL)
  1149. X                  fprintf(mailfp, "Can't open %s\n", outfile) ;
  1150. X            else {
  1151. X                  fprintf(mailfp, "Output of program:\n") ;
  1152. X                  while ((rc = getc(fp)) != EOF)
  1153. X                        putc(rc, mailfp) ;
  1154. X                  fclose(fp) ;
  1155. X            }
  1156. X            pclose(mailfp) ;
  1157. X            if (unlink(outfile) < 0)
  1158. X                  msg("can't unlink %s", outfile) ;
  1159. X            return -1 ;
  1160. X      }
  1161. X      if (unlink(outfile) < 0)
  1162. X            msg("can't unlink %s", outfile) ;
  1163. X      return 0 ;
  1164. X}
  1165. X
  1166. X
  1167. X
  1168. Xrun(args, in, out)
  1169. X      char *args[] ;
  1170. X      int in, out ;
  1171. X      {
  1172. X      int pid ;
  1173. X      int status ;
  1174. X      int i ;
  1175. X
  1176. X#ifdef DEBUG
  1177. X      printf("run") ;                /*DEBUG*/
  1178. X      for (i = 0 ; args[i] != NULL ; i++)    /*DEBUG*/
  1179. X            printf(" %s", args[i]) ;        /*DEBUG*/
  1180. X      putchar('\n') ;                /*DEBUG*/
  1181. X#endif
  1182. X      if ((pid = fork()) == -1)
  1183. X            fatal("Cannot fork") ;
  1184. X      if (pid == 0) {
  1185. X            if (in != 0) {
  1186. X                  close(0) ;
  1187. X                  if (dup(in) != 0) {
  1188. X                        msg("Cannot redirect input") ;
  1189. X                        exit(127) ;
  1190. X                  }
  1191. X                  close(in) ;
  1192. X            }
  1193. X            if (out != 1) {
  1194. X                  close(1) ;
  1195. X                  if (dup(out) != 1) {
  1196. X                        msg("Cannot redirect output") ;
  1197. X                        exit(127) ;
  1198. X                  }
  1199. X                  close(out) ;
  1200. X                  close(2) ;
  1201. X                  if (dup(1) != 2) {
  1202. X                        msg("Cannot dup 1") ;
  1203. X                        exit(127) ;
  1204. X                  }
  1205. X            }
  1206. X            execv(args[0], args) ;
  1207. X            msg("exec failed") ;
  1208. X            exit(127) ;
  1209. X      }
  1210. X      while ((i = wait(&status)) != pid && i != -1) ;
  1211. X      return status ;
  1212. X}
  1213. X
  1214. X
  1215. X/*
  1216. X * Fatal error.
  1217. X * Print error message and send mail to administrator.
  1218. X */
  1219. X
  1220. Xfatal(fmt, a1, a2, a3, a4)
  1221. X      char *fmt ;
  1222. X      {
  1223. X      static int reentered = 0 ;
  1224. X
  1225. X      if (reentered) {
  1226. X            fprintf(stderr, "fatal entered recursively\n") ;
  1227. X            fprintf(stderr, fmt, a1, a2, a3, a4) ;
  1228. X            exit(3) ;
  1229. X      }
  1230. X      reentered = 1 ;
  1231. X      msg(fmt, a1, a2, a3, a4) ;
  1232. X      reentered = 0 ;
  1233. X      reset() ;
  1234. X}
  1235. X
  1236. X
  1237. X/*
  1238. X * Send mail to administrator.  Flag is set to indicate fatal error.
  1239. X */
  1240. X
  1241. Xmsg(fmt, a1, a2, a3, a4)
  1242. X      char *fmt ;
  1243. X      {
  1244. X      FILE *fp ;
  1245. X      int e = errno ;
  1246. X
  1247. X      errflag = 1 ;
  1248. X      fprintf(stderr, fmt, a1, a2, a3, a4) ;
  1249. X      putc('\n', stderr) ;
  1250. X      if ((fp = popen(MAILCMD, "w")) == NULL)
  1251. X            fatal("popen failed") ;
  1252. X      fputs("Subject:  error in recvnews\n\n", fp) ;
  1253. X      fprintf(fp, fmt, a1, a2, a3, a4) ;
  1254. X      if (directory != NULL) {
  1255. X            fputs("\nprocessing ", fp) ;
  1256. X            fputs(directory, fp) ;
  1257. X      }
  1258. X      putc('\n', fp) ;
  1259. X      fprintf(fp, "errno = %d\n", e) ;
  1260. X      if (pclose(fp) != 0)
  1261. X            fatal("msg failed") ;
  1262. X}
  1263. X
  1264. X
  1265. X
  1266. Xsetlock(name)
  1267. X      char *name ;
  1268. X      {
  1269. X      FILE *fp ;
  1270. X      char buf[10] ;
  1271. X
  1272. X      if ((fp = fopen(name, "r")) != NULL) {
  1273. X            if (fgets(buf, 10, fp) == NULL) {
  1274. X                  msg("empty lock file") ;
  1275. X                  fclose(fp) ;
  1276. X                  goto lock ;
  1277. X            }
  1278. X            fclose(fp) ;
  1279. X            if (buf[0] < '0' || buf[0] > '9') {
  1280. X                  msg("no pid in lock file") ;
  1281. X                  goto lock ;
  1282. X            }
  1283. X            if (! procexists(atoi(buf))) {
  1284. X                  msg("previous recvnews didn't remove lock") ;
  1285. X                  goto lock ;
  1286. X            }
  1287. X            return 0 ;
  1288. X      }
  1289. Xlock:
  1290. X      if ((fp = fopen(name, "w")) == NULL)
  1291. X            fatal("cannot create lock file") ;
  1292. X      fprintf(fp, "%d\n", getpid()) ;
  1293. X      fclose(fp) ;
  1294. X      return 1 ;
  1295. X}
  1296. +FUNKY+STUFF+
  1297. echo '-rw-r--r-- 1 wan       10786 Dec 15  1983 recvnews.c    (as sent)'
  1298. chmod u=rw,g=r,o=r recvnews.c
  1299. ls -l recvnews.c
  1300. echo x - sendnews.c
  1301. sed 's/^X//' > sendnews.c <<'+FUNKY+STUFF+'
  1302. X#define DEBUG
  1303. X#include "common.h"
  1304. X
  1305. X#define ASKIP 4
  1306. X
  1307. Xstruct arglist {
  1308. X      int nargs ;
  1309. X      char **first ;
  1310. X      char *arg[MAXARGS] ;
  1311. X} ;
  1312. X
  1313. Xstruct arglist uuargs ;
  1314. Xchar *directory ;
  1315. Xint errflag ;
  1316. Xchar resentflag[] = "resentflag" ;
  1317. Xchar lastack[] = "lastack" ;
  1318. Xchar ackfile[] = "ackfile" ;
  1319. X#ifndef NOTGATECH
  1320. Xint cflag ;
  1321. X#endif
  1322. X
  1323. X
  1324. X
  1325. Xmain(argc, argv)
  1326. X      char **argv ;
  1327. X      {
  1328. X      register char **ap ;
  1329. X      int rflag ;
  1330. X      char *p ;
  1331. X      int i ;
  1332. X      struct stat statb ;
  1333. X
  1334. X      setuid(NETNEWS) ;
  1335. X      ap = argv + 1 ;
  1336. X      rflag = 0 ;
  1337. X      while ((p = *ap++) != NULL && *p == '-') {
  1338. X            if (strcmp(p, "-r") == 0)
  1339. X                  rflag++ ;
  1340. X#ifndef NOTGATECH
  1341. X        else if (strcmp(p, "-c") == 0)
  1342. X          cflag++ ;
  1343. X#endif
  1344. X            else
  1345. Xusage:            fatal("usage: sendnews [ -r ] from to") ;
  1346. X      }
  1347. X      if (p == NULL || *ap == NULL)
  1348. X            goto usage ;
  1349. X      directory = p ;
  1350. X      if (chdir(p) < 0)
  1351. X            fatal("no directory") ;
  1352. X      uuargs.first = &uuargs.arg[ASKIP] ;
  1353. X      uuargs.nargs = ASKIP ;
  1354. X      if (unlink(resentflag) < 0) {
  1355. X            sendnews(1) ;
  1356. X      }
  1357. X      if (uuargs.nargs > ASKIP) {
  1358. X            if ((i = creat(resentflag, 0666)) < 0)
  1359. X                  msg("can't create resent flag") ;
  1360. X            close(i) ;
  1361. X            msg("resent %d files", uuargs.nargs - ASKIP) ;
  1362. X      }
  1363. X      sendnews(0) ;
  1364. X      if (stat(ackfile, &statb) >= 0
  1365. X       && (uuargs.nargs > ASKIP || statb.st_size >= MINACK)) {
  1366. X            long t ;
  1367. X            char buf[FNLEN + 5] ;
  1368. X
  1369. X            time(&t) ;
  1370. X            sprintf(buf, "sent/a%lda", t) ;
  1371. X            if (link(ackfile, buf) < 0) {
  1372. X                  msg("can't link ackfile") ;
  1373. X                  goto uu ;
  1374. X            }
  1375. X            if (unlink(ackfile) < 0) {
  1376. X                  msg("can't unlink ackfile") ;
  1377. X                  goto uu ;
  1378. X            }
  1379. X            insarg(buf + 5, &uuargs) ;
  1380. X      }
  1381. Xuu:
  1382. X      uucp(*ap, rflag) ;
  1383. X      exit(errflag) ;
  1384. X}
  1385. X
  1386. X
  1387. X
  1388. Xsendnews(resend) {
  1389. X      char *dir ;
  1390. X      char sentname[PATHLEN] ;
  1391. X      DIR *dp ;
  1392. X      FILE *fp ;
  1393. X      struct direct *d ;
  1394. X      long last ;
  1395. X      int oflow ;
  1396. X
  1397. X      if (resend == 0) {
  1398. X            dir = "out" ;
  1399. X      } else {
  1400. X            dir = "sent" ;
  1401. X            if ((fp = fopen(lastack, "r")) == NULL) {
  1402. X                  msg("can't open lastack") ;
  1403. X                  return ;
  1404. X            }
  1405. X            if (fgets(sentname, FNLEN, fp) == NULL) {
  1406. X                  /* Can occur bacause no locking done */
  1407. X                  msg("lastack is empty file") ;
  1408. X                  fclose(fp) ;
  1409. X                  return ;
  1410. X            }
  1411. X            fclose(fp) ;
  1412. X            last = atol(sentname) - 3600L ;
  1413. X      }
  1414. X      if (chdir(dir) < 0)
  1415. X            fatal("chdir %s failed", dir) ;
  1416. X      if ((dp = opendir(".")) == NULL)
  1417. X            fatal("no .") ;
  1418. X      oflow = 0 ;
  1419. X      while ((d = readdir(dp)) != NULL) {
  1420. X            if (d->d_name[0] == '.')
  1421. X                  continue ;
  1422. X            else if (badname(d->d_name)) {
  1423. X                  msg("bad file %s in %s", d->d_name, dir) ;
  1424. X                  movebad(d->d_name) ;
  1425. X                  continue ;
  1426. X            }
  1427. X            if (resend) {
  1428. X                  if (atol(d->d_name + 1) > last)
  1429. X                        continue ;
  1430. X                  printf("resending %s\n", d->d_name) ;
  1431. X            }
  1432. X            if (uuargs.nargs >= MAXARGS - 3) {
  1433. X                  oflow++ ;
  1434. X                  continue ;
  1435. X            }
  1436. X            addarg(d->d_name, &uuargs) ;
  1437. X            if (! resend) {
  1438. X                  sprintf(sentname, "../sent/%s", d->d_name) ;
  1439. X                  if (link(d->d_name, sentname) < 0)
  1440. X                        msg("link %s failed", d->d_name) ;
  1441. X                  else if (unlink(d->d_name) < 0)
  1442. X                        msg("unlink %s failed", d->d_name) ;
  1443. X            }
  1444. X      }
  1445. X      closedir(dp) ;
  1446. X      if (oflow > 0)
  1447. X            msg("too many files: %d not sent", oflow) ;
  1448. X      if (chdir("..") < 0)
  1449. X            fatal("no ..") ;
  1450. X}
  1451. X
  1452. X
  1453. X
  1454. Xuucp(to, rflag)
  1455. X      char *to ;
  1456. X      {
  1457. X      if (uuargs.first == uuargs.arg + uuargs.nargs)
  1458. X            return ;
  1459. X      if (chdir("sent") < 0)
  1460. X            fatal("no sent dir") ;
  1461. X      qsort((char *)(uuargs.arg + ASKIP), uuargs.nargs - ASKIP, sizeof(char *), comp) ;
  1462. X      addarg(to, &uuargs) ;
  1463. X      addarg(NULL, &uuargs) ;
  1464. X      if (rflag)  insarg("-r", &uuargs) ;
  1465. X#ifndef NOTGATECH
  1466. X      if (cflag)  insarg("-c", &uuargs) ;
  1467. X#endif
  1468. X      insarg(UUCP, &uuargs) ;
  1469. X      if (run(uuargs.first, 0, 0) != 0)
  1470. X            fatal("uucp failed") ;
  1471. X      if (chdir("..") < 0)
  1472. X            fatal("no ..") ;
  1473. X}
  1474. X
  1475. X
  1476. X
  1477. Xbadname(fname)
  1478. X      char *fname ;
  1479. X      {
  1480. X      register c ;
  1481. X
  1482. X      if ((c = *fname++) != 'a' && c != 'n' && c != 'm')
  1483. X            return -1 ;
  1484. X      if ((c = *fname++) < '0' || c > '9')
  1485. X            return -1 ;
  1486. X      return 0 ;
  1487. X}
  1488. X
  1489. X
  1490. X
  1491. Xmovebad(fname)
  1492. X      char *fname ;
  1493. X      {
  1494. X      char bad[PATHLEN] ;
  1495. X
  1496. X      sprintf(bad, "../bad/%s", fname) ;
  1497. X      unlink(bad) ;
  1498. X      if (link(fname, bad) < 0)
  1499. X            fatal("link to bad failed for %s", fname) ;
  1500. X      if (unlink(fname) < 0)
  1501. X            fatal("unlink bad file %s failed", fname) ;
  1502. X}
  1503. X
  1504. X
  1505. X
  1506. Xcomp(a, b)
  1507. X      char **a, **b ;
  1508. X      {
  1509. X      return strcmp(*a, *b) ;
  1510. X}
  1511. X
  1512. X
  1513. X
  1514. Xaddarg(fname, argl)
  1515. X      struct arglist *argl ;
  1516. X      char *fname ;
  1517. X      {
  1518. X      char *p ;
  1519. X
  1520. X      if (argl->nargs >= MAXARGS)
  1521. X            fatal("too many articles") ;
  1522. X      if (fname == NULL)
  1523. X            p = NULL ;
  1524. X      else {
  1525. X            if ((p = malloc(strlen(fname) + 1)) == NULL)
  1526. X                  fatal("out of space") ;
  1527. X            strcpy(p, fname) ;
  1528. X      }
  1529. X      argl->arg[argl->nargs++] = p ;
  1530. X}
  1531. X
  1532. X
  1533. Xinsarg(fname, argl)
  1534. X      struct arglist *argl ;
  1535. X      char *fname ;
  1536. X      {
  1537. X      char *p ;
  1538. X
  1539. X      if (argl->first <= argl->arg)
  1540. X            fatal("insarg failed") ;
  1541. X      if (fname == NULL)
  1542. X            p = NULL ;
  1543. X      else {
  1544. X            if ((p = malloc(strlen(fname) + 1)) == NULL)
  1545. X                  fatal("out of space") ;
  1546. X            strcpy(p, fname) ;
  1547. X      }
  1548. X      *--(argl->first) = p ;
  1549. X}
  1550. X
  1551. X
  1552. X
  1553. Xrun(args, flags, fd)
  1554. X      char *args[] ;
  1555. X      int flags ;
  1556. X      int fd ;
  1557. X      {
  1558. X      int pid ;
  1559. X      int status ;
  1560. X      int i ;
  1561. X
  1562. X#ifdef DEBUG
  1563. X      printf("run") ;                /*DEBUG*/
  1564. X      for (i = 0 ; args[i] != NULL ; i++)    /*DEBUG*/
  1565. X            printf(" %s", args[i]) ;        /*DEBUG*/
  1566. X      putchar('\n') ;                /*DEBUG*/
  1567. X#endif
  1568. X      if ((pid = fork()) == -1)
  1569. X            fatal("Cannot fork") ;
  1570. X      if (pid == 0) {
  1571. X            if (flags & SETIN) {
  1572. X                  close(0) ;
  1573. X                  if (dup(fd) != 0) {
  1574. X                        msg("Cannot redirect input") ;
  1575. X                        exit(127) ;
  1576. X                  }
  1577. X                  close(fd) ;
  1578. X            }
  1579. X            execv(args[0], args) ;
  1580. X            msg("exec failed") ;
  1581. X            exit(127) ;
  1582. X      }
  1583. X      while ((i = wait(&status)) != pid && i != -1) ;
  1584. X      return status ;
  1585. X}
  1586. X
  1587. X
  1588. X/*
  1589. X * Fatal error.
  1590. X * Print error message and send mail to administrator.
  1591. X */
  1592. X
  1593. Xfatal(fmt, a1, a2, a3, a4)
  1594. X      char *fmt ;
  1595. X      {
  1596. X      static int reentered = 0 ;
  1597. X
  1598. X      if (reentered) {
  1599. X            fprintf(stderr, "fatal entered recursively\n") ;
  1600. X            fprintf(stderr, fmt, a1, a2, a3, a4) ;
  1601. X            exit(3) ;
  1602. X      }
  1603. X      reentered = 1 ;
  1604. X      msg(fmt, a1, a2, a3, a4) ;
  1605. X      exit(2) ;
  1606. X}
  1607. X
  1608. X
  1609. X/*
  1610. X * Send mail to administrator.  Flag is set to indicate fatal error.
  1611. X */
  1612. X
  1613. Xmsg(fmt, a1, a2, a3, a4)
  1614. X      char *fmt ;
  1615. X      {
  1616. X      FILE *fp ;
  1617. X
  1618. X      errflag = 1 ;
  1619. X      fprintf(stderr, fmt, a1, a2, a3, a4) ;
  1620. X      putc('\n', stderr) ;
  1621. X      if ((fp = popen(MAILCMD, "w")) == NULL)
  1622. X            fatal("popen failed") ;
  1623. X      fputs("Subject:  error in sendnews\n\n", fp) ;
  1624. X      fprintf(fp, fmt, a1, a2, a3, a4) ;
  1625. X      if (directory != NULL) {
  1626. X            fputs("\nprocessing ", fp) ;
  1627. X            fputs(directory, fp) ;
  1628. X      }
  1629. X      putc('\n', fp) ;
  1630. X      if (pclose(fp) != 0)
  1631. X            fatal("msg failed") ;
  1632. X}
  1633. +FUNKY+STUFF+
  1634. echo '-rw-r--r-- 1 wan        7817 Nov 29  1983 sendnews.c    (as sent)'
  1635. chmod u=rw,g=r,o=r sendnews.c
  1636. ls -l sendnews.c
  1637. exit 0
  1638.  
  1639.  
  1640.