queue.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:67k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #include <sendmail.h>
  14. #ifndef lint
  15. # if QUEUE
  16. static char id[] = "@(#)$Id: queue.c,v 8.329 1999/12/06 21:17:01 ca Exp $ (with queueing)";
  17. # else /* QUEUE */
  18. static char id[] = "@(#)$Id: queue.c,v 8.329 1999/12/06 21:17:01 ca Exp $ (without queueing)";
  19. # endif /* QUEUE */
  20. #endif /* ! lint */
  21. #include <dirent.h>
  22. #if QUEUE
  23. # if _FFR_QUEUEDELAY
  24. #  define QF_VERSION 4 /* version number of this queue format */
  25. static time_t queuedelay __P((ENVELOPE *));
  26. # else /* _FFR_QUEUEDELAY */
  27. #  define QF_VERSION 3 /* version number of this queue format */
  28. #  define queuedelay(e) MinQueueAge
  29. # endif /* _FFR_QUEUEDELAY */
  30. /*
  31. **  Work queue.
  32. */
  33. struct work
  34. {
  35. char *w_name; /* name of control file */
  36. char *w_host; /* name of recipient host */
  37. bool w_lock; /* is message locked? */
  38. bool w_tooyoung; /* is it too young to run? */
  39. long w_pri; /* priority of message, see below */
  40. time_t w_ctime; /* creation time of message */
  41. struct work *w_next; /* next in queue */
  42. };
  43. typedef struct work WORK;
  44. static WORK *WorkQ; /* queue of things to be done */
  45. static void grow_wlist __P((int));
  46. static int orderq __P((int, bool));
  47. static void printctladdr __P((ADDRESS *, FILE *));
  48. static int print_single_queue __P((int));
  49. static bool readqf __P((ENVELOPE *));
  50. static void runqueueevent __P((void));
  51. static int run_single_queue __P((int, bool, bool));
  52. static char *strrev __P((char *));
  53. static ADDRESS *setctluser __P((char *, int));
  54. static int workcmpf0();
  55. static int workcmpf1();
  56. static int workcmpf2();
  57. static int workcmpf3();
  58. static int workcmpf4();
  59. /*
  60. **  QUEUEUP -- queue a message up for future transmission.
  61. **
  62. ** Parameters:
  63. ** e -- the envelope to queue up.
  64. ** announce -- if TRUE, tell when you are queueing up.
  65. **
  66. ** Returns:
  67. ** none.
  68. **
  69. ** Side Effects:
  70. ** The current request are saved in a control file.
  71. ** The queue file is left locked.
  72. */
  73. void
  74. queueup(e, announce)
  75. register ENVELOPE *e;
  76. bool announce;
  77. {
  78. char *qf;
  79. register FILE *tfp;
  80. register HDR *h;
  81. register ADDRESS *q;
  82. int tfd = -1;
  83. int i;
  84. bool newid;
  85. register char *p;
  86. MAILER nullmailer;
  87. MCI mcibuf;
  88. char tf[MAXPATHLEN];
  89. char buf[MAXLINE];
  90. /*
  91. **  Create control file.
  92. */
  93. newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
  94. /* if newid, queuename will create a locked qf file in e->lockfp */
  95. (void) strlcpy(tf, queuename(e, 't'), sizeof tf);
  96. tfp = e->e_lockfp;
  97. if (tfp == NULL)
  98. newid = FALSE;
  99. /* if newid, just write the qf file directly (instead of tf file) */
  100. if (!newid)
  101. {
  102. /* get a locked tf file */
  103. for (i = 0; i < 128; i++)
  104. {
  105. tfd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
  106. if (tfd < 0)
  107. {
  108. if (errno != EEXIST)
  109. break;
  110. if (LogLevel > 0 && (i % 32) == 0)
  111. sm_syslog(LOG_ALERT, e->e_id,
  112.   "queueup: cannot create %s, uid=%d: %s",
  113.   tf, geteuid(), errstring(errno));
  114. }
  115. else
  116. {
  117. if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
  118. break;
  119. else if (LogLevel > 0 && (i % 32) == 0)
  120. sm_syslog(LOG_ALERT, e->e_id,
  121.   "queueup: cannot lock %s: %s",
  122.   tf, errstring(errno));
  123. (void) close(tfd);
  124. }
  125. if ((i % 32) == 31)
  126. {
  127. /* save the old temp file away */
  128. (void) rename(tf, queuename(e, 'T'));
  129. }
  130. else
  131. (void) sleep(i % 32);
  132. }
  133. if (tfd < 0 || (tfp = fdopen(tfd, "w")) == NULL)
  134. {
  135. int save_errno = errno;
  136. printopenfds(TRUE);
  137. errno = save_errno;
  138. syserr("!queueup: cannot create queue temp file %s, uid=%d",
  139. tf, geteuid());
  140. }
  141. }
  142. if (tTd(40, 1))
  143. dprintf("n>>>>> queueing %s/qf%s%s >>>>>n",
  144. qid_printqueue(e->e_queuedir), e->e_id,
  145. newid ? " (new id)" : "");
  146. if (tTd(40, 3))
  147. {
  148. dprintf("  e_flags=");
  149. printenvflags(e);
  150. }
  151. if (tTd(40, 32))
  152. {
  153. dprintf("  sendq=");
  154. printaddr(e->e_sendqueue, TRUE);
  155. }
  156. if (tTd(40, 9))
  157. {
  158. dprintf("  tfp=");
  159. dumpfd(fileno(tfp), TRUE, FALSE);
  160. dprintf("  lockfp=");
  161. if (e->e_lockfp == NULL)
  162. dprintf("NULLn");
  163. else
  164. dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
  165. }
  166. /*
  167. **  If there is no data file yet, create one.
  168. */
  169. if (bitset(EF_HAS_DF, e->e_flags))
  170. {
  171. if (e->e_dfp != NULL && bfcommit(e->e_dfp) < 0)
  172. syserr("!queueup: cannot commit data file %s, uid=%d",
  173. queuename(e, 'd'), geteuid());
  174. }
  175. else
  176. {
  177. int dfd;
  178. register FILE *dfp = NULL;
  179. char dfname[MAXPATHLEN];
  180. struct stat stbuf;
  181. if (e->e_dfp != NULL && bftest(e->e_dfp))
  182. syserr("committing over bf file");
  183. (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
  184. dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
  185. if (dfd < 0 || (dfp = fdopen(dfd, "w")) == NULL)
  186. syserr("!queueup: cannot create data temp file %s, uid=%d",
  187. dfname, geteuid());
  188. if (fstat(dfd, &stbuf) < 0)
  189. e->e_dfino = -1;
  190. else
  191. {
  192. e->e_dfdev = stbuf.st_dev;
  193. e->e_dfino = stbuf.st_ino;
  194. }
  195. e->e_flags |= EF_HAS_DF;
  196. memset(&mcibuf, '', sizeof mcibuf);
  197. mcibuf.mci_out = dfp;
  198. mcibuf.mci_mailer = FileMailer;
  199. (*e->e_putbody)(&mcibuf, e, NULL);
  200. if (fclose(dfp) < 0)
  201. syserr("!queueup: cannot save data temp file %s, uid=%d",
  202. dfname, geteuid());
  203. e->e_putbody = putbody;
  204. }
  205. /*
  206. **  Output future work requests.
  207. ** Priority and creation time should be first, since
  208. ** they are required by orderq.
  209. */
  210. /* output queue version number (must be first!) */
  211. fprintf(tfp, "V%dn", QF_VERSION);
  212. /* output creation time */
  213. fprintf(tfp, "T%ldn", (long) e->e_ctime);
  214. /* output last delivery time */
  215. # if _FFR_QUEUEDELAY
  216. fprintf(tfp, "K%ldn", (long) e->e_dtime);
  217. fprintf(tfp, "G%dn", e->e_queuealg);
  218. fprintf(tfp, "Y%ldn", (long) e->e_queuedelay);
  219. if (tTd(40, 64))
  220. sm_syslog(LOG_INFO, e->e_id,
  221. "queue alg: %d delay %ld next: %ld (now: %ld)n",
  222. e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime());
  223. # else /* _FFR_QUEUEDELAY */
  224. fprintf(tfp, "K%ldn", (long) e->e_dtime);
  225. # endif /* _FFR_QUEUEDELAY */
  226. /* output number of delivery attempts */
  227. fprintf(tfp, "N%dn", e->e_ntries);
  228. /* output message priority */
  229. fprintf(tfp, "P%ldn", e->e_msgpriority);
  230. /* output inode number of data file */
  231. /* XXX should probably include device major/minor too */
  232. if (e->e_dfino != -1)
  233. {
  234. /*CONSTCOND*/
  235. if (sizeof e->e_dfino > sizeof(long))
  236. fprintf(tfp, "I%ld/%ld/%sn",
  237. (long) major(e->e_dfdev),
  238. (long) minor(e->e_dfdev),
  239. quad_to_string(e->e_dfino));
  240. else
  241. fprintf(tfp, "I%ld/%ld/%lun",
  242. (long) major(e->e_dfdev),
  243. (long) minor(e->e_dfdev),
  244. (unsigned long) e->e_dfino);
  245. }
  246. /* output body type */
  247. if (e->e_bodytype != NULL)
  248. fprintf(tfp, "B%sn", denlstring(e->e_bodytype, TRUE, FALSE));
  249. # if _FFR_SAVE_CHARSET
  250. if (e->e_charset != NULL)
  251. fprintf(tfp, "X%sn", denlstring(e->e_charset, TRUE, FALSE));
  252. # endif /* _FFR_SAVE_CHARSET */
  253. /* message from envelope, if it exists */
  254. if (e->e_message != NULL)
  255. fprintf(tfp, "M%sn", denlstring(e->e_message, TRUE, FALSE));
  256. /* send various flag bits through */
  257. p = buf;
  258. if (bitset(EF_WARNING, e->e_flags))
  259. *p++ = 'w';
  260. if (bitset(EF_RESPONSE, e->e_flags))
  261. *p++ = 'r';
  262. if (bitset(EF_HAS8BIT, e->e_flags))
  263. *p++ = '8';
  264. if (bitset(EF_DELETE_BCC, e->e_flags))
  265. *p++ = 'b';
  266. if (bitset(EF_RET_PARAM, e->e_flags))
  267. *p++ = 'd';
  268. if (bitset(EF_NO_BODY_RETN, e->e_flags))
  269. *p++ = 'n';
  270. *p++ = '';
  271. if (buf[0] != '')
  272. fprintf(tfp, "F%sn", buf);
  273. /* save $={persistentMacros} macro values */
  274. queueup_macros(macid("{persistentMacros}", NULL), tfp, e);
  275. /* output name of sender */
  276. if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
  277. p = e->e_sender;
  278. else
  279. p = e->e_from.q_paddr;
  280. fprintf(tfp, "S%sn", denlstring(p, TRUE, FALSE));
  281. /* output ESMTP-supplied "original" information */
  282. if (e->e_envid != NULL)
  283. fprintf(tfp, "Z%sn", denlstring(e->e_envid, TRUE, FALSE));
  284. /* output AUTH= parameter */
  285. if (e->e_auth_param != NULL)
  286. fprintf(tfp, "A%sn", denlstring(e->e_auth_param,
  287.  TRUE, FALSE));
  288. /* output list of recipient addresses */
  289. printctladdr(NULL, NULL);
  290. for (q = e->e_sendqueue; q != NULL; q = q->q_next)
  291. {
  292. if (!QS_IS_UNDELIVERED(q->q_state))
  293. continue;
  294. printctladdr(q, tfp);
  295. if (q->q_orcpt != NULL)
  296. fprintf(tfp, "Q%sn",
  297. denlstring(q->q_orcpt, TRUE, FALSE));
  298. (void) putc('R', tfp);
  299. if (bitset(QPRIMARY, q->q_flags))
  300. (void) putc('P', tfp);
  301. if (bitset(QHASNOTIFY, q->q_flags))
  302. (void) putc('N', tfp);
  303. if (bitset(QPINGONSUCCESS, q->q_flags))
  304. (void) putc('S', tfp);
  305. if (bitset(QPINGONFAILURE, q->q_flags))
  306. (void) putc('F', tfp);
  307. if (bitset(QPINGONDELAY, q->q_flags))
  308. (void) putc('D', tfp);
  309. (void) putc(':', tfp);
  310. (void) fprintf(tfp, "%sn", denlstring(q->q_paddr, TRUE, FALSE));
  311. if (announce)
  312. {
  313. e->e_to = q->q_paddr;
  314. message("queued");
  315. if (LogLevel > 8)
  316. logdelivery(q->q_mailer, NULL, "queued",
  317.     NULL, (time_t) 0, e);
  318. e->e_to = NULL;
  319. }
  320. if (tTd(40, 1))
  321. {
  322. dprintf("queueing ");
  323. printaddr(q, FALSE);
  324. }
  325. }
  326. /*
  327. **  Output headers for this message.
  328. ** Expand macros completely here.  Queue run will deal with
  329. ** everything as absolute headers.
  330. ** All headers that must be relative to the recipient
  331. ** can be cracked later.
  332. ** We set up a "null mailer" -- i.e., a mailer that will have
  333. ** no effect on the addresses as they are output.
  334. */
  335. memset((char *) &nullmailer, '', sizeof nullmailer);
  336. nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
  337. nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
  338. nullmailer.m_eol = "n";
  339. memset(&mcibuf, '', sizeof mcibuf);
  340. mcibuf.mci_mailer = &nullmailer;
  341. mcibuf.mci_out = tfp;
  342. define('g', "201f", e);
  343. for (h = e->e_header; h != NULL; h = h->h_link)
  344. {
  345. if (h->h_value == NULL)
  346. continue;
  347. /* don't output resent headers on non-resent messages */
  348. if (bitset(H_RESENT, h->h_flags) &&
  349.     !bitset(EF_RESENT, e->e_flags))
  350. continue;
  351. /* expand macros; if null, don't output header at all */
  352. if (bitset(H_DEFAULT, h->h_flags))
  353. {
  354. (void) expand(h->h_value, buf, sizeof buf, e);
  355. if (buf[0] == '')
  356. continue;
  357. }
  358. /* output this header */
  359. fprintf(tfp, "H");
  360. /* if conditional, output the set of conditions */
  361. if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
  362. {
  363. int j;
  364. (void) putc('?', tfp);
  365. for (j = ''; j <= '177'; j++)
  366. if (bitnset(j, h->h_mflags))
  367. (void) putc(j, tfp);
  368. (void) putc('?', tfp);
  369. }
  370. /* output conditional macro if present */
  371. if (h->h_macro != '')
  372. {
  373. if (bitset(0200, h->h_macro))
  374. fprintf(tfp, "${%s}",
  375. macname(h->h_macro & 0377));
  376. else
  377. fprintf(tfp, "$%c", h->h_macro);
  378. }
  379. /* output the header: expand macros, convert addresses */
  380. if (bitset(H_DEFAULT, h->h_flags) &&
  381.     !bitset(H_BINDLATE, h->h_flags))
  382. {
  383. fprintf(tfp, "%s: %sn",
  384. h->h_field,
  385. denlstring(buf, FALSE, TRUE));
  386. }
  387. else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
  388.  !bitset(H_BINDLATE, h->h_flags))
  389. {
  390. bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
  391. FILE *savetrace = TrafficLogFile;
  392. TrafficLogFile = NULL;
  393. if (bitset(H_FROM, h->h_flags))
  394. oldstyle = FALSE;
  395. commaize(h, h->h_value, oldstyle, &mcibuf, e);
  396. TrafficLogFile = savetrace;
  397. }
  398. else
  399. {
  400. fprintf(tfp, "%s: %sn",
  401. h->h_field,
  402. denlstring(h->h_value, FALSE, TRUE));
  403. }
  404. }
  405. /*
  406. **  Clean up.
  407. **
  408. ** Write a terminator record -- this is to prevent
  409. ** scurrilous crackers from appending any data.
  410. */
  411. fprintf(tfp, ".n");
  412. if (fflush(tfp) < 0 ||
  413.     (SuperSafe && fsync(fileno(tfp)) < 0) ||
  414.     ferror(tfp))
  415. {
  416. if (newid)
  417. syserr("!552 Error writing control file %s", tf);
  418. else
  419. syserr("!452 Error writing control file %s", tf);
  420. }
  421. if (!newid)
  422. {
  423. /* rename (locked) tf to be (locked) qf */
  424. qf = queuename(e, 'q');
  425. if (rename(tf, qf) < 0)
  426. syserr("cannot rename(%s, %s), uid=%d",
  427. tf, qf, geteuid());
  428. /*
  429. **  fsync() after renaming to make sure
  430. **  metadata is written to disk on
  431. **  filesystems in which renames are
  432. **  not guaranteed such as softupdates.
  433. */
  434. if (tfd >= 0 && SuperSafe && fsync(tfd) < 0)
  435. syserr("!queueup: cannot fsync queue temp file %s",
  436.        tf);
  437. /* close and unlock old (locked) qf */
  438. if (e->e_lockfp != NULL)
  439. (void) fclose(e->e_lockfp);
  440. e->e_lockfp = tfp;
  441. }
  442. else
  443. qf = tf;
  444. errno = 0;
  445. e->e_flags |= EF_INQUEUE;
  446. /* save log info */
  447. if (LogLevel > 79)
  448. sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
  449. if (tTd(40, 1))
  450. dprintf("<<<<< done queueing %s <<<<<nn", e->e_id);
  451. return;
  452. }
  453. static void
  454. printctladdr(a, tfp)
  455. register ADDRESS *a;
  456. FILE *tfp;
  457. {
  458. char *user;
  459. register ADDRESS *q;
  460. uid_t uid;
  461. gid_t gid;
  462. static ADDRESS *lastctladdr = NULL;
  463. static uid_t lastuid;
  464. /* initialization */
  465. if (a == NULL || a->q_alias == NULL || tfp == NULL)
  466. {
  467. if (lastctladdr != NULL && tfp != NULL)
  468. fprintf(tfp, "Cn");
  469. lastctladdr = NULL;
  470. lastuid = 0;
  471. return;
  472. }
  473. /* find the active uid */
  474. q = getctladdr(a);
  475. if (q == NULL)
  476. {
  477. user = NULL;
  478. uid = 0;
  479. gid = 0;
  480. }
  481. else
  482. {
  483. user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
  484. uid = q->q_uid;
  485. gid = q->q_gid;
  486. }
  487. a = a->q_alias;
  488. /* check to see if this is the same as last time */
  489. if (lastctladdr != NULL && uid == lastuid &&
  490.     strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
  491. return;
  492. lastuid = uid;
  493. lastctladdr = a;
  494. if (uid == 0 || user == NULL || user[0] == '')
  495. fprintf(tfp, "C");
  496. else
  497. fprintf(tfp, "C%s:%ld:%ld",
  498. denlstring(user, TRUE, FALSE), (long) uid, (long) gid);
  499. fprintf(tfp, ":%sn", denlstring(a->q_paddr, TRUE, FALSE));
  500. }
  501. /*
  502. **  RUNQUEUE -- run the jobs in the queue.
  503. **
  504. ** Gets the stuff out of the queue in some presumably logical
  505. ** order and processes them.
  506. **
  507. ** Parameters:
  508. ** forkflag -- TRUE if the queue scanning should be done in
  509. ** a child process.  We double-fork so it is not our
  510. ** child and we don't have to clean up after it.
  511. ** verbose -- if TRUE, print out status information.
  512. **
  513. ** Returns:
  514. ** TRUE if the queue run successfully began.
  515. **
  516. ** Side Effects:
  517. ** runs things in the mail queue.
  518. */
  519. static ENVELOPE QueueEnvelope; /* the queue run envelope */
  520. static int NumQueues = 0;
  521. static time_t LastQueueTime = 0; /* last time a queue ID assigned */
  522. static pid_t LastQueuePid = -1; /* last PID which had a queue ID */
  523. struct qpaths_s
  524. {
  525. char *qp_name; /* name of queue dir */
  526. short qp_subdirs; /* use subdirs? */
  527. };
  528. typedef struct qpaths_s QPATHS;
  529. /* values for qp_supdirs */
  530. #define QP_NOSUB 0x0000 /* No subdirectories */
  531. #define QP_SUBDF 0x0001 /* "df" subdirectory */
  532. #define QP_SUBQF 0x0002 /* "qf" subdirectory */
  533. #define QP_SUBXF 0x0004 /* "xf" subdirectory */
  534. static QPATHS *QPaths = NULL; /* list of queue directories */
  535. bool
  536. runqueue(forkflag, verbose)
  537. bool forkflag;
  538. bool verbose;
  539. {
  540. int i;
  541. bool ret = TRUE;
  542. static int curnum = 0;
  543. for (i = 0; i < NumQueues; i++)
  544. {
  545. /*
  546. **  Pick up where we left off, in case we
  547. **  used up all the children last time
  548. **  without finishing.
  549. */
  550. ret = run_single_queue(curnum, forkflag, verbose);
  551. /*
  552. **  Failure means a message was printed for ETRN
  553. **  and subsequent queues are likely to fail as well.
  554. */
  555. if (!ret)
  556. break;
  557. if (++curnum >= NumQueues)
  558. curnum = 0;
  559. }
  560. if (QueueIntvl != 0)
  561. (void) setevent(QueueIntvl, runqueueevent, 0);
  562. return ret;
  563. }
  564. /*
  565. **  RUN_SINGLE_QUEUE -- run the jobs in a single queue.
  566. **
  567. ** Gets the stuff out of the queue in some presumably logical
  568. ** order and processes them.
  569. **
  570. ** Parameters:
  571. ** queuedir -- queue to process
  572. ** forkflag -- TRUE if the queue scanning should be done in
  573. ** a child process.  We double-fork so it is not our
  574. ** child and we don't have to clean up after it.
  575. ** verbose -- if TRUE, print out status information.
  576. **
  577. ** Returns:
  578. ** TRUE if the queue run successfully began.
  579. **
  580. ** Side Effects:
  581. ** runs things in the mail queue.
  582. */
  583. static bool
  584. run_single_queue(queuedir, forkflag, verbose)
  585. int queuedir;
  586. bool forkflag;
  587. bool verbose;
  588. {
  589. register ENVELOPE *e;
  590. int njobs;
  591. int sequenceno = 0;
  592. time_t current_la_time;
  593. extern ENVELOPE BlankEnvelope;
  594. DoQueueRun = FALSE;
  595. /*
  596. **  If no work will ever be selected, don't even bother reading
  597. **  the queue.
  598. */
  599. CurrentLA = sm_getla(NULL); /* get load average */
  600. current_la_time = curtime();
  601. if (shouldqueue(WkRecipFact, current_la_time))
  602. {
  603. char *msg = "Skipping queue run -- load average too high";
  604. if (verbose)
  605. message("458 %sn", msg);
  606. if (LogLevel > 8)
  607. sm_syslog(LOG_INFO, NOQID,
  608.   "runqueue: %s",
  609.   msg);
  610. return FALSE;
  611. }
  612. /*
  613. **  See if we already have too many children.
  614. */
  615. if (forkflag && QueueIntvl != 0 &&
  616.     MaxChildren > 0 && CurChildren >= MaxChildren)
  617. {
  618. char *msg = "Skipping queue run -- too many children";
  619. if (verbose)
  620. message("458 %s (%d)n", msg, CurChildren);
  621. if (LogLevel > 8)
  622. sm_syslog(LOG_INFO, NOQID,
  623.   "runqueue: %s (%d)",
  624.   msg, CurChildren);
  625. return FALSE;
  626. }
  627. /*
  628. **  See if we want to go off and do other useful work.
  629. */
  630. if (forkflag)
  631. {
  632. pid_t pid;
  633. (void) blocksignal(SIGCHLD);
  634. (void) setsignal(SIGCHLD, reapchild);
  635. pid = dofork();
  636. if (pid == -1)
  637. {
  638. const char *msg = "Skipping queue run -- fork() failed";
  639. const char *err = errstring(errno);
  640. if (verbose)
  641. message("458 %s: %sn", msg, err);
  642. if (LogLevel > 8)
  643. sm_syslog(LOG_INFO, NOQID,
  644.   "runqueue: %s: %s",
  645.   msg, err);
  646. (void) releasesignal(SIGCHLD);
  647. return FALSE;
  648. }
  649. if (pid != 0)
  650. {
  651. /* parent -- pick up intermediate zombie */
  652. (void) blocksignal(SIGALRM);
  653. proc_list_add(pid, "Queue runner", PROC_QUEUE);
  654. (void) releasesignal(SIGALRM);
  655. (void) releasesignal(SIGCHLD);
  656. return TRUE;
  657. }
  658. /* child -- clean up signals */
  659. clrcontrol();
  660. proc_list_clear();
  661. /* Add parent process as first child item */
  662. proc_list_add(getpid(), "Queue runner child process",
  663.       PROC_QUEUE_CHILD);
  664. (void) releasesignal(SIGCHLD);
  665. (void) setsignal(SIGCHLD, SIG_DFL);
  666. (void) setsignal(SIGHUP, intsig);
  667. }
  668. sm_setproctitle(TRUE, CurEnv, "running queue: %s",
  669. qid_printqueue(queuedir));
  670. if (LogLevel > 69 || tTd(63, 99))
  671. sm_syslog(LOG_DEBUG, NOQID,
  672.   "runqueue %s, pid=%d, forkflag=%d",
  673.   qid_printqueue(queuedir), getpid(), forkflag);
  674. /*
  675. **  Release any resources used by the daemon code.
  676. */
  677. # if DAEMON
  678. clrdaemon();
  679. # endif /* DAEMON */
  680. /* force it to run expensive jobs */
  681. NoConnect = FALSE;
  682. /* drop privileges */
  683. if (geteuid() == (uid_t) 0)
  684. (void) drop_privileges(FALSE);
  685. /*
  686. **  Create ourselves an envelope
  687. */
  688. CurEnv = &QueueEnvelope;
  689. e = newenvelope(&QueueEnvelope, CurEnv);
  690. e->e_flags = BlankEnvelope.e_flags;
  691. /* make sure we have disconnected from parent */
  692. if (forkflag)
  693. {
  694. disconnect(1, e);
  695. QuickAbort = FALSE;
  696. }
  697. /*
  698. **  If we are running part of the queue, always ignore stored
  699. **  host status.
  700. */
  701. if (QueueLimitId != NULL || QueueLimitSender != NULL ||
  702.     QueueLimitRecipient != NULL)
  703. {
  704. IgnoreHostStatus = TRUE;
  705. MinQueueAge = 0;
  706. }
  707. /*
  708. **  Start making passes through the queue.
  709. ** First, read and sort the entire queue.
  710. ** Then, process the work in that order.
  711. ** But if you take too long, start over.
  712. */
  713. /* order the existing work requests */
  714. njobs = orderq(queuedir, FALSE);
  715. /* process them once at a time */
  716. while (WorkQ != NULL)
  717. {
  718. WORK *w = WorkQ;
  719. WorkQ = WorkQ->w_next;
  720. e->e_to = NULL;
  721. /*
  722. **  Ignore jobs that are too expensive for the moment.
  723. **
  724. ** Get new load average every 30 seconds.
  725. */
  726. if (current_la_time < curtime() - 30)
  727. {
  728. CurrentLA = sm_getla(e);
  729. current_la_time = curtime();
  730. }
  731. if (shouldqueue(WkRecipFact, current_la_time))
  732. {
  733. char *msg = "Aborting queue run: load average too high";
  734. if (Verbose)
  735. message("%s", msg);
  736. if (LogLevel > 8)
  737. sm_syslog(LOG_INFO, NOQID,
  738.   "runqueue: %s",
  739.   msg);
  740. break;
  741. }
  742. sequenceno++;
  743. if (shouldqueue(w->w_pri, w->w_ctime))
  744. {
  745. if (Verbose)
  746. message("");
  747. if (QueueSortOrder == QSO_BYPRIORITY)
  748. {
  749. if (Verbose)
  750. message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
  751. qid_printqueue(queuedir),
  752. w->w_name + 2,
  753. sequenceno,
  754. njobs);
  755. if (LogLevel > 8)
  756. sm_syslog(LOG_INFO, NOQID,
  757.   "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
  758.   qid_printqueue(queuedir),
  759.   w->w_name + 2,
  760.   w->w_pri,
  761.   CurrentLA,
  762.   sequenceno,
  763.   njobs);
  764. break;
  765. }
  766. else if (Verbose)
  767. message("Skipping %s/%s (sequence %d of %d)",
  768. qid_printqueue(queuedir),
  769. w->w_name + 2,
  770. sequenceno, njobs);
  771. }
  772. else
  773. {
  774. pid_t pid;
  775. if (Verbose)
  776. {
  777. message("");
  778. message("Running %s/%s (sequence %d of %d)",
  779. qid_printqueue(queuedir),
  780. w->w_name + 2,
  781. sequenceno, njobs);
  782. }
  783. if (tTd(63, 100))
  784. sm_syslog(LOG_DEBUG, NOQID,
  785.   "runqueue %s dowork(%s)",
  786.   qid_printqueue(queuedir),
  787.   w->w_name + 2);
  788. pid = dowork(queuedir, w->w_name + 2,
  789.      ForkQueueRuns, FALSE, e);
  790. errno = 0;
  791. if (pid != 0)
  792. (void) waitfor(pid);
  793. }
  794. free(w->w_name);
  795. if (w->w_host)
  796. free(w->w_host);
  797. free((char *) w);
  798. }
  799. /* exit without the usual cleanup */
  800. e->e_id = NULL;
  801. if (forkflag)
  802. finis(TRUE, ExitStat);
  803. /* NOTREACHED */
  804. return TRUE;
  805. }
  806. /*
  807. **  RUNQUEUEEVENT -- stub for use in setevent
  808. */
  809. static void
  810. runqueueevent()
  811. {
  812. DoQueueRun = TRUE;
  813. }
  814. /*
  815. **  ORDERQ -- order the work queue.
  816. **
  817. ** Parameters:
  818. ** queuedir -- the index of the queue directory.
  819. ** doall -- if set, include everything in the queue (even
  820. ** the jobs that cannot be run because the load
  821. ** average is too high).  Otherwise, exclude those
  822. ** jobs.
  823. **
  824. ** Returns:
  825. ** The number of request in the queue (not necessarily
  826. ** the number of requests in WorkQ however).
  827. **
  828. ** Side Effects:
  829. ** Sets WorkQ to the queue of available work, in order.
  830. */
  831. # define NEED_P 001
  832. # define NEED_T 002
  833. # define NEED_R 004
  834. # define NEED_S 010
  835. static WORK *WorkList = NULL;
  836. static int WorkListSize = 0;
  837. static int
  838. orderq(queuedir, doall)
  839. int queuedir;
  840. bool doall;
  841. {
  842. register struct dirent *d;
  843. register WORK *w;
  844. register char *p;
  845. DIR *f;
  846. register int i;
  847. int wn = -1;
  848. int wc;
  849. QUEUE_CHAR *check;
  850. char qd[MAXPATHLEN];
  851. char qf[MAXPATHLEN];
  852. if (queuedir == NOQDIR)
  853. (void) strlcpy(qd, ".", sizeof qd);
  854. else
  855. (void) snprintf(qd, sizeof qd, "%s%s",
  856. QPaths[queuedir].qp_name,
  857. (bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
  858. if (tTd(41, 1))
  859. {
  860. dprintf("orderq:n");
  861. check = QueueLimitId;
  862. while (check != NULL)
  863. {
  864. dprintf("tQueueLimitId = %sn",
  865. check->queue_match);
  866. check = check->queue_next;
  867. }
  868. check = QueueLimitSender;
  869. while (check != NULL)
  870. {
  871. dprintf("tQueueLimitSender = %sn",
  872. check->queue_match);
  873. check = check->queue_next;
  874. }
  875. check = QueueLimitRecipient;
  876. while (check != NULL)
  877. {
  878. dprintf("tQueueLimitRecipient = %sn",
  879. check->queue_match);
  880. check = check->queue_next;
  881. }
  882. }
  883. /* clear out old WorkQ */
  884. for (w = WorkQ; w != NULL; )
  885. {
  886. register WORK *nw = w->w_next;
  887. WorkQ = nw;
  888. free(w->w_name);
  889. if (w->w_host)
  890. free(w->w_host);
  891. free((char *) w);
  892. w = nw;
  893. }
  894. /* open the queue directory */
  895. f = opendir(qd);
  896. if (f == NULL)
  897. {
  898. syserr("orderq: cannot open "%s"", qid_printqueue(queuedir));
  899. return 0;
  900. }
  901. /*
  902. **  Read the work directory.
  903. */
  904. while ((d = readdir(f)) != NULL)
  905. {
  906. FILE *cf;
  907. int qfver = 0;
  908. char lbuf[MAXNAME + 1];
  909. struct stat sbuf;
  910. if (tTd(41, 50))
  911. dprintf("orderq: checking %sn", d->d_name);
  912. /* is this an interesting entry? */
  913. if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
  914. continue;
  915. if (strlen(d->d_name) >= MAXQFNAME)
  916. {
  917. if (Verbose)
  918. printf("orderq: %s too long, %d max charactersn",
  919. d->d_name, MAXQFNAME);
  920. if (LogLevel > 0)
  921. sm_syslog(LOG_ALERT, NOQID,
  922.   "orderq: %s too long, %d max characters",
  923.   d->d_name, MAXQFNAME);
  924. continue;
  925. }
  926. check = QueueLimitId;
  927. while (check != NULL)
  928. {
  929. if (strcontainedin(check->queue_match, d->d_name))
  930. break;
  931. else
  932. check = check->queue_next;
  933. }
  934. if (QueueLimitId != NULL && check == NULL)
  935. continue;
  936. /* grow work list if necessary */
  937. if (++wn >= MaxQueueRun && MaxQueueRun > 0)
  938. {
  939. if (wn == MaxQueueRun && LogLevel > 0)
  940. sm_syslog(LOG_WARNING, NOQID,
  941.   "WorkList for %s maxed out at %d",
  942.   qid_printqueue(queuedir),
  943.   MaxQueueRun);
  944. continue;
  945. }
  946. if (wn >= WorkListSize)
  947. {
  948. grow_wlist(queuedir);
  949. if (wn >= WorkListSize)
  950. continue;
  951. }
  952. w = &WorkList[wn];
  953. (void) snprintf(qf, sizeof qf, "%s/%s", qd, d->d_name);
  954. if (stat(qf, &sbuf) < 0)
  955. {
  956. if (errno != ENOENT)
  957. sm_syslog(LOG_INFO, NOQID,
  958.   "orderq: can't stat %s/%s",
  959.   qid_printqueue(queuedir), d->d_name);
  960. wn--;
  961. continue;
  962. }
  963. if (!bitset(S_IFREG, sbuf.st_mode))
  964. {
  965. /* Yikes!  Skip it or we will hang on open! */
  966. syserr("orderq: %s/%s is not a regular file",
  967.        qid_printqueue(queuedir), d->d_name);
  968. wn--;
  969. continue;
  970. }
  971. /* avoid work if possible */
  972. if (QueueSortOrder == QSO_BYFILENAME)
  973. {
  974. w->w_name = newstr(d->d_name);
  975. w->w_host = NULL;
  976. w->w_lock = w->w_tooyoung = FALSE;
  977. w->w_pri = 0;
  978. w->w_ctime = 0;
  979. continue;
  980. }
  981. /* open control file */
  982. cf = fopen(qf, "r");
  983. if (cf == NULL)
  984. {
  985. /* this may be some random person sending hir msgs */
  986. /* syserr("orderq: cannot open %s", cbuf); */
  987. if (tTd(41, 2))
  988. dprintf("orderq: cannot open %s: %sn",
  989. d->d_name, errstring(errno));
  990. errno = 0;
  991. wn--;
  992. continue;
  993. }
  994. w->w_name = newstr(d->d_name);
  995. w->w_host = NULL;
  996. w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
  997. w->w_tooyoung = FALSE;
  998. /* make sure jobs in creation don't clog queue */
  999. w->w_pri = 0x7fffffff;
  1000. w->w_ctime = 0;
  1001. /* extract useful information */
  1002. i = NEED_P | NEED_T;
  1003. if (QueueLimitSender != NULL)
  1004. i |= NEED_S;
  1005. if (QueueSortOrder == QSO_BYHOST || QueueLimitRecipient != NULL)
  1006. i |= NEED_R;
  1007. while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
  1008. {
  1009. int c;
  1010. time_t age;
  1011. p = strchr(lbuf, 'n');
  1012. if (p != NULL)
  1013. *p = '';
  1014. else
  1015. {
  1016. /* flush rest of overly long line */
  1017. while ((c = getc(cf)) != EOF && c != 'n')
  1018. continue;
  1019. }
  1020. switch (lbuf[0])
  1021. {
  1022.   case 'V':
  1023. qfver = atoi(&lbuf[1]);
  1024. break;
  1025.   case 'P':
  1026. w->w_pri = atol(&lbuf[1]);
  1027. i &= ~NEED_P;
  1028. break;
  1029.   case 'T':
  1030. w->w_ctime = atol(&lbuf[1]);
  1031. i &= ~NEED_T;
  1032. break;
  1033.   case 'R':
  1034. if (w->w_host == NULL &&
  1035.     (p = strrchr(&lbuf[1], '@')) != NULL)
  1036. {
  1037. w->w_host = strrev(&p[1]);
  1038. makelower(w->w_host);
  1039. }
  1040. if (QueueLimitRecipient == NULL)
  1041. {
  1042. i &= ~NEED_R;
  1043. break;
  1044. }
  1045. if (qfver > 0)
  1046. {
  1047. p = strchr(&lbuf[1], ':');
  1048. if (p == NULL)
  1049. p = &lbuf[1];
  1050. }
  1051. else
  1052. p = &lbuf[1];
  1053. check = QueueLimitRecipient;
  1054. while (check != NULL)
  1055. {
  1056. if (strcontainedin(check->queue_match,
  1057.    p))
  1058. break;
  1059. else
  1060. check = check->queue_next;
  1061. }
  1062. if (check != NULL)
  1063. i &= ~NEED_R;
  1064. break;
  1065.   case 'S':
  1066.   check = QueueLimitSender;
  1067.   while (check != NULL)
  1068.   {
  1069.   if (strcontainedin(check->queue_match,
  1070.      &lbuf[1]))
  1071.   break;
  1072.   else
  1073.   check = check->queue_next;
  1074.   }
  1075.   if (check != NULL)
  1076.   i &= ~NEED_S;
  1077. break;
  1078.   case 'K':
  1079. age = curtime() - (time_t) atol(&lbuf[1]);
  1080. if (age >= 0 && MinQueueAge > 0 &&
  1081.     age < MinQueueAge)
  1082. w->w_tooyoung = TRUE;
  1083. break;
  1084.   case 'N':
  1085. if (atol(&lbuf[1]) == 0)
  1086. w->w_tooyoung = FALSE;
  1087. break;
  1088. # if _FFR_QUEUEDELAY
  1089. /*
  1090.   case 'G':
  1091. queuealg = atoi(lbuf[1]);
  1092. break;
  1093.   case 'Y':
  1094. queuedelay = (time_t) atol(&lbuf[1]);
  1095. break;
  1096. */
  1097. # endif /* _FFR_QUEUEDELAY */
  1098. }
  1099. }
  1100. (void) fclose(cf);
  1101. if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
  1102.     bitset(NEED_R|NEED_S, i))
  1103. {
  1104. /* don't even bother sorting this job in */
  1105. if (tTd(41, 49))
  1106. dprintf("skipping %s (%x)n", w->w_name, i);
  1107. free(w->w_name);
  1108. if (w->w_host)
  1109. free(w->w_host);
  1110. wn--;
  1111. }
  1112. }
  1113. (void) closedir(f);
  1114. wn++;
  1115. WorkQ = NULL;
  1116. if (WorkList == NULL)
  1117. return 0;
  1118. wc = min(wn, WorkListSize);
  1119. if (wc > MaxQueueRun && MaxQueueRun > 0)
  1120. wc = MaxQueueRun;
  1121. if (QueueSortOrder == QSO_BYHOST)
  1122. {
  1123. /*
  1124. **  Sort the work directory for the first time,
  1125. **  based on host name, lock status, and priority.
  1126. */
  1127. qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
  1128. /*
  1129. **  If one message to host is locked, "lock" all messages
  1130. **  to that host.
  1131. */
  1132. i = 0;
  1133. while (i < wc)
  1134. {
  1135. if (!WorkList[i].w_lock)
  1136. {
  1137. i++;
  1138. continue;
  1139. }
  1140. w = &WorkList[i];
  1141. while (++i < wc)
  1142. {
  1143. if (WorkList[i].w_host == NULL &&
  1144.     w->w_host == NULL)
  1145. WorkList[i].w_lock = TRUE;
  1146. else if (WorkList[i].w_host != NULL &&
  1147.  w->w_host != NULL &&
  1148.  sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
  1149. WorkList[i].w_lock = TRUE;
  1150. else
  1151. break;
  1152. }
  1153. }
  1154. /*
  1155. **  Sort the work directory for the second time,
  1156. **  based on lock status, host name, and priority.
  1157. */
  1158. qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
  1159. }
  1160. else if (QueueSortOrder == QSO_BYTIME)
  1161. {
  1162. /*
  1163. **  Simple sort based on submission time only.
  1164. */
  1165. qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
  1166. }
  1167. else if (QueueSortOrder == QSO_BYFILENAME)
  1168. {
  1169. /*
  1170. **  Sort based on qf filename.
  1171. */
  1172. qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
  1173. }
  1174. else
  1175. {
  1176. /*
  1177. **  Simple sort based on queue priority only.
  1178. */
  1179. qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
  1180. }
  1181. /*
  1182. **  Convert the work list into canonical form.
  1183. ** Should be turning it into a list of envelopes here perhaps.
  1184. */
  1185. for (i = wc; --i >= 0; )
  1186. {
  1187. w = (WORK *) xalloc(sizeof *w);
  1188. w->w_name = WorkList[i].w_name;
  1189. w->w_host = WorkList[i].w_host;
  1190. w->w_lock = WorkList[i].w_lock;
  1191. w->w_tooyoung = WorkList[i].w_tooyoung;
  1192. w->w_pri = WorkList[i].w_pri;
  1193. w->w_ctime = WorkList[i].w_ctime;
  1194. w->w_next = WorkQ;
  1195. WorkQ = w;
  1196. }
  1197. if (WorkList != NULL)
  1198. free(WorkList);
  1199. WorkList = NULL;
  1200. WorkListSize = 0;
  1201. if (tTd(40, 1))
  1202. {
  1203. for (w = WorkQ; w != NULL; w = w->w_next)
  1204. {
  1205. if (w->w_host != NULL)
  1206. dprintf("%22s: pri=%ld %sn",
  1207. w->w_name, w->w_pri, w->w_host);
  1208. else
  1209. dprintf("%32s: pri=%ldn",
  1210. w->w_name, w->w_pri);
  1211. }
  1212. }
  1213. return wn;
  1214. }
  1215. /*
  1216. **  GROW_WLIST -- make the work list larger
  1217. **
  1218. ** Parameters:
  1219. ** queuedir -- the index for the queue directory.
  1220. **
  1221. ** Returns:
  1222. ** none.
  1223. **
  1224. ** Side Effects:
  1225. ** Adds another QUEUESEGSIZE entries to WorkList if possible.
  1226. ** It can fail if there isn't enough memory, so WorkListSize
  1227. ** should be checked again upon return.
  1228. */
  1229. static void
  1230. grow_wlist(queuedir)
  1231. int queuedir;
  1232. {
  1233. if (tTd(41, 1))
  1234. dprintf("grow_wlist: WorkListSize=%dn", WorkListSize);
  1235. if (WorkList == NULL)
  1236. {
  1237. WorkList = (WORK *) xalloc((sizeof *WorkList) *
  1238.    (QUEUESEGSIZE + 1));
  1239. WorkListSize = QUEUESEGSIZE;
  1240. }
  1241. else
  1242. {
  1243. int newsize = WorkListSize + QUEUESEGSIZE;
  1244. WORK *newlist = (WORK *) realloc((char *)WorkList,
  1245.   (unsigned)sizeof(WORK) * (newsize + 1));
  1246. if (newlist != NULL)
  1247. {
  1248. WorkListSize = newsize;
  1249. WorkList = newlist;
  1250. if (LogLevel > 1)
  1251. {
  1252. sm_syslog(LOG_INFO, NOQID,
  1253.   "grew WorkList for %s to %d",
  1254.   qid_printqueue(queuedir),
  1255.   WorkListSize);
  1256. }
  1257. }
  1258. else if (LogLevel > 0)
  1259. {
  1260. sm_syslog(LOG_ALERT, NOQID,
  1261.   "FAILED to grow WorkList for %s to %d",
  1262.   qid_printqueue(queuedir), newsize);
  1263. }
  1264. }
  1265. if (tTd(41, 1))
  1266. dprintf("grow_wlist: WorkListSize now %dn", WorkListSize);
  1267. }
  1268. /*
  1269. **  WORKCMPF0 -- simple priority-only compare function.
  1270. **
  1271. ** Parameters:
  1272. ** a -- the first argument.
  1273. ** b -- the second argument.
  1274. **
  1275. ** Returns:
  1276. ** -1 if a < b
  1277. **  0 if a == b
  1278. ** +1 if a > b
  1279. **
  1280. ** Side Effects:
  1281. ** none.
  1282. */
  1283. static int
  1284. workcmpf0(a, b)
  1285. register WORK *a;
  1286. register WORK *b;
  1287. {
  1288. long pa = a->w_pri;
  1289. long pb = b->w_pri;
  1290. if (pa == pb)
  1291. return 0;
  1292. else if (pa > pb)
  1293. return 1;
  1294. else
  1295. return -1;
  1296. }
  1297. /*
  1298. **  WORKCMPF1 -- first compare function for ordering work based on host name.
  1299. **
  1300. ** Sorts on host name, lock status, and priority in that order.
  1301. **
  1302. ** Parameters:
  1303. ** a -- the first argument.
  1304. ** b -- the second argument.
  1305. **
  1306. ** Returns:
  1307. ** <0 if a < b
  1308. **  0 if a == b
  1309. ** >0 if a > b
  1310. **
  1311. ** Side Effects:
  1312. ** none.
  1313. */
  1314. static int
  1315. workcmpf1(a, b)
  1316. register WORK *a;
  1317. register WORK *b;
  1318. {
  1319. int i;
  1320. /* host name */
  1321. if (a->w_host != NULL && b->w_host == NULL)
  1322. return 1;
  1323. else if (a->w_host == NULL && b->w_host != NULL)
  1324. return -1;
  1325. if (a->w_host != NULL && b->w_host != NULL &&
  1326.     (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
  1327. return i;
  1328. /* lock status */
  1329. if (a->w_lock != b->w_lock)
  1330. return b->w_lock - a->w_lock;
  1331. /* job priority */
  1332. return a->w_pri - b->w_pri;
  1333. }
  1334. /*
  1335. **  WORKCMPF2 -- second compare function for ordering work based on host name.
  1336. **
  1337. ** Sorts on lock status, host name, and priority in that order.
  1338. **
  1339. ** Parameters:
  1340. ** a -- the first argument.
  1341. ** b -- the second argument.
  1342. **
  1343. ** Returns:
  1344. ** <0 if a < b
  1345. **  0 if a == b
  1346. ** >0 if a > b
  1347. **
  1348. ** Side Effects:
  1349. ** none.
  1350. */
  1351. static int
  1352. workcmpf2(a, b)
  1353. register WORK *a;
  1354. register WORK *b;
  1355. {
  1356. int i;
  1357. /* lock status */
  1358. if (a->w_lock != b->w_lock)
  1359. return a->w_lock - b->w_lock;
  1360. /* host name */
  1361. if (a->w_host != NULL && b->w_host == NULL)
  1362. return 1;
  1363. else if (a->w_host == NULL && b->w_host != NULL)
  1364. return -1;
  1365. if (a->w_host != NULL && b->w_host != NULL &&
  1366.     (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
  1367. return i;
  1368. /* job priority */
  1369. return a->w_pri - b->w_pri;
  1370. }
  1371. /*
  1372. **  WORKCMPF3 -- simple submission-time-only compare function.
  1373. **
  1374. ** Parameters:
  1375. ** a -- the first argument.
  1376. ** b -- the second argument.
  1377. **
  1378. ** Returns:
  1379. ** -1 if a < b
  1380. **  0 if a == b
  1381. ** +1 if a > b
  1382. **
  1383. ** Side Effects:
  1384. ** none.
  1385. */
  1386. static int
  1387. workcmpf3(a, b)
  1388. register WORK *a;
  1389. register WORK *b;
  1390. {
  1391. if (a->w_ctime > b->w_ctime)
  1392. return 1;
  1393. else if (a->w_ctime < b->w_ctime)
  1394. return -1;
  1395. else
  1396. return 0;
  1397. }
  1398. /*
  1399. **  WORKCMPF4 -- compare based on file name
  1400. **
  1401. ** Parameters:
  1402. ** a -- the first argument.
  1403. ** b -- the second argument.
  1404. **
  1405. ** Returns:
  1406. ** -1 if a < b
  1407. **  0 if a == b
  1408. ** +1 if a > b
  1409. **
  1410. ** Side Effects:
  1411. ** none.
  1412. */
  1413. static int
  1414. workcmpf4(a, b)
  1415. register WORK *a;
  1416. register WORK *b;
  1417. {
  1418. return strcmp(a->w_name, b->w_name);
  1419. }
  1420. /*
  1421. **  STRREV -- reverse string
  1422. **
  1423. ** Returns a pointer to a new string that is the reverse of
  1424. ** the string pointed to by fwd.  The space for the new
  1425. ** string is obtained using xalloc().
  1426. **
  1427. ** Parameters:
  1428. ** fwd -- the string to reverse.
  1429. **
  1430. ** Returns:
  1431. ** the reversed string.
  1432. */
  1433. static char *
  1434. strrev(fwd)
  1435. char *fwd;
  1436. {
  1437. char *rev = NULL;
  1438. int len, cnt;
  1439. len = strlen(fwd);
  1440. rev = xalloc(len + 1);
  1441. for (cnt = 0; cnt < len; ++cnt)
  1442. rev[cnt] = fwd[len - cnt - 1];
  1443. rev[len] = '';
  1444. return rev;
  1445. }
  1446. /*
  1447. **  DOWORK -- do a work request.
  1448. **
  1449. ** Parameters:
  1450. ** queuedir -- the index of the queue directory for the job.
  1451. ** id -- the ID of the job to run.
  1452. ** forkflag -- if set, run this in background.
  1453. ** requeueflag -- if set, reinstantiate the queue quickly.
  1454. ** This is used when expanding aliases in the queue.
  1455. ** If forkflag is also set, it doesn't wait for the
  1456. ** child.
  1457. ** e - the envelope in which to run it.
  1458. **
  1459. ** Returns:
  1460. ** process id of process that is running the queue job.
  1461. **
  1462. ** Side Effects:
  1463. ** The work request is satisfied if possible.
  1464. */
  1465. pid_t
  1466. dowork(queuedir, id, forkflag, requeueflag, e)
  1467. int queuedir;
  1468. char *id;
  1469. bool forkflag;
  1470. bool requeueflag;
  1471. register ENVELOPE *e;
  1472. {
  1473. register pid_t pid;
  1474. if (tTd(40, 1))
  1475. dprintf("dowork(%s/%s)n", qid_printqueue(queuedir), id);
  1476. /*
  1477. **  Fork for work.
  1478. */
  1479. if (forkflag)
  1480. {
  1481. /*
  1482. **  Since the delivery may happen in a child and the
  1483. **  parent does not wait, the parent may close the
  1484. **  maps thereby removing any shared memory used by
  1485. **  the map.  Therefore, close the maps now so the
  1486. **  child will dynamically open them if necessary.
  1487. */
  1488. closemaps();
  1489. pid = fork();
  1490. if (pid < 0)
  1491. {
  1492. syserr("dowork: cannot fork");
  1493. return 0;
  1494. }
  1495. else if (pid > 0)
  1496. {
  1497. /* parent -- clean out connection cache */
  1498. mci_flush(FALSE, NULL);
  1499. }
  1500. else
  1501. {
  1502. /* child -- error messages to the transcript */
  1503. QuickAbort = OnlyOneError = FALSE;
  1504. }
  1505. }
  1506. else
  1507. {
  1508. pid = 0;
  1509. }
  1510. if (pid == 0)
  1511. {
  1512. /*
  1513. **  CHILD
  1514. ** Lock the control file to avoid duplicate deliveries.
  1515. ** Then run the file as though we had just read it.
  1516. ** We save an idea of the temporary name so we
  1517. ** can recover on interrupt.
  1518. */
  1519. /* set basic modes, etc. */
  1520. (void) alarm(0);
  1521. clearstats();
  1522. clearenvelope(e, FALSE);
  1523. e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
  1524. set_delivery_mode(SM_DELIVER, e);
  1525. e->e_errormode = EM_MAIL;
  1526. e->e_id = id;
  1527. e->e_queuedir = queuedir;
  1528. GrabTo = UseErrorsTo = FALSE;
  1529. ExitStat = EX_OK;
  1530. if (forkflag)
  1531. {
  1532. disconnect(1, e);
  1533. OpMode = MD_QUEUERUN;
  1534. }
  1535. sm_setproctitle(TRUE, e, "%s: from queue", qid_printname(e));
  1536. if (LogLevel > 76)
  1537. sm_syslog(LOG_DEBUG, e->e_id,
  1538.   "dowork, pid=%d",
  1539.   getpid());
  1540. /* don't use the headers from sendmail.cf... */
  1541. e->e_header = NULL;
  1542. /* read the queue control file -- return if locked */
  1543. if (!readqf(e))
  1544. {
  1545. if (tTd(40, 4) && e->e_id != NULL)
  1546. dprintf("readqf(%s) failedn",
  1547. qid_printname(e));
  1548. e->e_id = NULL;
  1549. if (forkflag)
  1550. finis(FALSE, EX_OK);
  1551. else
  1552. return 0;
  1553. }
  1554. e->e_flags |= EF_INQUEUE;
  1555. eatheader(e, requeueflag);
  1556. if (requeueflag)
  1557. queueup(e, FALSE);
  1558. /* do the delivery */
  1559. sendall(e, SM_DELIVER);
  1560. /* finish up and exit */
  1561. if (forkflag)
  1562. finis(TRUE, ExitStat);
  1563. else
  1564. dropenvelope(e, TRUE);
  1565. }
  1566. e->e_id = NULL;
  1567. return pid;
  1568. }
  1569. /*
  1570. **  READQF -- read queue file and set up environment.
  1571. **
  1572. ** Parameters:
  1573. ** e -- the envelope of the job to run.
  1574. **
  1575. ** Returns:
  1576. ** TRUE if it successfully read the queue file.
  1577. ** FALSE otherwise.
  1578. **
  1579. ** Side Effects:
  1580. ** The queue file is returned locked.
  1581. */
  1582. static bool
  1583. readqf(e)
  1584. register ENVELOPE *e;
  1585. {
  1586. register FILE *qfp;
  1587. ADDRESS *ctladdr;
  1588. struct stat st;
  1589. char *bp;
  1590. int qfver = 0;
  1591. int chompflags;
  1592. long hdrsize = 0;
  1593. register char *p;
  1594. char *orcpt = NULL;
  1595. bool nomore = FALSE;
  1596. char qf[MAXPATHLEN];
  1597. char buf[MAXLINE];
  1598. /*
  1599. **  Read and process the file.
  1600. */
  1601. (void) strlcpy(qf, queuename(e, 'q'), sizeof qf);
  1602. qfp = fopen(qf, "r+");
  1603. if (qfp == NULL)
  1604. {
  1605. int save_errno = errno;
  1606. if (tTd(40, 8))
  1607. dprintf("readqf(%s): fopen failure (%s)n",
  1608. qf, errstring(errno));
  1609. errno = save_errno;
  1610. if (errno != ENOENT)
  1611. syserr("readqf: no control file %s", qf);
  1612. return FALSE;
  1613. }
  1614. if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
  1615. {
  1616. /* being processed by another queuer */
  1617. if (Verbose)
  1618. printf("%s: lockedn", e->e_id);
  1619. if (tTd(40, 8))
  1620. dprintf("%s: lockedn", e->e_id);
  1621. if (LogLevel > 19)
  1622. sm_syslog(LOG_DEBUG, e->e_id, "locked");
  1623. (void) fclose(qfp);
  1624. return FALSE;
  1625. }
  1626. /*
  1627. **  Check the queue file for plausibility to avoid attacks.
  1628. */
  1629. if (fstat(fileno(qfp), &st) < 0)
  1630. {
  1631. /* must have been being processed by someone else */
  1632. if (tTd(40, 8))
  1633. dprintf("readqf(%s): fstat failure (%s)n",
  1634. qf, errstring(errno));
  1635. (void) fclose(qfp);
  1636. return FALSE;
  1637. }
  1638. if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
  1639.     bitset(S_IWOTH|S_IWGRP, st.st_mode))
  1640. {
  1641. if (LogLevel > 0)
  1642. {
  1643. sm_syslog(LOG_ALERT, e->e_id,
  1644.   "bogus queue file, uid=%d, mode=%o",
  1645.   st.st_uid, st.st_mode);
  1646. }
  1647. if (tTd(40, 8))
  1648. dprintf("readqf(%s): bogus filen", qf);
  1649. loseqfile(e, "bogus file uid in mqueue");
  1650. (void) fclose(qfp);
  1651. return FALSE;
  1652. }
  1653. if (st.st_size == 0)
  1654. {
  1655. /* must be a bogus file -- if also old, just remove it */
  1656. if (st.st_ctime + 10 * 60 < curtime())
  1657. {
  1658. (void) unlink(queuename(e, 'd'));
  1659. (void) unlink(queuename(e, 'q'));
  1660. }
  1661. (void) fclose(qfp);
  1662. return FALSE;
  1663. }
  1664. if (st.st_nlink == 0)
  1665. {
  1666. /*
  1667. **  Race condition -- we got a file just as it was being
  1668. **  unlinked.  Just assume it is zero length.
  1669. */
  1670. (void) fclose(qfp);
  1671. return FALSE;
  1672. }
  1673. /* good file -- save this lock */
  1674. e->e_lockfp = qfp;
  1675. /* do basic system initialization */
  1676. initsys(e);
  1677. define('i', e->e_id, e);
  1678. LineNumber = 0;
  1679. e->e_flags |= EF_GLOBALERRS;
  1680. OpMode = MD_QUEUERUN;
  1681. ctladdr = NULL;
  1682. e->e_dfino = -1;
  1683. e->e_msgsize = -1;
  1684. # if _FFR_QUEUEDELAY
  1685. e->e_queuealg = QD_LINEAR;
  1686. e->e_queuedelay = (time_t) 0;
  1687. # endif /* _FFR_QUEUEDELAY */
  1688. while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
  1689. {
  1690. u_long qflags;
  1691. ADDRESS *q;
  1692. int mid;
  1693. auto char *ep;
  1694. if (tTd(40, 4))
  1695. dprintf("+++++ %sn", bp);
  1696. if (nomore)
  1697. {
  1698. /* hack attack */
  1699. syserr("SECURITY ALERT: extra data in qf: %s", bp);
  1700. (void) fclose(qfp);
  1701. loseqfile(e, "bogus queue line");
  1702. return FALSE;
  1703. }
  1704. switch (bp[0])
  1705. {
  1706.   case 'V': /* queue file version number */
  1707. qfver = atoi(&bp[1]);
  1708. if (qfver <= QF_VERSION)
  1709. break;
  1710. syserr("Version number in qf (%d) greater than max (%d)",
  1711. qfver, QF_VERSION);
  1712. (void) fclose(qfp);
  1713. loseqfile(e, "unsupported qf file version");
  1714. return FALSE;
  1715.   case 'C': /* specify controlling user */
  1716. ctladdr = setctluser(&bp[1], qfver);
  1717. break;
  1718.   case 'Q': /* original recipient */
  1719. orcpt = newstr(&bp[1]);
  1720. break;
  1721.   case 'R': /* specify recipient */
  1722. p = bp;
  1723. qflags = 0;
  1724. if (qfver >= 1)
  1725. {
  1726. /* get flag bits */
  1727. while (*++p != '' && *p != ':')
  1728. {
  1729. switch (*p)
  1730. {
  1731.   case 'N':
  1732. qflags |= QHASNOTIFY;
  1733. break;
  1734.   case 'S':
  1735. qflags |= QPINGONSUCCESS;
  1736. break;
  1737.   case 'F':
  1738. qflags |= QPINGONFAILURE;
  1739. break;
  1740.   case 'D':
  1741. qflags |= QPINGONDELAY;
  1742. break;
  1743.   case 'P':
  1744. qflags |= QPRIMARY;
  1745. break;
  1746. }
  1747. }
  1748. }
  1749. else
  1750. qflags |= QPRIMARY;
  1751. q = parseaddr(++p, NULLADDR, RF_COPYALL, '', NULL, e);
  1752. if (q != NULL)
  1753. {
  1754. q->q_alias = ctladdr;
  1755. if (qfver >= 1)
  1756. q->q_flags &= ~Q_PINGFLAGS;
  1757. q->q_flags |= qflags;
  1758. q->q_orcpt = orcpt;
  1759. (void) recipient(q, &e->e_sendqueue, 0, e);
  1760. }
  1761. orcpt = NULL;
  1762. break;
  1763.   case 'E': /* specify error recipient */
  1764. /* no longer used */
  1765. break;
  1766.   case 'H': /* header */
  1767. chompflags = 0;
  1768. (void) chompheader(&bp[1], &chompflags, NULL, e);
  1769. hdrsize += strlen(&bp[1]);
  1770. break;
  1771.   case 'L': /* Solaris Content-Length: */
  1772.   case 'M': /* message */
  1773. /* ignore this; we want a new message next time */
  1774. break;
  1775.   case 'S': /* sender */
  1776. setsender(newstr(&bp[1]), e, NULL, '', TRUE);
  1777. break;
  1778.   case 'B': /* body type */
  1779. e->e_bodytype = newstr(&bp[1]);
  1780. break;
  1781. # if _FFR_SAVE_CHARSET
  1782.   case 'X': /* character set */
  1783. e->e_charset = newstr(&bp[1]);
  1784. break;
  1785. # endif /* _FFR_SAVE_CHARSET */
  1786.   case 'D': /* data file name */
  1787. /* obsolete -- ignore */
  1788. break;
  1789.   case 'T': /* init time */
  1790. e->e_ctime = atol(&bp[1]);
  1791. break;
  1792.   case 'I': /* data file's inode number */
  1793. /* regenerated below */
  1794. break;
  1795.   case 'K': /* time of last delivery attempt */
  1796. e->e_dtime = atol(&buf[1]);
  1797. break;
  1798. # if _FFR_QUEUEDELAY
  1799.   case 'G': /* queue delay algorithm */
  1800. e->e_queuealg = atoi(&buf[1]);
  1801. break;
  1802.   case 'Y': /* current delay */
  1803. e->e_queuedelay = (time_t) atol(&buf[1]);
  1804. break;
  1805. # endif /* _FFR_QUEUEDELAY */
  1806.   case 'N': /* number of delivery attempts */
  1807. e->e_ntries = atoi(&buf[1]);
  1808. /* if this has been tried recently, let it be */
  1809. if (e->e_ntries > 0 && e->e_dtime <= curtime() &&
  1810.     curtime() < e->e_dtime + queuedelay(e))
  1811. {
  1812. char *howlong;
  1813. howlong = pintvl(curtime() - e->e_dtime, TRUE);
  1814. if (Verbose)
  1815. printf("%s: too young (%s)n",
  1816.        e->e_id, howlong);
  1817. if (tTd(40, 8))
  1818. dprintf("%s: too young (%s)n",
  1819. e->e_id, howlong);
  1820. if (LogLevel > 19)
  1821. sm_syslog(LOG_DEBUG, e->e_id,
  1822.   "too young (%s)",
  1823.   howlong);
  1824. e->e_id = NULL;
  1825. unlockqueue(e);
  1826. return FALSE;
  1827. }
  1828. define(macid("{ntries}", NULL), newstr(&buf[1]), e);
  1829. # if NAMED_BIND
  1830. /* adjust BIND parameters immediately */
  1831. if (e->e_ntries == 0)
  1832. {
  1833. _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
  1834. _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
  1835. }
  1836. else
  1837. {
  1838. _res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
  1839. _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
  1840. }
  1841. # endif /* NAMED_BIND */
  1842. break;
  1843.   case 'P': /* message priority */
  1844. e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
  1845. break;
  1846.   case 'F': /* flag bits */
  1847. if (strncmp(bp, "From ", 5) == 0)
  1848. {
  1849. /* we are being spoofed! */
  1850. syserr("SECURITY ALERT: bogus qf line %s", bp);
  1851. (void) fclose(qfp);
  1852. loseqfile(e, "bogus queue line");
  1853. return FALSE;
  1854. }
  1855. for (p = &bp[1]; *p != ''; p++)
  1856. {
  1857. switch (*p)
  1858. {
  1859.   case 'w': /* warning sent */
  1860. e->e_flags |= EF_WARNING;
  1861. break;
  1862.   case 'r': /* response */
  1863. e->e_flags |= EF_RESPONSE;
  1864. break;
  1865.   case '8': /* has 8 bit data */
  1866. e->e_flags |= EF_HAS8BIT;
  1867. break;
  1868.   case 'b': /* delete Bcc: header */
  1869. e->e_flags |= EF_DELETE_BCC;
  1870. break;
  1871.   case 'd': /* envelope has DSN RET= */
  1872. e->e_flags |= EF_RET_PARAM;
  1873. break;
  1874.   case 'n': /* don't return body */
  1875. e->e_flags |= EF_NO_BODY_RETN;
  1876. break;
  1877. }
  1878. }
  1879. break;
  1880.   case 'Z': /* original envelope id from ESMTP */
  1881. e->e_envid = newstr(&bp[1]);
  1882. define(macid("{dsn_envid}", NULL), newstr(&bp[1]), e);
  1883. break;
  1884.   case 'A': /* AUTH= parameter */
  1885. e->e_auth_param = newstr(&bp[1]);
  1886. break;
  1887.   case '$': /* define macro */
  1888. mid = macid(&bp[1], &ep);
  1889. define(mid, newstr(ep), e);
  1890. break;
  1891.   case '.': /* terminate file */
  1892. nomore = TRUE;
  1893. break;
  1894.   default:
  1895. syserr("readqf: %s: line %d: bad line "%s"",
  1896. qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
  1897. (void) fclose(qfp);
  1898. loseqfile(e, "unrecognized line");
  1899. return FALSE;
  1900. }
  1901. if (bp != buf)
  1902. free(bp);
  1903. }
  1904. /*
  1905. **  If we haven't read any lines, this queue file is empty.
  1906. **  Arrange to remove it without referencing any null pointers.
  1907. */
  1908. if (LineNumber == 0)
  1909. {
  1910. errno = 0;
  1911. e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
  1912. return TRUE;
  1913. }
  1914. /* possibly set ${dsn_ret} macro */
  1915. if (bitset(EF_RET_PARAM, e->e_flags))
  1916. {
  1917. if (bitset(EF_NO_BODY_RETN, e->e_flags))
  1918. define(macid("{dsn_ret}", NULL), "hdrs", e);
  1919. else
  1920. define(macid("{dsn_ret}", NULL), "full", e);
  1921. }
  1922. /*
  1923. **  Arrange to read the data file.
  1924. */
  1925. p = queuename(e, 'd');
  1926. e->e_dfp = fopen(p, "r");
  1927. if (e->e_dfp == NULL)
  1928. {
  1929. syserr("readqf: cannot open %s", p);
  1930. }
  1931. else
  1932. {
  1933. e->e_flags |= EF_HAS_DF;
  1934. if (fstat(fileno(e->e_dfp), &st) >= 0)
  1935. {
  1936. e->e_msgsize = st.st_size + hdrsize;
  1937. e->e_dfdev = st.st_dev;
  1938. e->e_dfino = st.st_ino;
  1939. }
  1940. }
  1941. return TRUE;
  1942. }
  1943. /*
  1944. **  PRINTQUEUE -- print out a representation of the mail queue
  1945. **
  1946. ** Parameters:
  1947. ** none.
  1948. **
  1949. ** Returns:
  1950. ** none.
  1951. **
  1952. ** Side Effects:
  1953. ** Prints a listing of the mail queue on the standard output.
  1954. */
  1955. void
  1956. printqueue()
  1957. {
  1958. int i, nrequests = 0;
  1959. for (i = 0; i < NumQueues; i++)
  1960. nrequests += print_single_queue(i);
  1961. if (NumQueues > 1)
  1962. printf("ttTotal Requests: %dn", nrequests);
  1963. }
  1964. /*
  1965. **  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
  1966. **
  1967. ** Parameters:
  1968. ** queuedir -- queue directory
  1969. **
  1970. ** Returns:
  1971. ** none.
  1972. **
  1973. ** Side Effects:
  1974. ** Prints a listing of the mail queue on the standard output.
  1975. */
  1976. static int
  1977. print_single_queue(queuedir)
  1978. int queuedir;
  1979. {
  1980. register WORK *w;
  1981. FILE *f;
  1982. int nrequests;
  1983. char qd[MAXPATHLEN];
  1984. char qddf[MAXPATHLEN];
  1985. char buf[MAXLINE];
  1986. if (queuedir == NOQDIR)
  1987. {
  1988. (void) strlcpy(qd, ".", sizeof qd);
  1989. (void) strlcpy(qddf, ".", sizeof qddf);
  1990. }
  1991. else
  1992. {
  1993. (void) snprintf(qd, sizeof qd, "%s%s",
  1994. QPaths[queuedir].qp_name,
  1995. (bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
  1996. (void) snprintf(qddf, sizeof qddf, "%s%s",
  1997. QPaths[queuedir].qp_name,
  1998. (bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
  1999. }
  2000. /*
  2001. **  Check for permission to print the queue
  2002. */
  2003. if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
  2004. {
  2005. struct stat st;
  2006. # ifdef NGROUPS_MAX
  2007. int n;
  2008. extern GIDSET_T InitialGidSet[NGROUPS_MAX];
  2009. # endif /* NGROUPS_MAX */
  2010. if (stat(qd, &st) < 0)
  2011. {
  2012. syserr("Cannot stat %s", qid_printqueue(queuedir));
  2013. return 0;
  2014. }
  2015. # ifdef NGROUPS_MAX
  2016. n = NGROUPS_MAX;
  2017. while (--n >= 0)
  2018. {
  2019. if (InitialGidSet[n] == st.st_gid)
  2020. break;
  2021. }
  2022. if (n < 0 && RealGid != st.st_gid)
  2023. # else /* NGROUPS_MAX */
  2024. if (RealGid != st.st_gid)
  2025. # endif /* NGROUPS_MAX */
  2026. {
  2027. usrerr("510 You are not permitted to see the queue");
  2028. setstat(EX_NOPERM);
  2029. return 0;
  2030. }
  2031. }
  2032. /*
  2033. **  Read and order the queue.
  2034. */
  2035. nrequests = orderq(queuedir, TRUE);
  2036. /*
  2037. **  Print the work list that we have read.
  2038. */
  2039. /* first see if there is anything */
  2040. if (nrequests <= 0)
  2041. {
  2042. printf("%s is emptyn", qid_printqueue(queuedir));
  2043. return 0;
  2044. }
  2045. CurrentLA = sm_getla(NULL); /* get load average */
  2046. printf("tt%s (%d request%s", qid_printqueue(queuedir), nrequests,
  2047.        nrequests == 1 ? "" : "s");
  2048. if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
  2049. printf(", only %d printed", MaxQueueRun);
  2050. if (Verbose)
  2051. printf(")n----Q-ID---- --Size-- -Priority- ---Q-Time--- ---------Sender/Recipient--------n");
  2052. else
  2053. printf(")n----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------n");
  2054. for (w = WorkQ; w != NULL; w = w->w_next)
  2055. {
  2056. struct stat st;
  2057. auto time_t submittime = 0;
  2058. long dfsize;
  2059. int flags = 0;
  2060. int qfver;
  2061. char statmsg[MAXLINE];
  2062. char bodytype[MAXNAME + 1];
  2063. char qf[MAXPATHLEN];
  2064. printf("%12s", w->w_name + 2);
  2065. (void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name);
  2066. f = fopen(qf, "r");
  2067. if (f == NULL)
  2068. {
  2069. printf(" (job completed)n");
  2070. errno = 0;
  2071. continue;
  2072. }
  2073. w->w_name[0] = 'd';
  2074. (void) snprintf(qf, sizeof qf, "%s/%s", qddf, w->w_name);
  2075. if (stat(qf, &st) >= 0)
  2076. dfsize = st.st_size;
  2077. else
  2078. dfsize = -1;
  2079. if (w->w_lock)
  2080. printf("*");
  2081. else if (w->w_tooyoung)
  2082. printf("-");
  2083. else if (shouldqueue(w->w_pri, w->w_ctime))
  2084. printf("X");
  2085. else
  2086. printf(" ");
  2087. errno = 0;
  2088. statmsg[0] = bodytype[0] = '';
  2089. qfver = 0;
  2090. while (fgets(buf, sizeof buf, f) != NULL)
  2091. {
  2092. register int i;
  2093. register char *p;
  2094. fixcrlf(buf, TRUE);
  2095. switch (buf[0])
  2096. {
  2097.   case 'V': /* queue file version */
  2098. qfver = atoi(&buf[1]);
  2099. break;
  2100.   case 'M': /* error message */
  2101. if ((i = strlen(&buf[1])) >= sizeof statmsg)
  2102. i = sizeof statmsg - 1;
  2103. memmove(statmsg, &buf[1], i);
  2104. statmsg[i] = '';
  2105. break;
  2106.   case 'B': /* body type */
  2107. if ((i = strlen(&buf[1])) >= sizeof bodytype)
  2108. i = sizeof bodytype - 1;
  2109. memmove(bodytype, &buf[1], i);
  2110. bodytype[i] = '';
  2111. break;
  2112.   case 'S': /* sender name */
  2113. if (Verbose)
  2114. printf("%8ld %10ld%c%.12s %.78s",
  2115.        dfsize,
  2116.        w->w_pri,
  2117.        bitset(EF_WARNING, flags) ? '+' : ' ',
  2118.        ctime(&submittime) + 4,
  2119.        &buf[1]);
  2120. else
  2121. printf("%8ld %.16s %.40s", dfsize,
  2122.     ctime(&submittime), &buf[1]);
  2123. if (statmsg[0] != '' || bodytype[0] != '')
  2124. {
  2125. printf("n    %10.10s", bodytype);
  2126. if (statmsg[0] != '')
  2127. printf("   (%.*s)",
  2128.        Verbose ? 100 : 60,
  2129.        statmsg);
  2130. }
  2131. break;
  2132.   case 'C': /* controlling user */
  2133. if (Verbose)
  2134. printf("ntttt      (---%.74s---)",
  2135.        &buf[1]);
  2136. break;
  2137.   case 'R': /* recipient name */
  2138. p = &buf[1];
  2139. if (qfver >= 1)
  2140. {
  2141. p = strchr(p, ':');
  2142. if (p == NULL)
  2143. break;
  2144. p++;
  2145. }
  2146. if (Verbose)
  2147. printf("nttttt      %.73s", p);
  2148. else
  2149. printf("ntttt       %.40s", p);
  2150. break;
  2151.   case 'T': /* creation time */
  2152. submittime = atol(&buf[1]);
  2153. break;
  2154.   case 'F': /* flag bits */
  2155. for (p = &buf[1]; *p != ''; p++)
  2156. {
  2157. switch (*p)
  2158. {
  2159.   case 'w':
  2160. flags |= EF_WARNING;
  2161. break;
  2162. }
  2163. }
  2164. }
  2165. }
  2166. if (submittime == (time_t) 0)
  2167. printf(" (no control file)");
  2168. printf("n");
  2169. (void) fclose(f);
  2170. }
  2171. return nrequests;
  2172. }
  2173. /*
  2174. **  QUEUENAME -- build a file name in the queue directory for this envelope.
  2175. **
  2176. ** Parameters:
  2177. ** e -- envelope to build it in/from.
  2178. ** type -- the file type, used as the first character
  2179. ** of the file name.
  2180. **
  2181. ** Returns:
  2182. ** a pointer to the queue name (in a static buffer).
  2183. **
  2184. ** Side Effects:
  2185. ** If no id code is already assigned, queuename() will
  2186. ** assign an id code with assign_queueid().  If no queue
  2187. ** directory is assigned, one will be set with setnewqueue().
  2188. */
  2189. char *
  2190. queuename(e, type)
  2191. register ENVELOPE *e;
  2192. int type;
  2193. {
  2194. char *sub = "";
  2195. static char buf[MAXPATHLEN];
  2196. /* Assign an ID if needed */
  2197. if (e->e_id == NULL)
  2198. assign_queueid(e);
  2199. /* Assign a queue directory if needed */
  2200. if (e->e_queuedir == NOQDIR)
  2201. setnewqueue(e);
  2202. if (e->e_queuedir == NOQDIR)
  2203. (void) snprintf(buf, sizeof buf, "%cf%s",
  2204. type, e->e_id);
  2205. else
  2206. {
  2207. switch (type)
  2208. {
  2209.   case 'd':
  2210. if (bitset(QP_SUBDF, QPaths[e->e_queuedir].qp_subdirs))
  2211. sub = "/df";
  2212. break;
  2213.   case 'T':
  2214.   case 't':
  2215.   case 'Q':
  2216.   case 'q':
  2217. if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs))
  2218. sub = "/qf";
  2219. break;
  2220.   case 'x':
  2221. if (bitset(QP_SUBXF, QPaths[e->e_queuedir].qp_subdirs))
  2222. sub = "/xf";
  2223. break;
  2224. }
  2225. (void) snprintf(buf, sizeof buf, "%s%s/%cf%s",
  2226. QPaths[e->e_queuedir].qp_name,
  2227. sub, type, e->e_id);
  2228. }
  2229. if (tTd(7, 2))
  2230. dprintf("queuename: %sn", buf);
  2231. return buf;
  2232. }
  2233. /*
  2234. **  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
  2235. **
  2236. ** Assigns an id code if one does not already exist.
  2237. ** This code assumes that nothing will remain in the queue for
  2238. ** longer than 60 years.  It is critical that files with the given
  2239. ** name not already exist in the queue.
  2240. ** Also initializes e_queuedir to NOQDIR.
  2241. **
  2242. ** Parameters:
  2243. ** e -- envelope to set it in.
  2244. **
  2245. ** Returns:
  2246. ** none.
  2247. */
  2248. static char Base60Code[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
  2249. void
  2250. assign_queueid(e)
  2251. register ENVELOPE *e;
  2252. {
  2253. pid_t pid = getpid();
  2254. static char cX = 0;
  2255. static long random_offset;
  2256. struct tm *tm;
  2257. char idbuf[MAXQFNAME - 2];
  2258. if (e->e_id != NULL)
  2259. return;
  2260. /* see if we need to get a new base time/pid */
  2261. if (cX >= 60 || LastQueueTime == 0 || LastQueuePid != pid)
  2262. {
  2263. time_t then = LastQueueTime;
  2264. /* if the first time through, pick a random offset */
  2265. if (LastQueueTime == 0)
  2266. random_offset = get_random();
  2267. while ((LastQueueTime = curtime()) == then &&
  2268.        LastQueuePid == pid)
  2269. {
  2270. (void) sleep(1);
  2271. }
  2272. LastQueuePid = getpid();
  2273. cX = 0;
  2274. }
  2275. if (tTd(7, 50))
  2276. dprintf("assign_queueid: random_offset = %ld (%d)n",
  2277. random_offset, (int)(cX + random_offset) % 60);
  2278. tm = gmtime(&LastQueueTime);
  2279. idbuf[0] = Base60Code[tm->tm_year % 60];
  2280. idbuf[1] = Base60Code[tm->tm_mon];
  2281. idbuf[2] = Base60Code[tm->tm_mday];
  2282. idbuf[3] = Base60Code[tm->tm_hour];
  2283. idbuf[4] = Base60Code[tm->tm_min];
  2284. idbuf[5] = Base60Code[tm->tm_sec];
  2285. idbuf[6] = Base60Code[((int)cX++ + random_offset) % 60];
  2286. (void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d",
  2287. (int) LastQueuePid);
  2288. e->e_id = newstr(idbuf);
  2289. define('i', e->e_id, e);
  2290. e->e_queuedir = NOQDIR;
  2291. if (tTd(7, 1))
  2292. dprintf("assign_queueid: assigned id %s, e=%lxn",
  2293. e->e_id, (u_long) e);
  2294. if (LogLevel > 93)
  2295. sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
  2296. }
  2297. /*
  2298. **  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
  2299. **
  2300. ** Make sure one PID can't be used by two processes in any one second.
  2301. **
  2302. ** If the system rotates PIDs fast enough, may get the
  2303. ** same pid in the same second for two distinct processes.
  2304. ** This will interfere with the queue file naming system.
  2305. **
  2306. ** Parameters:
  2307. ** none
  2308. **
  2309. ** Returns:
  2310. ** none
  2311. */
  2312. void
  2313. sync_queue_time()
  2314. {
  2315. # if FAST_PID_RECYCLE
  2316. if (OpMode != MD_TEST &&
  2317.     OpMode != MD_VERIFY &&
  2318.     LastQueueTime > 0 &&
  2319.     LastQueuePid == getpid() &&
  2320.     curtime() == LastQueueTime)
  2321. (void) sleep(1);
  2322. # endif /* FAST_PID_RECYCLE */
  2323. }
  2324. /*
  2325. **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
  2326. **
  2327. ** Parameters:
  2328. ** e -- the envelope to unlock.
  2329. **
  2330. ** Returns:
  2331. ** none
  2332. **
  2333. ** Side Effects:
  2334. ** unlocks the queue for `e'.
  2335. */
  2336. void
  2337. unlockqueue(e)
  2338. ENVELOPE *e;
  2339. {
  2340. if (tTd(51, 4))
  2341. dprintf("unlockqueue(%s)n",
  2342. e->e_id == NULL ? "NOQUEUE" : e->e_id);
  2343. /* if there is a lock file in the envelope, close it */
  2344. if (e->e_lockfp != NULL)
  2345. (void) fclose(e->e_lockfp);
  2346. e->e_lockfp = NULL;
  2347. /* don't create a queue id if we don't already have one */
  2348. if (e->e_id == NULL)
  2349. return;
  2350. /* remove the transcript */
  2351. if (LogLevel > 87)
  2352. sm_syslog(LOG_DEBUG, e->e_id, "unlock");
  2353. if (!tTd(51, 104))
  2354. xunlink(queuename(e, 'x'));
  2355. }
  2356. /*
  2357. **  SETCTLUSER -- create a controlling address
  2358. **
  2359. ** Create a fake "address" given only a local login name; this is
  2360. ** used as a "controlling user" for future recipient addresses.
  2361. **
  2362. ** Parameters:
  2363. ** user -- the user name of the controlling user.
  2364. ** qfver -- the version stamp of this qf file.
  2365. **
  2366. ** Returns:
  2367. ** An address descriptor for the controlling user.
  2368. **
  2369. ** Side Effects:
  2370. ** none.
  2371. */
  2372. static ADDRESS *
  2373. setctluser(user, qfver)
  2374. char *user;
  2375. int qfver;
  2376. {
  2377. register ADDRESS *a;
  2378. struct passwd *pw;
  2379. char *p;
  2380. /*
  2381. **  See if this clears our concept of controlling user.
  2382. */
  2383. if (user == NULL || *user == '')
  2384. return NULL;
  2385. /*
  2386. **  Set up addr fields for controlling user.
  2387. */
  2388. a = (ADDRESS *) xalloc(sizeof *a);
  2389. memset((char *) a, '', sizeof *a);
  2390. if (*user == '')
  2391. {
  2392. p = NULL;
  2393. a->q_user = newstr(DefUser);
  2394. }
  2395. else if (*user == ':')
  2396. {
  2397. p = &user[1];
  2398. a->q_user = newstr(p);
  2399. }
  2400. else
  2401. {
  2402. p = strtok(user, ":");
  2403. a->q_user = newstr(user);
  2404. if (qfver >= 2)
  2405. {
  2406. if ((p = strtok(NULL, ":")) != NULL)
  2407. a->q_uid = atoi(p);
  2408. if ((p = strtok(NULL, ":")) != NULL)
  2409. a->q_gid = atoi(p);
  2410. if ((p = strtok(NULL, ":")) != NULL)
  2411. a->q_flags |= QGOODUID;
  2412. }
  2413. else if ((pw = sm_getpwnam(user)) != NULL)
  2414. {
  2415. if (strcmp(pw->pw_dir, "/") == 0)
  2416. a->q_home = "";
  2417. else
  2418. a->q_home = newstr(pw->pw_dir);
  2419. a->q_uid = pw->pw_uid;
  2420. a->q_gid = pw->pw_gid;
  2421. a->q_flags |= QGOODUID;
  2422. }
  2423. }
  2424. a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
  2425. a->q_mailer = LocalMailer;
  2426. if (p == NULL)
  2427. a->q_paddr = newstr(a->q_user);
  2428. else
  2429. a->q_paddr = newstr(p);
  2430. return a;
  2431. }
  2432. /*
  2433. **  LOSEQFILE -- save the qf as Qf and try to let someone know
  2434. **
  2435. ** Parameters:
  2436. ** e -- the envelope (e->e_id will be used).
  2437. ** why -- reported to whomever can hear.
  2438. **
  2439. ** Returns:
  2440. ** none.
  2441. */
  2442. void
  2443. loseqfile(e, why)
  2444. register ENVELOPE *e;
  2445. char *why;
  2446. {
  2447. char *p;
  2448. char buf[MAXPATHLEN];
  2449. if (e == NULL || e->e_id == NULL)
  2450. return;
  2451. p = queuename(e, 'q');
  2452. if (strlen(p) >= (SIZE_T) sizeof buf)
  2453. return;
  2454. (void) strlcpy(buf, p, sizeof buf);
  2455. p = queuename(e, 'Q');
  2456. if (rename(buf, p) < 0)
  2457. syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
  2458. else if (LogLevel > 0)
  2459. sm_syslog(LOG_ALERT, e->e_id,
  2460.   "Losing %s: %s", buf, why);
  2461. }
  2462. /*
  2463. **  QID_PRINTNAME -- create externally printable version of queue id
  2464. **
  2465. ** Parameters:
  2466. ** e -- the envelope.
  2467. **
  2468. ** Returns:
  2469. ** a printable version
  2470. */
  2471. char *
  2472. qid_printname(e)
  2473. ENVELOPE *e;
  2474. {
  2475. char *id;
  2476. static char idbuf[MAXQFNAME + 34];
  2477. if (e == NULL)
  2478. return "";
  2479. if (e->e_id == NULL)
  2480. id = "";
  2481. else
  2482. id = e->e_id;
  2483. if (e->e_queuedir == NOQDIR)
  2484. return id;
  2485. (void) snprintf(idbuf, sizeof idbuf, "%.32s/%s",
  2486. QPaths[e->e_queuedir].qp_name, id);
  2487. return idbuf;
  2488. }
  2489. /*
  2490. **  QID_PRINTQUEUE -- create full version of queue directory for df files
  2491. **
  2492. ** Parameters:
  2493. ** queuedir -- the short version of the queue directory
  2494. **
  2495. ** Returns:
  2496. ** the full pathname to the queue (static)
  2497. */
  2498. char *
  2499. qid_printqueue(queuedir)
  2500. int queuedir;
  2501. {
  2502. char *subdir;
  2503. static char dir[MAXPATHLEN];
  2504. if (queuedir == NOQDIR)
  2505. return QueueDir;
  2506. if (strcmp(QPaths[queuedir].qp_name, ".") == 0)
  2507. subdir = NULL;
  2508. else
  2509. subdir = QPaths[queuedir].qp_name;
  2510. (void) snprintf(dir, sizeof dir, "%s%s%s%s", QueueDir,
  2511. subdir == NULL ? "" : "/",
  2512. subdir == NULL ? "" : subdir,
  2513. (bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
  2514. return dir;
  2515. }
  2516. /*
  2517. **  SETNEWQUEUE -- Sets a new queue directory
  2518. **
  2519. ** Assign a queue directory to an envelope and store the directory
  2520. ** in e->e_queuedir.  The queue is chosen at random.
  2521. **
  2522. ** This routine may be improved in the future to allow for more
  2523. ** elaborate queueing schemes.  Suggestions and code contributions
  2524. ** are welcome.
  2525. **
  2526. ** Parameters:
  2527. ** e -- envelope to assign a queue for.
  2528. **
  2529. ** Returns:
  2530. ** none.
  2531. */
  2532. void
  2533. setnewqueue(e)
  2534. ENVELOPE *e;
  2535. {
  2536. int idx;
  2537. if (tTd(41, 20))
  2538. dprintf("setnewqueue: calledn");
  2539. if (e->e_queuedir != NOQDIR)
  2540. {
  2541. if (tTd(41, 20))
  2542. dprintf("setnewqueue: e_queuedir already assigned (%s)n",
  2543. qid_printqueue(e->e_queuedir));
  2544. return;
  2545. }
  2546. if (NumQueues == 1)
  2547. idx = 0;
  2548. else
  2549. {
  2550. idx = get_random() % NumQueues;
  2551. if (tTd(41, 15))
  2552. dprintf("setnewqueue: get_random() %% %d = %dn",
  2553. NumQueues, idx);
  2554. }
  2555. e->e_queuedir = idx;
  2556. if (tTd(41, 3))
  2557. dprintf("setnewqueue: Assigned queue directory %sn",
  2558. qid_printqueue(e->e_queuedir));
  2559. }
  2560. /*
  2561. **  CHKQDIR -- check a queue directory
  2562. **
  2563. ** Parameters:
  2564. ** name -- name of queue directory
  2565. ** sff -- flags for safefile()
  2566. **
  2567. ** Returns:
  2568. ** is it a queue directory?
  2569. */
  2570. static bool
  2571. chkqdir(name, sff)
  2572. char *name;
  2573. long sff;
  2574. {
  2575. struct stat statb;
  2576. int i;
  2577. # if HASLSTAT
  2578. if (lstat(name, &statb) < 0)
  2579. # else /* HASLSTAT */
  2580. if (stat(name, &statb) < 0)
  2581. # endif /* HASLSTAT */
  2582. {
  2583. if (tTd(41, 2))
  2584. dprintf("multiqueue_cache: stat("%s"): %sn",
  2585. name, errstring(errno));
  2586. return FALSE;
  2587. }
  2588. # if HASLSTAT
  2589. if (S_ISLNK(statb.st_mode))
  2590. {
  2591. /*
  2592. **  For a symlink we need to make sure the
  2593. **  target is a directory
  2594. */
  2595. if (stat(name, &statb) < 0)
  2596. {
  2597. if (tTd(41, 2))
  2598. dprintf("multiqueue_cache: stat("%s"): %sn",
  2599. name, errstring(errno));
  2600. return FALSE;
  2601. }
  2602. }
  2603. # endif /* HASLSTAT */
  2604. if (!S_ISDIR(statb.st_mode))
  2605. {
  2606. if (tTd(41, 2))
  2607. dprintf("multiqueue_cache: "%s": Not a directoryn",
  2608. name);
  2609. return FALSE;
  2610. }
  2611. /* Print a warning if unsafe (but still use it) */
  2612. i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
  2613. if (i != 0 && tTd(41, 2))
  2614. dprintf("multiqueue_cache: "%s": Not safe: %sn",
  2615. name, errstring(i));
  2616. return TRUE;
  2617. }
  2618. /*
  2619. **  MULTIQUEUE_CACHE -- cache a list of paths to queues.
  2620. **
  2621. ** Each potential queue is checked as the cache is built.
  2622. ** Thereafter, each is blindly trusted.
  2623. ** Note that we can be called again after a timeout to rebuild
  2624. ** (although code for that is not ready yet).
  2625. **
  2626. ** Parameters:
  2627. ** none
  2628. **
  2629. ** Returns:
  2630. ** none
  2631. */
  2632. void
  2633. multiqueue_cache()
  2634. {
  2635. register DIR *dp;
  2636. register struct dirent *d;
  2637. char *cp;
  2638. int i, len;
  2639. int slotsleft = 0;
  2640. long sff = SFF_ANYFILE;
  2641. char qpath[MAXPATHLEN];
  2642. char subdir[MAXPATHLEN];
  2643. if (tTd(41, 20))
  2644. dprintf("multiqueue_cache: calledn");
  2645. if (NumQueues != 0 && QPaths != NULL)
  2646. {
  2647. for (i = 0; i < NumQueues; i++)
  2648. {
  2649. if (QPaths[i].qp_name != NULL)
  2650. (void) free(QPaths[i].qp_name);
  2651. }
  2652. (void) free((char *)QPaths);
  2653. QPaths = NULL;
  2654. NumQueues = 0;
  2655. }
  2656. /* If running as root, allow safedirpath() checks to use privs */
  2657. if (RunAsUid == 0)
  2658. sff |= SFF_ROOTOK;
  2659. (void) snprintf(qpath, sizeof qpath, "%s", QueueDir);
  2660. len = strlen(qpath) - 1;
  2661. cp = &qpath[len];
  2662. if (*cp == '*')
  2663. {
  2664. *cp = '';
  2665. if ((cp = strrchr(qpath, '/')) == NULL)
  2666. {
  2667. syserr("QueueDirectory: can not wildcard relative path");
  2668. if (tTd(41, 2))
  2669. dprintf("multiqueue_cache: "%s": Can not wildcard relative path.n",
  2670. QueueDir);
  2671. ExitStat = EX_CONFIG;
  2672. return;
  2673. }
  2674. if (cp == qpath)
  2675. {
  2676. /*
  2677. **  Special case of top level wildcard, like /foo*
  2678. */
  2679. (void) snprintf(qpath + 1, sizeof qpath - 1,
  2680. "%s", qpath);
  2681. ++cp;
  2682. }
  2683. *(cp++) = '';
  2684. len = strlen(cp);
  2685. if (tTd(41, 2))
  2686. dprintf("multiqueue_cache: prefix="%s"n", cp);
  2687. QueueDir = newstr(qpath);
  2688. /*
  2689. **  XXX Should probably wrap this whole loop in a timeout
  2690. **  in case some wag decides to NFS mount the queues.
  2691. */
  2692. /* test path to get warning messages */
  2693. i= safedirpath(QueueDir, RunAsUid, RunAsGid, NULL, sff, 0, 0);
  2694. if (i != 0 && tTd(41, 2))
  2695. dprintf("multiqueue_cache: "%s": Not safe: %sn",
  2696. QueueDir, errstring(i));
  2697. if (chdir(QueueDir) < 0)
  2698. {
  2699. syserr("can not chdir(%s)", QueueDir);
  2700. if (tTd(41, 2))
  2701. dprintf("multiqueue_cache: "%s": %sn",
  2702. qpath, errstring(errno));
  2703. ExitStat = EX_CONFIG;
  2704. return;
  2705. }
  2706. if ((dp = opendir(".")) == NULL)
  2707. {
  2708. syserr("can not opendir(%s)", QueueDir);
  2709. if (tTd(41, 2))
  2710. dprintf("multiqueue_cache: opendir("%s"): %sn",
  2711. QueueDir, errstring(errno));
  2712. ExitStat = EX_CONFIG;
  2713. return;
  2714. }
  2715. while ((d = readdir(dp)) != NULL)
  2716. {
  2717. if (strncmp(d->d_name, cp, len) != 0)
  2718. {
  2719. if (tTd(41, 5))
  2720. dprintf("multiqueue_cache: "%s", skippedn",
  2721. d->d_name);
  2722. continue;
  2723. }
  2724. if (!chkqdir(d->d_name, sff))
  2725. continue;
  2726. if (QPaths == NULL)
  2727. {
  2728. slotsleft = 20;
  2729. QPaths = (QPATHS *)xalloc((sizeof *QPaths) *
  2730.   slotsleft);
  2731. NumQueues = 0;
  2732. }
  2733. else if (slotsleft < 1)
  2734. {
  2735. QPaths = (QPATHS *)realloc((char *)QPaths,
  2736.   (sizeof *QPaths) *
  2737.   (NumQueues + 10));
  2738. if (QPaths == NULL)
  2739. {
  2740. (void) closedir(dp);
  2741. return;
  2742. }
  2743. slotsleft += 10;
  2744. }
  2745. /* check subdirs */
  2746. QPaths[NumQueues].qp_subdirs = QP_NOSUB;
  2747. (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
  2748. qpath, d->d_name, "qf");
  2749. if (chkqdir(subdir, sff))
  2750. QPaths[NumQueues].qp_subdirs |= QP_SUBQF;
  2751. (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
  2752. qpath, d->d_name, "df");
  2753. if (chkqdir(subdir, sff))
  2754. QPaths[NumQueues].qp_subdirs |= QP_SUBDF;
  2755. (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
  2756. qpath, d->d_name, "xf");
  2757. if (chkqdir(subdir, sff))
  2758. QPaths[NumQueues].qp_subdirs |= QP_SUBXF;
  2759. /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
  2760. /* maybe even - 17 (subdirs) */
  2761. QPaths[NumQueues].qp_name = newstr(d->d_name);
  2762. if (tTd(41, 2))
  2763. dprintf("multiqueue_cache: %d: "%s" cached (%x).n",
  2764. NumQueues, d->d_name,
  2765. QPaths[NumQueues].qp_subdirs);
  2766. NumQueues++;
  2767. slotsleft--;
  2768. }
  2769. (void) closedir(dp);
  2770. }
  2771. if (NumQueues == 0)
  2772. {
  2773. if (*cp != '*' && tTd(41, 2))
  2774. dprintf("multiqueue_cache: "%s": No wildcard suffix charactern",
  2775. QueueDir);
  2776. QPaths = (QPATHS *)xalloc(sizeof *QPaths);
  2777. QPaths[0].qp_name = newstr(".");
  2778. QPaths[0].qp_subdirs = QP_NOSUB;
  2779. NumQueues = 1;
  2780. /* test path to get warning messages */
  2781. (void) safedirpath(QueueDir, RunAsUid, RunAsGid,
  2782.    NULL, sff, 0, 0);
  2783. if (chdir(QueueDir) < 0)
  2784. {
  2785. syserr("can not chdir(%s)", QueueDir);
  2786. if (tTd(41, 2))
  2787. dprintf("multiqueue_cache: "%s": %sn",
  2788. QueueDir, errstring(errno));
  2789. ExitStat = EX_CONFIG;
  2790. }
  2791. /* check subdirs */
  2792. (void) snprintf(subdir, sizeof subdir, "%s/qf", QueueDir);
  2793. if (chkqdir(subdir, sff))
  2794. QPaths[0].qp_subdirs |= QP_SUBQF;
  2795. (void) snprintf(subdir, sizeof subdir, "%s/df", QueueDir);
  2796. if (chkqdir(subdir, sff))
  2797. QPaths[0].qp_subdirs |= QP_SUBDF;
  2798. (void) snprintf(subdir, sizeof subdir, "%s/xf", QueueDir);
  2799. if (chkqdir(subdir, sff))
  2800. QPaths[0].qp_subdirs |= QP_SUBXF;
  2801. }
  2802. }
  2803. # if 0
  2804. /*
  2805. **  HASHFQN -- calculate a hash value for a fully qualified host name
  2806. **
  2807. ** Arguments:
  2808. ** fqn -- an all lower-case host.domain string
  2809. ** buckets -- the number of buckets (queue directories)
  2810. **
  2811. ** Returns:
  2812. ** a bucket number (signed integer)
  2813. ** -1 on error
  2814. **
  2815. ** Contributed by Exactis.com, Inc.
  2816. */
  2817. int
  2818. hashfqn(fqn, buckets)
  2819. register char *fqn;
  2820. int buckets;
  2821. {
  2822. register char *p;
  2823. register int h = 0, hash, cnt;
  2824. #  define WATERINC (1000)
  2825. if (fqn == NULL)
  2826. return -1;
  2827. /*
  2828. **  A variation on the gdb hash
  2829. **  This is the best as of Feb 19, 1996 --bcx
  2830. */
  2831. p = fqn;
  2832. h = 0x238F13AF * strlen(p);
  2833. for (cnt = 0; *p != 0; ++p, cnt++)
  2834. {
  2835. h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
  2836. }
  2837. h = (1103515243 * h + 12345) & 0x7FFFFFFF;
  2838. if (buckets < 2)
  2839. hash = 0;
  2840. else
  2841. hash = (h % buckets);
  2842. return hash;
  2843. }
  2844. # endif /* 0 */
  2845. # if _FFR_QUEUEDELAY
  2846. /*
  2847. **  QUEUEDELAY -- compute queue delay time
  2848. **
  2849. ** Parameters:
  2850. ** e -- the envelope to queue up.
  2851. **
  2852. ** Returns:
  2853. ** queue delay time
  2854. **
  2855. ** Side Effects:
  2856. ** may change e_queuedelay
  2857. */
  2858. static time_t
  2859. queuedelay(e)
  2860. ENVELOPE *e;
  2861. {
  2862. time_t qd;
  2863. if (e->e_queuealg == QD_EXP)
  2864. {
  2865. if (e->e_queuedelay == 0)
  2866. e->e_queuedelay = QueueInitDelay;
  2867. else
  2868. {
  2869. e->e_queuedelay *= 2;
  2870. if (e->e_queuedelay > QueueMaxDelay)
  2871. e->e_queuedelay = QueueMaxDelay;
  2872. }
  2873. qd = e->e_queuedelay;
  2874. }
  2875. else
  2876. qd = MinQueueAge;
  2877. return qd;
  2878. }
  2879. # endif /* _FFR_QUEUEDELAY */
  2880. #endif /* QUEUE */