home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume16 / plp / part15 < prev    next >
Text File  |  1988-09-22  |  52KB  |  1,664 lines

  1. Subject:  v16i028:  Public lineprinter spooler package, Part15/16
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: papowell@julius.cs.umn.edu
  7. Posting-number: Volume 16, Issue 28
  8. Archive-name: plp/part15
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 15 (of 16)."
  17. # Contents:  src/lp.h src/utils.c
  18. # Wrapped by papowell@attila on Wed Aug 10 10:45:12 1988
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'src/lp.h' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'src/lp.h'\"
  22. else
  23. echo shar: Extracting \"'src/lp.h'\" \(23350 characters\)
  24. sed "s/^X//" >'src/lp.h' <<'END_OF_FILE'
  25. X/*************************************************************************
  26. X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
  27. X *************************************************************************
  28. X * MODULE: lp.h
  29. X * Includes and definitions for all programs
  30. X *************************************************************************
  31. X * Revision History: Created Sun Jan  3 15:37:08 CST 1988
  32. X * $Header: lp.h,v 3.2 88/06/24 17:15:52 papowell Exp $
  33. X * $Log:    lp.h,v $
  34. X * Revision 3.2  88/06/24  17:15:52  papowell
  35. X * MODS for VAX 4.3BSD UNIX
  36. X * 
  37. X * 
  38. X * Revision 3.1  88/06/18  09:34:30  papowell
  39. X * Version 3.0- Distributed Sat Jun 18 1988
  40. X * 
  41. X * Revision 2.3  88/05/29  13:09:55  papowell
  42. X * Added Header string for RCS purposes
  43. X * 
  44. X * Revision 2.2  88/05/14  10:18:16  papowell
  45. X * Use long format for job file names;
  46. X * Added 'fd', no forward flag;
  47. X * Control file has to have hostname and origination agree.
  48. X * 
  49. X * Revision 2.1  88/05/09  10:10:48  papowell
  50. X * PLP: Released Version
  51. X * 
  52. X * Revision 1.12  88/05/09  10:03:39  papowell
  53. X * Revised effects of -h option
  54. X * 
  55. X * Revision 1.11  88/05/05  20:08:53  papowell
  56. X * Added a NOHEADER option that allows user to suppress banner
  57. X * 
  58. X * Revision 1.10  88/04/29  07:48:55  papowell
  59. X * Added USE_LOCKF flags
  60. X * 
  61. X * Revision 1.9  88/04/28  17:32:47  papowell
  62. X * fixed Data General Options
  63. X * 
  64. X * Revision 1.8  88/04/21  21:49:40  papowell
  65. X * BADSETREUID: this flag is provided for situations where setreuid()
  66. X * does not allow changing back to root after changing to a user.
  67. X * This is a problem in security,  and should be avoided.
  68. X * 
  69. X * Revision 1.7  88/04/07  12:29:13  papowell
  70. X * Removed AF_UNIX socket definitions
  71. X * 
  72. X * Revision 1.6  88/04/07  09:09:23  papowell
  73. X * Apollo Workstation Modifications
  74. X * 
  75. X * Revision 1.5  88/04/06  12:13:40  papowell
  76. X * Minor updates, changes in error message formats.
  77. X * Elimination of the AF_UNIX connections, use AF_INET only.
  78. X * Better error messages.
  79. X * 
  80. X * Revision 1.4  88/03/25  14:59:54  papowell
  81. X * Debugged Version:
  82. X * 1. Added the PLP control file first transfer
  83. X * 2. Checks for MX during file transfers
  84. X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
  85. X *     apparently they open files and then assume that they will stay
  86. X *     open.
  87. X * 4. Made sure that stdin, stdout, stderr was available at all times.
  88. X * 
  89. X * Revision 1.3  88/03/11  19:29:10  papowell
  90. X * Minor Changes, Updates
  91. X * 
  92. X * Revision 1.2  88/03/05  15:02:09  papowell
  93. X * Minor Corrections,  Lint Problems
  94. X * 
  95. X * Revision 1.1  88/03/01  12:42:54  papowell
  96. X * Initial revision
  97. X * 
  98. X *************************************************************************/
  99. X
  100. X/*************************************************************************
  101. X * Make sure that you set the DEBUG flag if XPERIMENT is set
  102. X *
  103. X *************************************************************************/
  104. X#ifdef XPERIMENT
  105. X#define DEBUG 1
  106. X#endif XPERIMENT
  107. X/*************************************************************************
  108. X * Portability Definitions
  109. X * Several systems do not have the same definitions for these items.
  110. X * You will have to add your own local definitions.
  111. X * Ahh...  Dream of the day of a standard set of definitions
  112. X *************************************************************************/
  113. X#ifdef IS_SUN
  114. X#define uid_t    int    /* keep lint on the sun happy */
  115. X#endif IS_SUN
  116. X
  117. X#ifdef IS_VAX4BSD
  118. X#define SETREUID4BSD 1
  119. X#endif IS_VAX4BSD
  120. X
  121. X#ifdef IS_DATAGEN
  122. X#define fd_set    int    /* keep lint happy */
  123. X#define uid_t    int    /* keep lint happy */
  124. X#define NOSYMLINK    /* no symbolic links */
  125. X#define USE_LOCKF    /* use the lockf() function for locking */
  126. X#define F_TLOCK    2    /* test and lock a section (non-blocking) */
  127. X#endif IS_DATAGEN
  128. X
  129. X#ifdef IS_UMAX
  130. X#undef B19200
  131. X#undef B38400
  132. X#define B19200 EXTA
  133. X#define B38400 EXTB
  134. X#define time_t long
  135. X#define uid_t int
  136. X#endif IS_UMAX
  137. X
  138. X#ifdef IS_APOLLO
  139. X#undef B19200
  140. X#undef B38400
  141. X#define B19200 EXTA
  142. X#define B38400 EXTB
  143. X#define uid_t int
  144. X#define USE_STRINGS        /* use <strings.h> instead of <string.h> */
  145. X#define NO_A_OUT_H        /* no a.out.h include file */
  146. X#endif IS_APOLLO
  147. X
  148. X/******************************************************************
  149. X * System Include Files
  150. X ******************************************************************/
  151. X#include <stdio.h>
  152. X#include <sys/param.h>
  153. X#include <sys/types.h>
  154. X#include <sys/file.h>
  155. X#include <sys/dir.h>
  156. X#include <sys/time.h>
  157. X#include <sys/stat.h>
  158. X#include <sys/socket.h>
  159. X#include <sys/resource.h>
  160. X#include <netinet/in.h>
  161. X#include <netdb.h>
  162. X#include <pwd.h>
  163. X#include <signal.h>
  164. X#include <sys/wait.h>
  165. X#include <sgtty.h>
  166. X#include <ctype.h>
  167. X#ifdef USE_STRINGS
  168. X#include <strings.h>
  169. X#else USE_STRINGS
  170. X#include <string.h>
  171. X#endif USE_STRINGS
  172. X#include <errno.h>
  173. X#include <grp.h>
  174. X
  175. X
  176. X/******************************************************************
  177. X * Declare Standard Routines.
  178. X * Note: most of these are not declared in include files.
  179. X * This leads to some interesting problems with LINT. Declare these
  180. X * here.  Some specialized routines are declared in the individual
  181. X * routines that use them.
  182. X ******************************************************************/
  183. extern char    *malloc(), *realloc();
  184. extern char    *getenv();
  185. extern char    *gets();
  186. extern int errno, sys_nerr;
  187. extern char *sys_errlist[];
  188. extern char *index(), *rindex();
  189. extern char *sprintf();    /* sigh... sprintf strikes again */
  190. extern long lseek(), atol();
  191. X
  192. extern uid_t getuid(), geteuid();
  193. extern time_t time();    /* watch this one */
  194. X
  195. X/*
  196. X * This should be declared in <signal.h>
  197. X */
  198. X#ifndef sigmask
  199. X#define sigmask(m)    (1 << ((m)-1))
  200. X#endif
  201. X
  202. X/*************************************************************************
  203. X * PRINTCAP entries and associated variables.
  204. X * Each printcap entry has a corresponding variable; for example
  205. X * ":af=accnt:"
  206. X *   -> AF = "accnt";
  207. X *************************************************************************/
  208. extern int    AB;        /* Always have a banner flag, ignore lpr -h option */
  209. extern char  *AF;        /* accounting file */
  210. extern char  *BP;        /* banner printer filter */
  211. extern int    BK;        /* Berkeley compatible remote and local */
  212. extern int    BR;        /* baud rate if lp is a tty */
  213. extern int    CO;        /* cost of printing in dollars */
  214. extern char  *EP;        /* end printer filter */
  215. extern int    FD;        /* No forwarding, accept only from original site */
  216. extern int    FO;        /* print a form feed when device is opened */
  217. extern int    FC;        /* flags to clear if lp is a tty */
  218. extern char  *FF;        /* form feed string */
  219. extern int    FJ;        /* send control file  first to remote site */
  220. extern int    FQ;        /* form feed on quitting */
  221. extern int    FS;        /* flags to set if lp is a tty */
  222. extern char  *FX;        /* allowable formats */
  223. extern char  *LD;        /* leader string on opening */
  224. extern char  *LF;        /* log file for error messages */
  225. extern int    LH;        /* use long host name */
  226. extern char  *LO;        /* lock file name */
  227. extern char  *LN;        /* group allowed to use links */
  228. extern char  *LP;        /* line printer device name */
  229. extern int    MC;        /* maximum number of copies allowed */
  230. extern int    MX;        /* maximum number of blocks to copy */
  231. extern int    NW;        /* Networked file system, do not make copies */
  232. extern int    PL;        /* page length */
  233. extern char  *PR;        /* pr program name name */
  234. extern char  *PS;        /* printer status file name */
  235. extern int    PW;        /* page width */
  236. extern int    PX;        /* page width in pixels */
  237. extern int    PY;        /* page length in pixels */
  238. extern char  *QH;        /* queue handler */
  239. extern char  *RG;        /* restrict use to group */
  240. extern char  *RM;        /* remote machine name */
  241. extern char  *RP;        /* remote printer name */
  242. extern int    RT;        /* max retries */
  243. extern int    RW;        /* open LP for reading and writing */
  244. extern int    SB;        /* short banner instead of normal header */
  245. extern int    SC;        /* suppress multiple copies */
  246. extern char  *SD;        /* spool directory */
  247. extern int    SF;        /* suppress FF on each print job */
  248. extern int    SH;        /* suppress header page */
  249. extern char  *SS;        /* name of queue that the server serves  */
  250. extern char  *ST;        /* status file name */
  251. extern char  *SV;        /* names of servers */
  252. extern char  *TR;        /* trailer string to be output when Q empties */
  253. extern char  *TY;        /* terminal characteristics, stty options */
  254. extern int    XC;        /* flags to clear for local mode */
  255. extern int    XS;        /* flags to set for local mode */
  256. extern char  *XT;        /* format checked for text only */
  257. extern char  *XU;        /* restrict use to users whose names are in file */
  258. X/*
  259. X * Filter_name[] is an array of filter names, indexed by the first letter
  260. X * of the printcap tag. For example:
  261. X * ":if=/usr/lib/iffilter -n -a:"
  262. X *     -> Filter_name['i'-'a'] = "/usr/lib/iffilter -n -a";
  263. X */
  264. extern char *Filter_name[26];
  265. X#define    IF    (Filter_name['i'-'a'])
  266. X#define    OF    (Filter_name['o'-'a'])
  267. X/*
  268. X * Prefilter_name[] is similar to Filter_name[], but for prefilter entries.
  269. X */
  270. extern char *Prefilter_name[26];
  271. X
  272. X/**********************************************************************
  273. X * Globally accessed variables and routines
  274. X **********************************************************************/
  275. extern char    *Name;                /* program name */
  276. extern char    *Printer;            /* printer name */
  277. extern char *Person;            /* user name */
  278. extern char    Host[64];            /* Host machine name */
  279. extern char    *From;                /* client's machine name */
  280. extern int    Debug;                /* Debugging level */
  281. extern int    Echo_on_stdout;        /* stderr output on stdout as well */
  282. extern char *First_name;        /* first name in printcap entry */
  283. extern FILE *Lfd;                /* lock file */
  284. extern int Optind, Opterr;        /*  option index, error message suppression */
  285. extern char *Optarg;            /*  option value */
  286. extern char *Opt_flag;            /*  option staring flags */
  287. extern char Lpdlogf[];        /* = DEFLPDLOGF; */
  288. extern char Masterlock[];        /*  = MASTERLOCK; */
  289. extern int    Lpr_port_num;        /* port number to connect to */
  290. extern int Maxportno;            /*  = MAXPORTNO; */
  291. extern int Minportno;            /*  = MINPORTNO; */
  292. extern char Permfile[];            /*  = PERMFILE; */
  293. extern char Printcap[];            /*  = PRINTCAP; */
  294. extern char Last_errormsg[];    /* last errormessage */
  295. extern int Request;                /* current lpd request code */
  296. extern int Print_fd;            /* output printer FILE */
  297. extern int Short_format;        /* short status format */
  298. extern int  Is_root;            /* is this the root user? */
  299. extern int  Is_local;            /* doing this locally or remotely? */
  300. extern struct stat LO_statb;    /* used to stat lockfile */
  301. extern void Print_close(), Link_close(); /* close these things */
  302. extern int Daemon_uid;            /* daemon UID */
  303. extern int Daemon_gid;            /* daemon GID */
  304. extern char *estrcp();            /* handy form of strcp() */
  305. extern char *Time_str();        /* ctime with \n removed */
  306. extern char *Setup_filter();    /* set up argv for a filter */
  307. extern int Reapchild();         /* wait3() for a child */
  308. extern int Getopt();            /* get command line option */
  309. extern char *Errormsg();        /* printable error message */
  310. extern int    Errorcode;            /* exit() value on fatal termination */
  311. extern char *Decode_status();    /* decode a status returned by wait() */
  312. extern FILE    *fopen_daemon();    /* open a file as daemon */
  313. extern int    open_daemon();        /* open a file as daemon */
  314. X
  315. X/*******************************************************************
  316. X *  struct queue
  317. X *    used to record entries in the spool directory for printing
  318. X *    and status reporting.
  319. X *  NOTE: control and data file names in spool directory have the form
  320. X *  c f <priority> <job number> <Hostname>  <terminating 0>
  321. X *  d f <seq>      <job number> <Hostname>  <terminating 0>
  322. X *  1 1 1               3         max 64           1
  323. X * eg: dfA001attila.cs.umn.edu         (attila the SUN, of course)
  324. X * eg: cfZ001attila.cs.umn.edu         (attila the SUN, of course)
  325. X *******************************************************************/
  326. X#define CFNAMELEN (sizeof(Host)+8)    /* control or data file name length */
  327. X/*
  328. X * fields in the name
  329. X */
  330. X#define STARTPR    2    /* df[] */
  331. X#define STARTID    3    /* dfX[] */
  332. X#define IDLEN    3    /* dfX[NNN] */
  333. X#define    STARTFR    6    /* dfXNNN[] */
  334. X#define MAXPARMLEN    80
  335. struct queue {
  336. X    char    q_name[CFNAMELEN+1];    /* name of the control file */
  337. X    time_t    q_time;                    /* modification time */
  338. X    time_t    q_sp;                    /* spooled at time */
  339. X    time_t    q_unsp;                    /* unspool at time */
  340. X    int        q_priority;                /* priority */
  341. X    long    q_size;                    /* size of the data files */
  342. X    char    q_user[32];                /* user name */
  343. X    int        q_num;                    /* job number */
  344. X    char    q_data[MAXPARMLEN+1];    /* data files name */
  345. X    int        q_daemon;                /* daemon for this entry */
  346. X    char    *q_server;                /* server for this entry */
  347. X};
  348. X
  349. X#define    q_from    q_name[STARTFR]
  350. extern int Getq();                    /* find queue entries */
  351. extern struct queue *Jobentry;        /* current job entry in queue */
  352. extern struct queue *Queue;            /* Getq generates an array of jobs */
  353. extern int Jobcount;                /* and returns the number of jobs  */
  354. X
  355. extern int Rec_cnt;                    /* number of files in a job */
  356. X
  357. X/********************************************************************
  358. X * File Permissions
  359. X ********************************************************************/
  360. X
  361. X#define LFMODE      0644    /* log file permissions */
  362. X#define FILMOD      0600    /* spooling directory file permission */
  363. X
  364. X/*
  365. X * Queue Control is done by using the permissions of the lock file
  366. X * for the queue.  The following permissions are used:
  367. X *     Disable Printing: owner execute or 0100
  368. X *     Disable Queing:    group execute or 0010
  369. X *     Queue handler active (antique) 0001
  370. X */
  371. X#define    DISABLE_PRINT    (0100)
  372. X#define    ENABLE_PRINT    (0777 & ~ DISABLE_PRINT)
  373. X#define    DISABLE_QUEUE    (0010)
  374. X#define    ENABLE_QUEUE    (0777 & ~ DISABLE_QUEUE)
  375. X#define    FORCE_REQUE        (0001)
  376. X#define    CLEAR_REQUE        (0777 & ~ FORCE_REQUE)
  377. X
  378. X/*
  379. X *  syslog(8) message priorities.  These are defined by the values of
  380. X *  global variables.  The variables are initialized either with values
  381. X *  in the <syslog.h> include file,  or by a set of default values according
  382. X *  to the NOSYSLOG option in the Makefile.
  383. X */
  384. extern int XLOG_ERR;            /*4 synonym of LOG_ERROR */
  385. extern int XLOG_CRIT;            /*5    critical information */
  386. extern int XLOG_WARNING;        /*6    warning */
  387. extern int XLOG_NOTICE;            /*7    important information */
  388. extern int XLOG_INFO;            /*8    informational message */
  389. extern int XLOG_DEBUG;            /*9    Debug level info */
  390. X
  391. X/*******************************************************************
  392. X * Printcap Data Structures
  393. X * The printcap file information is extracted using a single pass of
  394. X * the printcap database.  As each entry is found,  it is looked up
  395. X * in a table which has the entry tag,  the type of entry,
  396. X * a default value,  and the variable used to hold the value.
  397. X *
  398. X * The table is sorted alphabetically by the tag values and the update
  399. X * routines use a modified binary search.  The time taken to read the
  400. X * printcap entry is proportional to
  401. X * K  log( M ), where K is the length of the printcap file and M is
  402. X * the number of printcap variables.  Note that this appears to be
  403. X * a much simpler and easier way to implement printcap information
  404. X * extraction.  The "initialization" of the entire set of variables
  405. X * is extremely fast,  apparently taking about the same time  as reading
  406. X * two variables using the original "termcap" code.
  407. X *******************************************************************/
  408. typedef struct pc_entry{
  409. X    char pc_name[3];    /* two character name, and the last char */
  410. X    int    kind;    /* the kind of entry */
  411. X#        define PC_NUM        0    /* integer */
  412. X#        define PC_FLAG        1    /* integer */
  413. X#        define PC_STRING    2    /* string */
  414. X    int idefault;    /* this is the default integer or flag value */
  415. X    char *sdefault;    /* this is the default integer or flag value */
  416. X    /*
  417. X     * the variable is assumed to be a pointer to char;
  418. X     * this is cast to pointer to int if neccessary. 
  419. X     */
  420. X    char **var;
  421. X} PC_ENTRY;
  422. X
  423. X/*
  424. X * Routines to look up printer names and printcap entries
  425. X * char ** All_printers():  reads the printcap database and extracts the
  426. X *   names of all the printer entries.
  427. X * char *First_printer(): gets name of first printer
  428. X * Get_pc_entry(): given name of a printer and an array  of PC_ENTRIES,
  429. X *  it finds the printcap entry and extracts all the information
  430. X *  for the variables listed in the array.
  431. X * Set_pc_entry(): same functionality, does not initialize variables.
  432. X */
  433. X#define PRNAMELEN    32    /* Maximum of 32 characters for printer name */
  434. X#define MAXPCNAMES    100    /* Maximum of 100 printers */
  435. extern int Get_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */);
  436. extern int Set_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */);
  437. extern char **All_printers();    /* returns array printer names */
  438. extern char *First_printer();    /* returns array printer names */
  439. X/*
  440. X * All_pc_vars[]: all printcap variables, and is used by lpr and lpd;
  441. X * Status_pc_vars[]: a short set needed by lpq, lprm, and lpc.
  442. X * Server_pc_vars[]: a few needed by servers only
  443. X */
  444. extern PC_ENTRY All_pc_vars[ /* All_pc_len */ ];
  445. extern int    All_pc_len;
  446. extern PC_ENTRY Status_pc_vars[ /* Status_pc_len */ ];
  447. extern int    Status_pc_len;
  448. extern PC_ENTRY Server_pc_vars[ /* Server_pc_len */ ];
  449. extern int    Server_pc_len;
  450. X
  451. X/***********************************************************************
  452. X * File Locking Support:
  453. X * see lockfile.c for details.
  454. X ***********************************************************************/
  455. extern FILE *Readlockfile();    /* reads file, returns FILE * */
  456. extern FILE *Getlockfile();        /* locks file, returns FILE * */
  457. extern int   Checklockfile();    /* checks for lock and daemon */
  458. extern FILE *Lockcf();            /* lock a control file */
  459. extern int   Exlockcf();        /* create and lock a control file */
  460. X
  461. X/***********************************************************************
  462. X * Parameter List Support
  463. X * struct parm parmlist[]
  464. X *  is used when parsing a command received from a remote Host
  465. X * It is also used by lpr to determine the command file, and to keep
  466. X * track of the file/datafile name correspondence.
  467. X ***********************************************************************/
  468. X#define MAXPARMS 50
  469. struct parm{
  470. X    char *str;                    /* string parameter */
  471. X    int   num;                    /* number parameter */
  472. X    char filename[CFNAMELEN+1];    /* file name for parameter */
  473. X    long size;                    /* size of file */
  474. X};
  475. extern struct parm Parms[MAXPARMS];        /* array of parmaters */
  476. extern int    Parmcount;                /* number of parameters */
  477. X
  478. X/***********************************************************************
  479. X * Request types
  480. X * A request sent to the LPD daemon has the format:
  481. X * \Xprinter [options],  where \X is a single character or byte value.
  482. X * The following are the values and commands
  483. X ***********************************************************************/
  484. X#define REQ_START    1    /* start printer */
  485. X#define REQ_RECV    2    /* transfer a job to the Host from a remote site */
  486. X#define REQ_DSHORT    3    /* print short form of queue status */
  487. X#define REQ_DLONG    4    /* print long form of queue status */
  488. X#define REQ_REMOVE    5    /* remove jobs */
  489. X#define REQ_CONTROL    6    /* do control operation */
  490. X/**************************************************************************
  491. X *      Control file format
  492. X *      First character is kind of entry, remainder of line is
  493. X *          the argument.
  494. X *
  495. X *        1 -- "R font file" for troff -ignore
  496. X *        2 -- "I font file" for troff -ignore
  497. X *        3 -- "B font file" for troff -ignore
  498. X *        4 -- "S font file" for troff -ignore
  499. X *        C -- "class name" on banner page
  500. X *        H -- "Host name" of machine where lpr was done
  501. X *        I -- "indent" amount to indent output
  502. X *        J -- "job name" on banner page
  503. X *        L -- "literal" user's name to print on banner
  504. X *        M -- "mail" to user when done printing
  505. X *        N -- "name" of file (used by lpq)
  506. X *        P -- "Person" user's login name
  507. X *        R -- account id  for charging 
  508. X *        U -- "unlink" name of file to remove after we print it
  509. X *        W -- "width" page width for PR
  510. X *        X -- "header" header title for PR
  511. X *        Z -- xtra options to filters 
  512. X *
  513. X *        Lower case letters are formats
  514. X *        f -- "file name" name of text file to print
  515. X *        l -- "file name" text file with control chars
  516. X *        p -- "file name" text file to print with pr(1)
  517. X *        t -- "file name" troff(1) file to print
  518. X *        n -- "file name" ditroff(1) file to print
  519. X *        d -- "file name" dvi file to print
  520. X *        g -- "file name" plot(1G) file to print
  521. X *        v -- "file name" plain raster file to print
  522. X *        c -- "file name" cifplot file to print
  523. X *
  524. X * CFparm is used to hold the upper case parameters
  525. X */
  526. extern char CFparm[26][MAXPARMLEN+1];
  527. X#define CLASSNAME CFparm['C'-'A']
  528. X#define WHENSP    CFparm['D'-'A']
  529. X#define FROMHOST  CFparm['H'-'A']
  530. X#define INDENT    CFparm['I'-'A']
  531. X#define JOBNAME   CFparm['J'-'A']
  532. X#define BNRNAME   CFparm['L'-'A']
  533. X#define FILENAME  CFparm['N'-'A']
  534. X#define MAILNAME  CFparm['M'-'A']
  535. X#define LOGNAME   CFparm['P'-'A']
  536. X#define ACCNTNAME CFparm['R'-'A']
  537. X#define NOHEADER  CFparm['S'-'A']
  538. X#define WHENUNSP  CFparm['T'-'A']
  539. X#define UNLNKFILE CFparm['U'-'A']
  540. X#define PWIDTH    CFparm['W'-'A']
  541. X#define PRTITLE   CFparm['X'-'A']
  542. X#define ZOPTS     CFparm['Z'-'A']
  543. X
  544. X/*
  545. X * printjob return codes
  546. X */
  547. X#define JBUSY    -1              /* being done by other means */
  548. X#define JFAIL     0                /* repeat with retry */
  549. X#define JSUCC     1                /* done */
  550. X#define JABORT   2                /* done, but problems */
  551. X
  552. X/*
  553. X * Mail program
  554. X */
  555. X#ifndef MAIL
  556. X#define MAIL "/usr/lib/sendmail"
  557. X#endif MAIL
  558. X
  559. X/*
  560. X * File Transfer Protocol Flags
  561. X */
  562. X#define CEND 5        /* last file */
  563. X#define CNAME 4        /* control file */
  564. X#define DFILE 3        /* data file */
  565. X#define CFILE 2        /* control file */
  566. X
  567. X/*
  568. X * Local parameters to the spooling system
  569. X * Defaults for line printer capabilities data base
  570. X */
  571. X#define DEFLOGF        "log"
  572. X#define DEFLOCK        "lock"
  573. X#define DEFSTAT        "status"
  574. X#define DEFACCT        "acct"
  575. X#define    DEFFORMATS    "flp"    /* default formats */
  576. X#define    DEFMX        1000
  577. X#define    DEFRETRY    3        /* maximum number of retries */
  578. X#define DEFMAXCOPIES    0
  579. X#define DEFFF        "\f"
  580. X#define DEFWIDTH    132
  581. X#define DEFLENGTH    66
  582. X#define DAEMON        "daemon"    /* daemon user id */
  583. X#define DEFPRICE    20    /* cost in dollars per thousand pages */
  584. X#define DEFPRIORITY    'Z'    /* default priority level */
  585. X#define DEFPR        "/bin/pr"    /* default pr program */
  586. X
  587. X/*
  588. X * REAL, not TEST version
  589. X */
  590. X
  591. X/*
  592. X * path name of files created by lpd.
  593. X */
  594. X#define RMASTERLOCK    "/usr/spool/lpd/lpd.lock."
  595. X#define    RDEFLPDLOGF        "/usr/spool/lpd/lpd.log."
  596. X#ifdef    ETCPC
  597. X#    define RPRINTCAP    ETCPC
  598. X#else
  599. X#    define RPRINTCAP    "/usr/spool/lpd/printcap."
  600. X#endif
  601. X/*
  602. X * connection services to be used
  603. X */
  604. X#define SERVERNAME    "printer"
  605. X#define SERVERPROT    "tcp"
  606. X/* name of the printer permissions file */
  607. X#ifdef    ETCPERMS
  608. X#    define    RPERMFILE   ETCPERMS
  609. X#else
  610. X#    define    RPERMFILE   "/usr/spool/lpd/printer_perms."
  611. X#endif
  612. X/*
  613. X *    The remote client must call from a port in the following range.
  614. X *    This is used for authentication purposes.  The ports less than
  615. X *    IPPORT_RESERVED are accessible only to SU processes.
  616. X */
  617. X#define RMINPORTNO    (IPPORT_RESERVED/2)
  618. X#define RMAXPORTNO    (IPPORT_RESERVED)
  619. X
  620. X/*
  621. X *    DEBUG Version, use to avoid screwing up normal operations
  622. X * path name of files created by lpd.
  623. X */
  624. X#define TMASTERLOCK     "/tmp/lpd.lock."
  625. X#define    TDEFLPDLOGF        "/tmp/lpd.log."
  626. X#define TPRINTCAP         "/tmp/printcap."
  627. X/*
  628. X * connection services to be used
  629. X */
  630. X#define TSERVICENAME    "testlpr"
  631. X#define TPORTNUM    1600    /* test port number */
  632. X/* name of the printer permissions file */
  633. X#define    TPERMFILE   "/tmp/printer_perms."
  634. X/*
  635. X *    The remote client must call from a port in the following range.
  636. X *    This is used for authentication purposes.  The ports less than
  637. X *    IPPORT_RESERVED are accessible only to SU processes.
  638. X */
  639. X#define TMINPORTNO    (IPPORT_RESERVED+1)
  640. X#define TMAXPORTNO    (2*IPPORT_RESERVED)
  641. END_OF_FILE
  642. if test 23350 -ne `wc -c <'src/lp.h'`; then
  643.     echo shar: \"'src/lp.h'\" unpacked with wrong size!
  644. fi
  645. # end of 'src/lp.h'
  646. fi
  647. if test -f 'src/utils.c' -a "${1}" != "-c" ; then 
  648.   echo shar: Will not clobber existing file \"'src/utils.c'\"
  649. else
  650. echo shar: Extracting \"'src/utils.c'\" \(25393 characters\)
  651. sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
  652. X/***************************************************************************
  653. X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
  654. X ***************************************************************************
  655. X * MODULE: utils.c
  656. X * Utility routines used by several programs
  657. X ***************************************************************************
  658. X * Revision History: Created Sat Jan  9 15:02:12 CST 1988
  659. X * $Log:    utils.c,v $
  660. X * Revision 3.2  88/06/24  17:55:27  papowell
  661. X * MODS for VAX 4.3BSD UNIX
  662. X * 
  663. X * Revision 3.1  88/06/18  09:35:55  papowell
  664. X * Version 3.0- Distributed Sat Jun 18 1988
  665. X * 
  666. X * Revision 2.4  88/05/19  10:34:26  papowell
  667. X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed
  668. X * 
  669. X * Revision 2.3  88/05/16  12:09:27  papowell
  670. X * Spelling mistake in error messages
  671. X * 
  672. X * Revision 2.2  88/05/14  10:18:31  papowell
  673. X * Use long format for job file names;
  674. X * Added 'fd', no forward flag;
  675. X * Control file has to have hostname and origination agree.
  676. X * 
  677. X * Revision 2.1  88/05/09  10:10:42  papowell
  678. X * PLP: Released Version
  679. X * 
  680. X * Revision 1.7  88/04/27  20:27:34  papowell
  681. X * Modified to remove unused variables
  682. X * 
  683. X * Revision 1.6  88/04/15  13:06:55  papowell
  684. X * Std_environ() call added, to ensure that fd 0 (stdin), 1 (stdout), 2(stderr)
  685. X * have valid file descriptors;  if not open, then /dev/null is used.
  686. X * 
  687. X * Revision 1.5  88/03/25  15:01:57  papowell
  688. X * Debugged Version:
  689. X * 1. Added the PLP control file first transfer
  690. X * 2. Checks for MX during file transfers
  691. X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
  692. X *     apparently they open files and then assume that they will stay
  693. X *     open.
  694. X * 4. Made sure that stdin, stdout, stderr was available at all times.
  695. X * 
  696. X * Revision 1.4  88/03/12  10:03:45  papowell
  697. X * *** empty log message ***
  698. X * 
  699. X * Revision 1.3  88/03/11  19:29:25  papowell
  700. X * Minor Changes, Updates
  701. X * 
  702. X * Revision 1.2  88/03/05  15:01:28  papowell
  703. X * Minor Corrections,  Lint Problems
  704. X * 
  705. X * Revision 1.1  88/03/01  11:09:27  papowell
  706. X * Initial revision
  707. X * 
  708. X ***************************************************************************/
  709. X#ifndef lint
  710. static char id_str1[] =
  711. X    "$Header: utils.c,v 3.2 88/06/24 17:55:27 papowell Exp $ PLP Copyright 1988 Patrick Powell";
  712. X#endif lint
  713. X
  714. X#include "lp.h"
  715. X/*
  716. X * Time_str: return ctime() value, but without terminating '\n'
  717. X */
  718. char *
  719. Time_str()
  720. X{
  721. X    time_t tvec;        /* time */
  722. X    char *ctime();
  723. X    static char s[40];
  724. X
  725. X    (void)time(&tvec);
  726. X    (void)strcpy(s,ctime(&tvec));
  727. X    s[strlen(s)-1] = 0;
  728. X    return( s );
  729. X}
  730. X
  731. X/***************************************************************************
  732. X * Remove_job( FILE *fp; struct queue *q )
  733. X * Remove a job and all associated files; if success == JSUCC, remove
  734. X * U links as well
  735. X * ACTIONS:
  736. X * 1. Read the control file
  737. X * 2. get data file names and unlink them if they match the job
  738. X * 3. Unlink the control file
  739. X ***************************************************************************/
  740. X
  741. Remove_job( fp, q )
  742. X    FILE *fp;
  743. X    struct queue *q;
  744. X{
  745. X    char parm[BUFSIZ];    /* line buffer */
  746. X    char *arg;            /* pointer to the argument */
  747. X    int c;                /* ACME Integers, Inc. */
  748. X    
  749. X    if(Debug>5)log(XLOG_DEBUG,"Remove_job: %s", q->q_name );
  750. X    clearerr( fp );
  751. X    if( fseek( fp, 0L, 0 ) < 0 ){
  752. X        logerr_die( XLOG_INFO,
  753. X            "Remove_job: fseek failed (%s)", q->q_name );
  754. X    } else {
  755. X        /*
  756. X         * read through the file, looking for things to remove
  757. X         */
  758. X        while(fgets( parm, sizeof(parm), fp )){
  759. X            if( (arg = index(parm, '\n')) == 0 ){
  760. X                log( XLOG_INFO, "Remove_job: file bad (%s), no endline",
  761. X                    q->q_name);
  762. X                continue;
  763. X            }
  764. X            *arg = 0;
  765. X            arg = parm+1;
  766. X            c = parm[0];
  767. X            /*
  768. X             * is it a format line?
  769. X             */
  770. X            if( !isascii( c ) || !islower( c ) ){
  771. X                continue;
  772. X            }
  773. X            if( Job_match( q->q_name, arg ) == 0){
  774. X                if(Debug>4)log(XLOG_DEBUG,"Remove_job: bad file name '%s'",
  775. X                    arg );
  776. X                continue;
  777. X            }
  778. X            (void)unlink_daemon( arg );
  779. X        }
  780. X    }
  781. X    if( unlink_daemon( q->q_name ) < 0 ){
  782. X        logerr( XLOG_INFO, "Remove_job: cannot unlink %s", q->q_name );
  783. X    }
  784. X}
  785. X/***************************************************************************
  786. X * int Getq();
  787. X * Scan the spool directory and make a list of server files sorted by
  788. X * priority, creation time, etc.
  789. X * Returns: the number of entries
  790. X * Side Effects: sets struct queue *Queue to point to an array of pointers
  791. X *   to queue entries
  792. X ***************************************************************************/
  793. static int arraysz;                /* number of entries in array */
  794. static struct queue qb;            /* for zeroing purposes */
  795. X
  796. Getq()
  797. X{
  798. X    struct direct *d;        /* directory entry */
  799. X    int nitems;                /* ACME Integers, Inc. */
  800. X    struct stat stbuf;        /* for statting files */
  801. X    int compar();            /* for sorting files */
  802. X    DIR *dirp;                /* used by directory routines */
  803. X    char l[BUFSIZ];            /* for reading the control file */
  804. X    char fullname[BUFSIZ];    /* for the full pathname */
  805. X    char *filepart;            /* end of the pathname */
  806. X    FILE *cfp;                /* control file FP */
  807. X    struct queue *q;        /* pointer to queue entry */
  808. X    char *bp, *ep;            /* ACME Pointers, Inc. */
  809. X
  810. X    if (SD == 0 || *SD == 0 ){
  811. X        fatal( XLOG_INFO, "no directory entry" );
  812. X    }
  813. X    if ((dirp = opendir(SD)) == NULL){
  814. X        logerr_die( XLOG_INFO, "cannot open spool directory %s", SD );
  815. X    }
  816. X
  817. X    /*
  818. X     * get the directory name and copy to buffer
  819. X     */
  820. X    if( strlen(SD) + sizeof(q->q_name) + 2 > sizeof(fullname) ){
  821. X        logerr_die( XLOG_NOTICE,"INTERNAL: Getq, file name too big" );
  822. X    }
  823. X    (void)strcpy(fullname,SD);
  824. X    filepart = &fullname[strlen(fullname)];
  825. X    *filepart++ = '/';
  826. X    /*
  827. X     * assume you have 100 entries to start with
  828. X     */
  829. X    if( arraysz == 0 ){
  830. X        arraysz = 100;
  831. X        Queue = (struct queue *)malloc(
  832. X                (unsigned)(arraysz * sizeof(struct queue)));
  833. X        if (Queue == NULL){
  834. X            logerr_die( XLOG_INFO, "Getq: malloc failed" );
  835. X        }
  836. X    }
  837. X    /*
  838. X     * set the item count to 0 and scan the directory
  839. X     */
  840. X    nitems = 0;
  841. X    while ((d = readdir(dirp)) != NULL) {
  842. X        if(Debug>5)log(XLOG_DEBUG,"Getq: file %s", d->d_name );
  843. X
  844. X        if (d->d_name[0] != 'c' || d->d_name[1] != 'f'){
  845. X            continue;    /* server control files only */
  846. X        }
  847. X        /*
  848. X         * Check to make sure the array has space left and
  849. X         * realloc the maximum size.
  850. X         */
  851. X        if( nitems >= arraysz ){
  852. X            /* try to get another buffer */
  853. X            arraysz = arraysz + 20;
  854. X            Queue = (struct queue *)realloc((char *)Queue,
  855. X                (unsigned)((arraysz)*sizeof(struct queue)));
  856. X            if (Queue == NULL){
  857. X                logerr_die(XLOG_NOTICE,"malloc failed in Getq" );
  858. X            }
  859. X        }
  860. X        /*
  861. X         * get next queue entry and clear it
  862. X         */
  863. X        q = &Queue[nitems];
  864. X        *q = qb;    /* zero it out the easy way */
  865. X
  866. X        if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s", d->d_name );
  867. X
  868. X        /* copy the name of the file */
  869. X        if( strlen( d->d_name ) >= CFNAMELEN){
  870. X            logerr_die(XLOG_NOTICE,"control file name %s too long", d->d_name );
  871. X        }
  872. X        (void)strcpy(q->q_name, d->d_name);
  873. X        (void)strcpy(filepart,d->d_name);
  874. X        if (stat(fullname, &stbuf) < 0){
  875. X            continue;    /* Doesn't exist */
  876. X        }
  877. X        /* get the modification time */
  878. X        q->q_time = stbuf.st_mtime;
  879. X        /* set a priority */
  880. X        q->q_priority = d->d_name[2];
  881. X        /* get the job number */
  882. X        q->q_num = atoi( &d->d_name[3] );
  883. X        
  884. X        /*
  885. X         * now we open the control file and read the information
  886. X         */
  887. X        if( (cfp = fopen_daemon( fullname, "r" )) == NULL ){
  888. X            /* it disappeared */
  889. X            continue;
  890. X        }
  891. X        if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s readable", d->d_name );
  892. X        bp = q->q_data;
  893. X        ep = bp + sizeof(q->q_data);
  894. X        while( fgets( l, sizeof(l), cfp) ){
  895. X            /* clobber the \n */
  896. X            l[strlen(l)-1] = 0;
  897. X            if( islower( l[0] ) ){
  898. X                /* get size of file to be printed */
  899. X                (void)strcpy(filepart, &l[1] );
  900. X                if( stat( fullname,  &stbuf) < 0){
  901. X                    (void)fclose(cfp);
  902. X                    if(Debug>5)log(XLOG_DEBUG,
  903. X                        "Getq: data file %s does not exist", l );
  904. X                } else {
  905. X                    q->q_size += stbuf.st_size;
  906. X                }
  907. X            } else switch( l[0] ){
  908. X                case 'N':    /* name of file */
  909. X                    bp = estrcp( bp, &l[1], ep );
  910. X                    bp = estrcp( bp, " ", ep );
  911. X                    break;
  912. X                case 'P':    /* name of user */
  913. X                    (void)strncpy( q->q_user, &l[1], sizeof(q->q_user)-1);
  914. X                    break;
  915. X                case 'D':    /* when spooled */
  916. X                    q->q_sp = (time_t)atol( &l[1] );
  917. X                    break;
  918. X                case 'T':    /* when to be unspooled */
  919. X                    q->q_unsp = (time_t)atol( &l[1] );
  920. X                    break;
  921. X                default: break;
  922. X            }
  923. X        }
  924. X        if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s is ok", d->d_name );
  925. X
  926. X        (void)fclose(cfp);
  927. X        ++nitems;
  928. X    }
  929. X    closedir(dirp);
  930. X
  931. X    /*
  932. X     * sort the queue
  933. X     */
  934. X    if (nitems){
  935. X        qsort((char *)Queue, nitems, sizeof(struct queue), compar);
  936. X    }
  937. X    return(nitems);
  938. X}
  939. X
  940. X
  941. X/*
  942. X * Compare queue entries by
  943. X * 1. Priority
  944. X * 2. Time
  945. X */
  946. static
  947. compar(c1, c2)
  948. X    char *c1, *c2;
  949. X{
  950. X    struct queue *p1, *p2;
  951. X
  952. X    p1 = (struct queue *)c1;
  953. X    p2 = (struct queue *)c2;
  954. X    if ((p1)->q_priority < (p2)->q_priority)
  955. X        return(-1);
  956. X    if ((p1)->q_priority > (p2)->q_priority)
  957. X        return(1);
  958. X    if ((p1)->q_time < (p2)->q_time)
  959. X        return(-1);
  960. X    if ((p1)->q_time > (p2)->q_time)
  961. X        return(1);
  962. X    return(0);
  963. X}
  964. X
  965. X/***************************************************************************
  966. X * Match_entry( struct queue *q )
  967. X * check the user name and job number against the parmlist starting at start;
  968. X * Return: 1 if match found, 0 otherwise 
  969. X ***************************************************************************/
  970. int
  971. Match_entry( q )
  972. X    struct queue *q;
  973. X{
  974. X    int i;        /* ACME Integer, Inc. */
  975. X
  976. X    if(Debug>4)log(XLOG_DEBUG,"Match_entry on %s, %d", q->q_user, q->q_num );
  977. X    for( i = 0; i < Parmcount; ++i ){
  978. X        if( (Parms[i].num >= 0 && Parms[i].num == q->q_num)
  979. X            || strcmp( Parms[i].str, q->q_user ) == 0 ){
  980. X            return(1);
  981. X        }
  982. X    }
  983. X    return(0);
  984. X}
  985. X
  986. X/***************************************************************************
  987. X * bpread( int fd ; char *buf; int size )
  988. X * Almost bombproof way to read command line from socket
  989. X * Returns: -1 if unable to read a line terminated with \n
  990. X *     0 if 0 length line or first character is null (i.e.- no input)
  991. X *     otherwise: length of line
  992. X ***************************************************************************/
  993. bpread( fd, buf, size )
  994. X    int fd;
  995. X    char *buf;
  996. X    int size;
  997. X{
  998. X    int n;            /* ACME Integer, Inc. */
  999. X    int i;
  1000. X
  1001. X    /*
  1002. X     * Bombproof line reading
  1003. X     */
  1004. X    for( i = 0; i < size; ++i ){
  1005. X        n = read(fd, &buf[i], 1);
  1006. X        if( n < 0 ){
  1007. X            logerr(XLOG_INFO,"bpread: lost connection");
  1008. X            return( -1 );
  1009. X        } else if( n == 0 ){
  1010. X            log(XLOG_INFO,"bpread: bad format %s", buf );
  1011. X            return( 0 );
  1012. X        }
  1013. X        if( buf[i] == '\n' ){
  1014. X            buf[i] = 0;
  1015. X            if(Debug>3)log(XLOG_DEBUG,"bpread: '%d' %s", buf[0], &buf[1]);
  1016. X            return( i );
  1017. X        } else if( buf[i] == 0 && i == 0 ){
  1018. X            if(Debug>3)log(XLOG_DEBUG,"bpread: zero byte first");
  1019. X            return( i );
  1020. X        }
  1021. X    }
  1022. X    log(XLOG_INFO,"bpread: bad line %s", buf );
  1023. X    return( -1 );
  1024. X}
  1025. X/***************************************************************************
  1026. X * estrcp(char *s, *t, *e)
  1027. X * copies t to s, and returns the end position
  1028. X * Returns: end of string if the result is shorter than e, NULL otherwise
  1029. X * Note: this is a very useful routine.  Think about adding it to string
  1030. X * functions.
  1031. X ***************************************************************************/
  1032. char *
  1033. estrcp( s,t,e )
  1034. X    char *s, *t, *e;
  1035. X{
  1036. X    if( s ){
  1037. X        while( (*s++ = *t++) && (s < e) );
  1038. X        if( s < e ){
  1039. X            return( s-1 );
  1040. X        } else {
  1041. X            return( (char *)0 );
  1042. X        }
  1043. X    }
  1044. X    return( s );
  1045. X}
  1046. X/***************************************************************************
  1047. X * splitline( char *line )
  1048. X *    splits a line into tokens, and places them in the Parms[] array.
  1049. X *    if firstarg is present then it is set to the first argument
  1050. X * Side Effects: modifies Parms, Parmcount
  1051. X ***************************************************************************/
  1052. X
  1053. splitline( bp )
  1054. X    char *bp;
  1055. X{
  1056. X    /* find the start */
  1057. X    while (*bp) {
  1058. X        while( *bp && isspace(*bp))
  1059. X            bp++;
  1060. X        if( *bp ){
  1061. X            if( Parmcount >= MAXPARMS ){
  1062. X                fatal(XLOG_INFO,"splitline: too many requests");
  1063. X            }
  1064. X            Parms[Parmcount].str = bp;
  1065. X            if (isdigit(*bp)) {
  1066. X                Parms[Parmcount].num = atoi(bp);
  1067. X            } else {
  1068. X                Parms[Parmcount].num = -1;
  1069. X            }
  1070. X            Parmcount++;
  1071. X        }
  1072. X        while( *bp && !isspace(*bp))
  1073. X            bp++;
  1074. X        if( *bp )
  1075. X            *bp++ = 0;
  1076. X    }
  1077. X}
  1078. X/**********************************************************************
  1079. X * Shift_parms( int n )
  1080. X * left shift the entries in the Parms[] array by n
  1081. X * Side Effects: modifies Parms and Parmcount
  1082. X **********************************************************************/
  1083. Shift_parms( n )
  1084. X    int n;
  1085. X{
  1086. X    int i;        /* ACME Chain and Integer, Inc. */
  1087. X    while( Parmcount > 0 && n > 0 ){
  1088. X        for( i = 1; i < Parmcount; ++i ){
  1089. X            Parms[i-1] = Parms[i];
  1090. X        }
  1091. X        --Parmcount;
  1092. X        --n;
  1093. X    }
  1094. X}
  1095. X
  1096. printstatus()
  1097. X{
  1098. X    if( ST && *ST ){
  1099. X        if(Debug>4)log(XLOG_DEBUG,"printstatus: ST %s", ST );
  1100. X        pr_stat_file( ST );
  1101. X    }
  1102. X    if( PS && *PS ){
  1103. X        if(Debug>4)log(XLOG_DEBUG,"printstatus: PS %s", PS );
  1104. X        pr_stat_file( PS );
  1105. X    }
  1106. X}
  1107. X
  1108. pr_stat_file( file )
  1109. X    char *file;
  1110. X{
  1111. X    FILE *fp;
  1112. X    char buf[BUFSIZ];
  1113. X
  1114. X    if( (fp = fopen_daemon( file, "r" )) != NULL ){
  1115. X        while( fgets( buf, sizeof(buf), fp) != NULL ){
  1116. X            (void)fprintf(stdout, "  %s", buf );
  1117. X        }
  1118. X        (void)fflush(stdout);
  1119. X        (void)fclose( fp );
  1120. X    }
  1121. X}
  1122. X/***************************************************************************
  1123. X * char *Sigstr(n)
  1124. X * Return a printable form the the signal
  1125. X ***************************************************************************/
  1126. X
  1127. struct signame{
  1128. X    char *str;
  1129. X    int value;
  1130. X} signals[] = {
  1131. X{ "SIGHUP", SIGHUP }, { "SIGINT", SIGINT }, { "SIGQUIT", SIGQUIT },
  1132. X{ "SIGILL", SIGILL }, { "SIGTRAP", SIGTRAP }, { "SIGIOT", SIGIOT },
  1133. X{ "SIGEMT", SIGEMT }, { "SIGFPE", SIGFPE }, { "SIGKILL", SIGKILL },
  1134. X{ "SIGBUS", SIGBUS }, { "SIGSEGV", SIGSEGV }, { "SIGSYS", SIGSYS },
  1135. X{ "SIGPIPE", SIGPIPE }, { "SIGALRM", SIGALRM }, { "SIGTERM", SIGTERM },
  1136. X{ "SIGURG", SIGURG }, { "SIGSTOP", SIGSTOP }, { "SIGTSTP", SIGTSTP },
  1137. X{ "SIGCONT", SIGCONT }, { "SIGCHLD", SIGCHLD }, { "SIGTTIN", SIGTTIN },
  1138. X{ "SIGTTOU", SIGTTOU }, { "SIGIO", SIGIO }, { "SIGXCPU", SIGXCPU },
  1139. X{ "SIGXFSZ", SIGXFSZ }, { "SIGVTALRM", SIGVTALRM }, { "SIGPROF", SIGPROF } };
  1140. int nsignals = sizeof( signals )/ sizeof( struct signame );
  1141. char *
  1142. Sigstr( n )
  1143. X    int n;
  1144. X{
  1145. X    int i;
  1146. X    static char buf[40];
  1147. X
  1148. X    for( i = 0; i < nsignals; ++i ){
  1149. X        if( signals[i].value == n ){
  1150. X            return( signals[i].str );
  1151. X        }
  1152. X    }
  1153. X    (void)sprintf(buf,"unknown signal (%d)", n );
  1154. X    return( buf );
  1155. X}
  1156. X/***************************************************************************
  1157. X * Decode_status( union wait *status )
  1158. X * returns a printable string encoding return status
  1159. X ***************************************************************************/
  1160. X
  1161. char *
  1162. Decode_status( status )
  1163. X    union wait *status;
  1164. X{
  1165. X    static char msg[BUFSIZ];
  1166. X
  1167. X    (void)sprintf( msg, "user: %d, system: %d%s",
  1168. X        status->w_retcode, status->w_termsig,
  1169. X        status->w_coredump ? ", core dump, " : ", " );
  1170. X    if( status->w_termsig ){
  1171. X        (void)sprintf(msg+strlen(msg),"error- %s",
  1172. X            Sigstr((int)status->w_termsig));
  1173. X    }
  1174. X    return( msg );
  1175. X}
  1176. X
  1177. X/*
  1178. X * Checkactive()
  1179. X * find the currently active files in the spool queue.
  1180. X * 1.  check for the single server possibility first.
  1181. X * 2.  find the Names of the servers
  1182. X * 3.  find the active files for each of the servers
  1183. X */
  1184. X
  1185. int 
  1186. Checkactive()
  1187. X{
  1188. X    int i;                /* ACME Integers, Inc. */
  1189. X    char buf[BUFSIZ];    /* Name of active file */
  1190. X    static char server[BUFSIZ];    /* Name of server file */
  1191. X    char *sp, *ep;            /* ACME Pointer */
  1192. X    int pid;
  1193. X
  1194. X    pid = 0;
  1195. X    buf[0] = 0;
  1196. X    if(Checklockfile(LO,&pid,buf,sizeof(buf),&LO_statb) && buf[0] ){
  1197. X        for( i = 0; i < Jobcount; ++i ){
  1198. X            if( strcmp( buf, Queue[i].q_name ) == 0 ){
  1199. X                Queue[i].q_daemon = pid;
  1200. X                Queue[i].q_server = Printer;
  1201. X            } else {
  1202. X                Queue[i].q_daemon = 0;
  1203. X                Queue[i].q_server = 0;
  1204. X            }
  1205. X        }
  1206. X    }
  1207. X    /*
  1208. X     * check for each of the servers
  1209. X     */
  1210. X    if( SV && *SV ){
  1211. X        (void)strcpy( server, SV );
  1212. X        for( sp = server; sp; sp = ep ){
  1213. X            if( ep = index( sp, ',' ) ){
  1214. X                *ep = 0;
  1215. X                ++ep;
  1216. X            }
  1217. X            /*
  1218. X             * get the lock file and the status from the server
  1219. X             */
  1220. X            buf[0] = 0;
  1221. X            if(Checklockfile(sp,&pid,buf,sizeof(buf),(struct stat *)0)
  1222. X                && buf[0] ){
  1223. X                for( i = 0; i < Jobcount; ++i ){
  1224. X                    if( strcmp( buf, Queue[i].q_name ) == 0 ){
  1225. X                        Queue[i].q_daemon = pid;
  1226. X                        Queue[i].q_server = sp;
  1227. X                    } else {
  1228. X                        Queue[i].q_daemon = 0;
  1229. X                        Queue[i].q_server = 0;
  1230. X                    }
  1231. X                }
  1232. X            }
  1233. X        }
  1234. X    }
  1235. X    return(pid);
  1236. X}
  1237. X
  1238. X
  1239. X/***************************************************************************
  1240. X * Get_Daemon()
  1241. X * Get the DAEMON uid and gid
  1242. X * Assume password entry has both values set for the user daemon
  1243. X ***************************************************************************/
  1244. Get_Daemon()
  1245. X{
  1246. X    struct passwd *passwd, *getpwnam();
  1247. X    if( Daemon_uid == 0 ){
  1248. X        if( (passwd = getpwnam(DAEMON)) == 0 ){
  1249. X            logerr_die( XLOG_INFO,"Get_Daemon: getpwnam(%s) failed", DAEMON );
  1250. X        }
  1251. X        Daemon_uid = passwd->pw_uid;
  1252. X        Daemon_gid = passwd->pw_gid;
  1253. X        if(Debug>4)log(XLOG_INFO,"Get_Daemon: uid=%d, gid=%d",
  1254. X            Daemon_uid, Daemon_gid);
  1255. X    }
  1256. X}
  1257. X
  1258. X/***************************************************************************
  1259. X * Job_match( char *control, *data)
  1260. X * Check to see if the control and data file names are matching
  1261. X * 1. data file must start with "df"
  1262. X * 2. next must be letter
  1263. X * 3. next must be 3 digit sequence number
  1264. X * 4. control and data file sequence number must match
  1265. X * return 1 if OK, 0 if not
  1266. X ***************************************************************************/
  1267. X
  1268. Job_match( control, data )
  1269. X    char *control;
  1270. X    char *data;
  1271. X{
  1272. X    int c, i, j;    /* ACME Chain and Integers, Inc. */
  1273. X
  1274. X    i = strlen( data );
  1275. X    for( j = 0; j < i ; ++j ){
  1276. X        c = data[j];
  1277. X        if( !isascii( c ) || !isprint( c ) ){
  1278. X            log(XLOG_INFO, "Job_match: bad char in '%s'", data );
  1279. X            return( 0 );
  1280. X        }
  1281. X    }
  1282. X    if( index( data, '/' ) ){
  1283. X        /*
  1284. X         * tried to embed a / in the file name
  1285. X         */
  1286. X        log(XLOG_INFO, "Job_match: / present '%s'",    data );
  1287. X        return( 0 );
  1288. X    }
  1289. X    if( i > CFNAMELEN
  1290. X        || i <= STARTFR
  1291. X        || i != strlen( control )
  1292. X        || index( "cd", data[0] ) == 0
  1293. X        || (data[1] != 'f')
  1294. X        || !isalpha( data[STARTPR] )
  1295. X        || strcmp( control+STARTID, data+STARTID ) ){
  1296. X        log(XLOG_INFO, "Job_match: bad match control '%s', data '%s'",    
  1297. X            control, data );
  1298. X        return( 0 );
  1299. X    }
  1300. X    for( j = 0; j < IDLEN; ++ j ){
  1301. X        if( !isdigit( data[j+STARTID] ) ){
  1302. X            log(XLOG_INFO, "Job_match: bad sequence control '%s', data '%s'",    
  1303. X                control, data );
  1304. X            return( 0 );
  1305. X        }
  1306. X    }
  1307. X    if(Debug>5)log(XLOG_DEBUG,"Job_match: OK control '%s', data '%s'",    
  1308. X        control, data );
  1309. X    return( 1 );
  1310. X}
  1311. X
  1312. X/***************************************************************************
  1313. X * Std_environ()
  1314. X * Make sure that fd 0, 1, 2 exist by opening /dev/null for them if they
  1315. X * have not been provided.
  1316. X * Set up the Host information as well
  1317. X ***************************************************************************/
  1318. X
  1319. Std_environ()
  1320. X{
  1321. X    int fd;
  1322. X    struct hostent *host_ent;    /* host entry from data base */
  1323. X
  1324. X    /*
  1325. X     * close all file descriptors up to NOFILE
  1326. X     */
  1327. X    for (fd = 3; fd < NOFILE; fd++){
  1328. X        (void) close(fd);
  1329. X    }
  1330. X    while( (fd = open( "/dev/null", O_RDWR, 0 )) >= 0 && fd < 3 );
  1331. X    if( fd < 0 ){
  1332. X        logerr_die( XLOG_CRIT, "Std_environ: cannot open /dev/null" );
  1333. X    } else {
  1334. X        (void)close(fd);
  1335. X    }
  1336. X    /*
  1337. X     * get the Host computer Name
  1338. X     */
  1339. X    if( gethostname(Host, sizeof(Host)) < 0 ){
  1340. X        logerr_die( XLOG_INFO, "Std_environ: gethostname failed" );
  1341. X    }
  1342. X    host_ent = gethostbyname( Host );
  1343. X    if( host_ent == 0 ){
  1344. X        fatal( XLOG_INFO, "Std_environ: host entry for '%' not found", Host );
  1345. X    }
  1346. X    if( strlen( host_ent->h_name ) > sizeof( Host ) ){
  1347. X        fatal( XLOG_INFO, "Std_enviorn: host name is too long: '%s'",
  1348. X            host_ent->h_name);
  1349. X    }
  1350. X    (void)strcpy(Host, host_ent->h_name );
  1351. X    /*
  1352. X     * Get Daemon UID
  1353. X     */
  1354. X    Get_Daemon();
  1355. X}
  1356. X
  1357. X/***************************************************************************
  1358. X * int open_daemon()
  1359. X * FILE *fopen_daemon()
  1360. X * int unlink_daemon()
  1361. X * Do the above actions as DAEMON.
  1362. X * Note that this is very difficult to do,  and ensure that all the error
  1363. X * conditions are met.  What you want to do is perform the following as
  1364. X * an uninterrupted critical section.
  1365. X * 1. setreuid( root, daemon)
  1366. X * 2. perform the action
  1367. X * 3. setreuid( whatever, root )
  1368. X * This will only work if
  1369. X * 1. you are really root
  1370. X * 2. you do not ever get interrupts
  1371. X ***************************************************************************/
  1372. static    uid_t ruid, euid;    /* real and effective UIDs */
  1373. static    int uid_parm;        /* must be able to hold -1 */
  1374. static    int omask;            /* block these signals */
  1375. X
  1376. X
  1377. void
  1378. Set_uid( new_uid )
  1379. X    int new_uid;
  1380. X{
  1381. X    /*
  1382. X     * get the DAEMON UID, GID
  1383. X     */
  1384. X    omask = sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP)
  1385. X        |sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
  1386. X    ruid = getuid();
  1387. X    euid = geteuid();
  1388. X
  1389. X#    ifdef SETREUID4BSD
  1390. X    uid_parm = euid;
  1391. X#    else
  1392. X    uid_parm = -1;
  1393. X#    endif SETREUID4BSD
  1394. X    /*
  1395. X     * check to see if we are running without SUID
  1396. X     */
  1397. X    if( euid && euid != getuid() && euid != new_uid ){
  1398. X        log( XLOG_INFO, "Set_uid: euid %d, ruid %d, bad SUID?",
  1399. X            euid, getuid() );
  1400. X        /*
  1401. X         * NOTE: do not try and take normal exit!!!
  1402. X         */
  1403. X        exit(1);
  1404. X    } else if( euid == 0 && setreuid( uid_parm, new_uid ) < 0 ){
  1405. X        logerr( XLOG_INFO, "Set_uid: setreuid( %d, %d) failed",
  1406. X            uid_parm, new_uid );
  1407. X        exit(1);
  1408. X    }
  1409. X    if(Debug>4)log(XLOG_DEBUG,"Set_uid: uid_parm %d, uid %d, euid %d",
  1410. X        uid_parm, getuid(), geteuid());
  1411. X}
  1412. X/*
  1413. X * set the UID to DAEMON
  1414. X */
  1415. void
  1416. Set_daemon()
  1417. X{
  1418. X    /*
  1419. X     * get the DAEMON UID, GID
  1420. X     */
  1421. X    Get_Daemon();
  1422. X    Set_uid( Daemon_uid );
  1423. X}
  1424. X/*
  1425. X * set UID back to normal.  Note that there are two versions of setreuid
  1426. X * available.  The VAX 4.2/4.3 version allows you to swap RUID/EUID
  1427. X * and will allow you only to set your UID if you are EUID root.
  1428. X * The SUN 3.X and others will allow you ONE call to the SUID function,
  1429. X * and will allow you to set the UID back to the original.  The
  1430. X * uid_parm flag determines which strategy to use.
  1431. X * If uid_parm is -1,  then you have to use setreuid( -1, euid )
  1432. X * If it is not,  then we have to swap the EUID/UID, then set
  1433. X * the UID and EUID explicitly
  1434. X */
  1435. void
  1436. Clear_uid()
  1437. X{
  1438. X    /*
  1439. X     * handle the easy one first: set euid back to original
  1440. X     */
  1441. X    if( uid_parm == -1 ){
  1442. X        if( setreuid( -1, euid ) < 0 ){
  1443. X            logerr( XLOG_INFO,
  1444. X            "Clear_uid: setreuid( %d, %d) from %d, %d failed",
  1445. X                -1, euid, getuid(), geteuid() );
  1446. X            /*
  1447. X             * avoid problems, exit early
  1448. X             */
  1449. X            exit(1);
  1450. X        }
  1451. X        (void)sigsetmask(omask);
  1452. X        return;
  1453. X    }
  1454. X    /*
  1455. X     * otherwise we swap the UID and EUID, but first make sure that it is
  1456. X     * consistent;  uid should be the old (original) euid on entry to set_uid
  1457. X     */
  1458. X    if( getuid() != euid ){
  1459. X        logerr( XLOG_INFO,
  1460. X            "Clear_uid: uid is %d, euid is %d, and uid should be %d",
  1461. X                getuid(), geteuid(), euid );
  1462. X        exit(1);
  1463. X    }
  1464. X    /*
  1465. X     * swap the RUID and EUID
  1466. X     */
  1467. X    if( setreuid( geteuid(), getuid() ) < 0 ){
  1468. X        logerr( XLOG_INFO,
  1469. X            "Clear_uid: setreuid( %d, %d) from %d, %d failed",
  1470. X                geteuid(), getuid(), getuid(), geteuid() );
  1471. X        /*
  1472. X         * avoid problems, exit early
  1473. X         */
  1474. X        exit(1);
  1475. X    }
  1476. X    /*
  1477. X     * Set the RUID and EUID explicitly
  1478. X     */
  1479. X    if( setreuid( ruid, euid ) < 0 ){
  1480. X        logerr( XLOG_INFO,
  1481. X            "Clear_uid: setreuid( %d, %d) from %d, %d failed",
  1482. X                ruid, euid, getuid(), geteuid() );
  1483. X        /*
  1484. X         * avoid problems, exit early
  1485. X         */
  1486. X        exit(1);
  1487. X    }
  1488. X    (void)sigsetmask(omask);
  1489. X}
  1490. X
  1491. X/*
  1492. X * Open a file as daemon.
  1493. X */
  1494. int
  1495. open_daemon( name, flag, perms )
  1496. X    char *name;
  1497. X    int flag;
  1498. X    int perms;
  1499. X{
  1500. X    int fd, err;
  1501. X    /*
  1502. X     * establish UID
  1503. X     */
  1504. X    Set_daemon();
  1505. X    /*
  1506. X     * now for the plunge into the unknown
  1507. X     */
  1508. X    fd = open( name, flag, perms );
  1509. X    err = errno;
  1510. X    Clear_uid();
  1511. X    errno = err;
  1512. X    return( fd );
  1513. X}
  1514. X
  1515. X/*
  1516. X * fopen a file; the file has been created, and we want to do this as
  1517. X * daemon for permissions reasons.
  1518. X */
  1519. XFILE *
  1520. fopen_daemon( name, how )
  1521. X    char *name;
  1522. X    char *how;
  1523. X{
  1524. X    int err;
  1525. X    FILE *fp;
  1526. X    /*
  1527. X     * establish UID
  1528. X     */
  1529. X    Set_daemon();
  1530. X    /*
  1531. X     * now for the plunge into the unknown
  1532. X     * NOTE: we are assuming that we only use this to READ a file already
  1533. X     * created.
  1534. X     */
  1535. X    fp = fopen( name, how );
  1536. X    err = errno;
  1537. X    /*
  1538. X     * done with the daemon stuff
  1539. X     */
  1540. X    Clear_uid();
  1541. X    errno = err;
  1542. X    return( fp );
  1543. X}
  1544. X
  1545. X/*
  1546. X * UNLINK a file as DAEMON
  1547. X */
  1548. unlink_daemon( name )
  1549. X    char *name;
  1550. X{
  1551. X    int f, err;
  1552. X    /*
  1553. X     * establish UID
  1554. X     */
  1555. X    Set_daemon();
  1556. X    /*
  1557. X     * now for the plunge into the unknown
  1558. X     */
  1559. X    f = unlink( name );
  1560. X    err = errno;
  1561. X    /*
  1562. X     * done with the daemon stuff
  1563. X     */
  1564. X    Clear_uid();
  1565. X    errno = err;
  1566. X    return( f );
  1567. X}
  1568. X
  1569. X
  1570. X/*
  1571. X * CHMOD a file as DAEMON
  1572. X */
  1573. chmod_daemon( name, perms )
  1574. X    char *name;
  1575. X    int perms;
  1576. X{
  1577. X    int f, err;
  1578. X    /*
  1579. X     * establish UID
  1580. X     */
  1581. X    Set_daemon();
  1582. X    /*
  1583. X     * now for the plunge into the unknown
  1584. X     */
  1585. X    f = chmod( name, perms );
  1586. X    err = errno;
  1587. X    /*
  1588. X     * done with the daemon stuff
  1589. X     */
  1590. X    Clear_uid();
  1591. X    errno = err;
  1592. X    return( f );
  1593. X}
  1594. X
  1595. X/***************************************************************************
  1596. X * Rename_cf( char *tf )
  1597. X * rename the temporary file to a control file
  1598. X ***************************************************************************/
  1599. X
  1600. Rename_cf( tf )
  1601. X    char *tf;
  1602. X{
  1603. X    char from[MAXPATHLEN+1];
  1604. X    char to[MAXPATHLEN+1];
  1605. X    int i, err;
  1606. X
  1607. X    (void)sprintf( from, "%s/%s", SD, tf );
  1608. X    (void)sprintf( to, "%s/c%s", SD, tf+1 );
  1609. X    if(Debug>4)log(XLOG_DEBUG,"Rename_cf: from '%s' to '%s'",from, to);
  1610. X    Set_daemon();
  1611. X    i = rename( from, to );
  1612. X    err = errno;
  1613. X    Clear_uid();
  1614. X    errno = err;
  1615. X    if( i < 0 ){
  1616. X        logerr_die(XLOG_INFO,"Rename_cf: rename '%s' to '%s' failed",from, to);
  1617. X    }
  1618. X}
  1619. X
  1620. X/***************************************************************************
  1621. X * Tailor_names()
  1622. X * Appends the Host information to several file names.
  1623. X ***************************************************************************/
  1624. static
  1625. append_name( s, t )
  1626. X    char *s, *t;
  1627. X{
  1628. X    if( (strlen(s) + strlen(t) + 2) > MAXPATHLEN ){
  1629. X        fatal( XLOG_INFO,"append_name: names too long 's' + 't'", s, t);
  1630. X    }
  1631. X    (void)strcat( s, t);
  1632. X}
  1633. Tailor_names()
  1634. X{
  1635. X    append_name( Lpdlogf, Host );
  1636. X    append_name( Masterlock, Host );
  1637. X    append_name( Permfile, Host );
  1638. X    append_name( Printcap, Host );
  1639. X}
  1640. END_OF_FILE
  1641. if test 25393 -ne `wc -c <'src/utils.c'`; then
  1642.     echo shar: \"'src/utils.c'\" unpacked with wrong size!
  1643. fi
  1644. # end of 'src/utils.c'
  1645. fi
  1646. echo shar: End of archive 15 \(of 16\).
  1647. cp /dev/null ark15isdone
  1648. MISSING=""
  1649. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
  1650.     if test ! -f ark${I}isdone ; then
  1651.     MISSING="${MISSING} ${I}"
  1652.     fi
  1653. done
  1654. if test "${MISSING}" = "" ; then
  1655.     echo You have unpacked all 16 archives.
  1656.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1657. else
  1658.     echo You still need to unpack the following archives:
  1659.     echo "        " ${MISSING}
  1660. fi
  1661. ##  End of shell archive.
  1662. exit 0
  1663.  
  1664.