rsalz@uunet.uu.net (Rich Salz) (09/17/88)
Submitted-by: papowell@julius.cs.umn.edu Posting-number: Volume 16, Issue 28 Archive-name: plp/part15 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 15 (of 16)." # Contents: src/lp.h src/utils.c # Wrapped by papowell@attila on Wed Aug 10 10:45:12 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'src/lp.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/lp.h'\" else echo shar: Extracting \"'src/lp.h'\" \(23350 characters\) sed "s/^X//" >'src/lp.h' <<'END_OF_FILE' X/************************************************************************* X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X ************************************************************************* X * MODULE: lp.h X * Includes and definitions for all programs X ************************************************************************* X * Revision History: Created Sun Jan 3 15:37:08 CST 1988 X * $Header: lp.h,v 3.2 88/06/24 17:15:52 papowell Exp $ X * $Log: lp.h,v $ X * Revision 3.2 88/06/24 17:15:52 papowell X * MODS for VAX 4.3BSD UNIX X * X * X * Revision 3.1 88/06/18 09:34:30 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.3 88/05/29 13:09:55 papowell X * Added Header string for RCS purposes X * X * Revision 2.2 88/05/14 10:18:16 papowell X * Use long format for job file names; X * Added 'fd', no forward flag; X * Control file has to have hostname and origination agree. X * X * Revision 2.1 88/05/09 10:10:48 papowell X * PLP: Released Version X * X * Revision 1.12 88/05/09 10:03:39 papowell X * Revised effects of -h option X * X * Revision 1.11 88/05/05 20:08:53 papowell X * Added a NOHEADER option that allows user to suppress banner X * X * Revision 1.10 88/04/29 07:48:55 papowell X * Added USE_LOCKF flags X * X * Revision 1.9 88/04/28 17:32:47 papowell X * fixed Data General Options X * X * Revision 1.8 88/04/21 21:49:40 papowell X * BADSETREUID: this flag is provided for situations where setreuid() X * does not allow changing back to root after changing to a user. X * This is a problem in security, and should be avoided. X * X * Revision 1.7 88/04/07 12:29:13 papowell X * Removed AF_UNIX socket definitions X * X * Revision 1.6 88/04/07 09:09:23 papowell X * Apollo Workstation Modifications X * X * Revision 1.5 88/04/06 12:13:40 papowell X * Minor updates, changes in error message formats. X * Elimination of the AF_UNIX connections, use AF_INET only. X * Better error messages. X * X * Revision 1.4 88/03/25 14:59:54 papowell X * Debugged Version: X * 1. Added the PLP control file first transfer X * 2. Checks for MX during file transfers X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities; X * apparently they open files and then assume that they will stay X * open. X * 4. Made sure that stdin, stdout, stderr was available at all times. X * X * Revision 1.3 88/03/11 19:29:10 papowell X * Minor Changes, Updates X * X * Revision 1.2 88/03/05 15:02:09 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 12:42:54 papowell X * Initial revision X * X *************************************************************************/ X X/************************************************************************* X * Make sure that you set the DEBUG flag if XPERIMENT is set X * X *************************************************************************/ X#ifdef XPERIMENT X#define DEBUG 1 X#endif XPERIMENT X/************************************************************************* X * Portability Definitions X * Several systems do not have the same definitions for these items. X * You will have to add your own local definitions. X * Ahh... Dream of the day of a standard set of definitions X *************************************************************************/ X#ifdef IS_SUN X#define uid_t int /* keep lint on the sun happy */ X#endif IS_SUN X X#ifdef IS_VAX4BSD X#define SETREUID4BSD 1 X#endif IS_VAX4BSD X X#ifdef IS_DATAGEN X#define fd_set int /* keep lint happy */ X#define uid_t int /* keep lint happy */ X#define NOSYMLINK /* no symbolic links */ X#define USE_LOCKF /* use the lockf() function for locking */ X#define F_TLOCK 2 /* test and lock a section (non-blocking) */ X#endif IS_DATAGEN X X#ifdef IS_UMAX X#undef B19200 X#undef B38400 X#define B19200 EXTA X#define B38400 EXTB X#define time_t long X#define uid_t int X#endif IS_UMAX X X#ifdef IS_APOLLO X#undef B19200 X#undef B38400 X#define B19200 EXTA X#define B38400 EXTB X#define uid_t int X#define USE_STRINGS /* use <strings.h> instead of <string.h> */ X#define NO_A_OUT_H /* no a.out.h include file */ X#endif IS_APOLLO X X/****************************************************************** X * System Include Files X ******************************************************************/ X#include <stdio.h> X#include <sys/param.h> X#include <sys/types.h> X#include <sys/file.h> X#include <sys/dir.h> X#include <sys/time.h> X#include <sys/stat.h> X#include <sys/socket.h> X#include <sys/resource.h> X#include <netinet/in.h> X#include <netdb.h> X#include <pwd.h> X#include <signal.h> X#include <sys/wait.h> X#include <sgtty.h> X#include <ctype.h> X#ifdef USE_STRINGS X#include <strings.h> X#else USE_STRINGS X#include <string.h> X#endif USE_STRINGS X#include <errno.h> X#include <grp.h> X X X/****************************************************************** X * Declare Standard Routines. X * Note: most of these are not declared in include files. X * This leads to some interesting problems with LINT. Declare these X * here. Some specialized routines are declared in the individual X * routines that use them. X ******************************************************************/ extern char *malloc(), *realloc(); extern char *getenv(); extern char *gets(); extern int errno, sys_nerr; extern char *sys_errlist[]; extern char *index(), *rindex(); extern char *sprintf(); /* sigh... sprintf strikes again */ extern long lseek(), atol(); X extern uid_t getuid(), geteuid(); extern time_t time(); /* watch this one */ X X/* X * This should be declared in <signal.h> X */ X#ifndef sigmask X#define sigmask(m) (1 << ((m)-1)) X#endif X X/************************************************************************* X * PRINTCAP entries and associated variables. X * Each printcap entry has a corresponding variable; for example X * ":af=accnt:" X * -> AF = "accnt"; X *************************************************************************/ extern int AB; /* Always have a banner flag, ignore lpr -h option */ extern char *AF; /* accounting file */ extern char *BP; /* banner printer filter */ extern int BK; /* Berkeley compatible remote and local */ extern int BR; /* baud rate if lp is a tty */ extern int CO; /* cost of printing in dollars */ extern char *EP; /* end printer filter */ extern int FD; /* No forwarding, accept only from original site */ extern int FO; /* print a form feed when device is opened */ extern int FC; /* flags to clear if lp is a tty */ extern char *FF; /* form feed string */ extern int FJ; /* send control file first to remote site */ extern int FQ; /* form feed on quitting */ extern int FS; /* flags to set if lp is a tty */ extern char *FX; /* allowable formats */ extern char *LD; /* leader string on opening */ extern char *LF; /* log file for error messages */ extern int LH; /* use long host name */ extern char *LO; /* lock file name */ extern char *LN; /* group allowed to use links */ extern char *LP; /* line printer device name */ extern int MC; /* maximum number of copies allowed */ extern int MX; /* maximum number of blocks to copy */ extern int NW; /* Networked file system, do not make copies */ extern int PL; /* page length */ extern char *PR; /* pr program name name */ extern char *PS; /* printer status file name */ extern int PW; /* page width */ extern int PX; /* page width in pixels */ extern int PY; /* page length in pixels */ extern char *QH; /* queue handler */ extern char *RG; /* restrict use to group */ extern char *RM; /* remote machine name */ extern char *RP; /* remote printer name */ extern int RT; /* max retries */ extern int RW; /* open LP for reading and writing */ extern int SB; /* short banner instead of normal header */ extern int SC; /* suppress multiple copies */ extern char *SD; /* spool directory */ extern int SF; /* suppress FF on each print job */ extern int SH; /* suppress header page */ extern char *SS; /* name of queue that the server serves */ extern char *ST; /* status file name */ extern char *SV; /* names of servers */ extern char *TR; /* trailer string to be output when Q empties */ extern char *TY; /* terminal characteristics, stty options */ extern int XC; /* flags to clear for local mode */ extern int XS; /* flags to set for local mode */ extern char *XT; /* format checked for text only */ extern char *XU; /* restrict use to users whose names are in file */ X/* X * Filter_name[] is an array of filter names, indexed by the first letter X * of the printcap tag. For example: X * ":if=/usr/lib/iffilter -n -a:" X * -> Filter_name['i'-'a'] = "/usr/lib/iffilter -n -a"; X */ extern char *Filter_name[26]; X#define IF (Filter_name['i'-'a']) X#define OF (Filter_name['o'-'a']) X/* X * Prefilter_name[] is similar to Filter_name[], but for prefilter entries. X */ extern char *Prefilter_name[26]; X X/********************************************************************** X * Globally accessed variables and routines X **********************************************************************/ extern char *Name; /* program name */ extern char *Printer; /* printer name */ extern char *Person; /* user name */ extern char Host[64]; /* Host machine name */ extern char *From; /* client's machine name */ extern int Debug; /* Debugging level */ extern int Echo_on_stdout; /* stderr output on stdout as well */ extern char *First_name; /* first name in printcap entry */ extern FILE *Lfd; /* lock file */ extern int Optind, Opterr; /* option index, error message suppression */ extern char *Optarg; /* option value */ extern char *Opt_flag; /* option staring flags */ extern char Lpdlogf[]; /* = DEFLPDLOGF; */ extern char Masterlock[]; /* = MASTERLOCK; */ extern int Lpr_port_num; /* port number to connect to */ extern int Maxportno; /* = MAXPORTNO; */ extern int Minportno; /* = MINPORTNO; */ extern char Permfile[]; /* = PERMFILE; */ extern char Printcap[]; /* = PRINTCAP; */ extern char Last_errormsg[]; /* last errormessage */ extern int Request; /* current lpd request code */ extern int Print_fd; /* output printer FILE */ extern int Short_format; /* short status format */ extern int Is_root; /* is this the root user? */ extern int Is_local; /* doing this locally or remotely? */ extern struct stat LO_statb; /* used to stat lockfile */ extern void Print_close(), Link_close(); /* close these things */ extern int Daemon_uid; /* daemon UID */ extern int Daemon_gid; /* daemon GID */ extern char *estrcp(); /* handy form of strcp() */ extern char *Time_str(); /* ctime with \n removed */ extern char *Setup_filter(); /* set up argv for a filter */ extern int Reapchild(); /* wait3() for a child */ extern int Getopt(); /* get command line option */ extern char *Errormsg(); /* printable error message */ extern int Errorcode; /* exit() value on fatal termination */ extern char *Decode_status(); /* decode a status returned by wait() */ extern FILE *fopen_daemon(); /* open a file as daemon */ extern int open_daemon(); /* open a file as daemon */ X X/******************************************************************* X * struct queue X * used to record entries in the spool directory for printing X * and status reporting. X * NOTE: control and data file names in spool directory have the form X * c f <priority> <job number> <Hostname> <terminating 0> X * d f <seq> <job number> <Hostname> <terminating 0> X * 1 1 1 3 max 64 1 X * eg: dfA001attila.cs.umn.edu (attila the SUN, of course) X * eg: cfZ001attila.cs.umn.edu (attila the SUN, of course) X *******************************************************************/ X#define CFNAMELEN (sizeof(Host)+8) /* control or data file name length */ X/* X * fields in the name X */ X#define STARTPR 2 /* df[] */ X#define STARTID 3 /* dfX[] */ X#define IDLEN 3 /* dfX[NNN] */ X#define STARTFR 6 /* dfXNNN[] */ X#define MAXPARMLEN 80 struct queue { X char q_name[CFNAMELEN+1]; /* name of the control file */ X time_t q_time; /* modification time */ X time_t q_sp; /* spooled at time */ X time_t q_unsp; /* unspool at time */ X int q_priority; /* priority */ X long q_size; /* size of the data files */ X char q_user[32]; /* user name */ X int q_num; /* job number */ X char q_data[MAXPARMLEN+1]; /* data files name */ X int q_daemon; /* daemon for this entry */ X char *q_server; /* server for this entry */ X}; X X#define q_from q_name[STARTFR] extern int Getq(); /* find queue entries */ extern struct queue *Jobentry; /* current job entry in queue */ extern struct queue *Queue; /* Getq generates an array of jobs */ extern int Jobcount; /* and returns the number of jobs */ X extern int Rec_cnt; /* number of files in a job */ X X/******************************************************************** X * File Permissions X ********************************************************************/ X X#define LFMODE 0644 /* log file permissions */ X#define FILMOD 0600 /* spooling directory file permission */ X X/* X * Queue Control is done by using the permissions of the lock file X * for the queue. The following permissions are used: X * Disable Printing: owner execute or 0100 X * Disable Queing: group execute or 0010 X * Queue handler active (antique) 0001 X */ X#define DISABLE_PRINT (0100) X#define ENABLE_PRINT (0777 & ~ DISABLE_PRINT) X#define DISABLE_QUEUE (0010) X#define ENABLE_QUEUE (0777 & ~ DISABLE_QUEUE) X#define FORCE_REQUE (0001) X#define CLEAR_REQUE (0777 & ~ FORCE_REQUE) X X/* X * syslog(8) message priorities. These are defined by the values of X * global variables. The variables are initialized either with values X * in the <syslog.h> include file, or by a set of default values according X * to the NOSYSLOG option in the Makefile. X */ extern int XLOG_ERR; /*4 synonym of LOG_ERROR */ extern int XLOG_CRIT; /*5 critical information */ extern int XLOG_WARNING; /*6 warning */ extern int XLOG_NOTICE; /*7 important information */ extern int XLOG_INFO; /*8 informational message */ extern int XLOG_DEBUG; /*9 Debug level info */ X X/******************************************************************* X * Printcap Data Structures X * The printcap file information is extracted using a single pass of X * the printcap database. As each entry is found, it is looked up X * in a table which has the entry tag, the type of entry, X * a default value, and the variable used to hold the value. X * X * The table is sorted alphabetically by the tag values and the update X * routines use a modified binary search. The time taken to read the X * printcap entry is proportional to X * K log( M ), where K is the length of the printcap file and M is X * the number of printcap variables. Note that this appears to be X * a much simpler and easier way to implement printcap information X * extraction. The "initialization" of the entire set of variables X * is extremely fast, apparently taking about the same time as reading X * two variables using the original "termcap" code. X *******************************************************************/ typedef struct pc_entry{ X char pc_name[3]; /* two character name, and the last char */ X int kind; /* the kind of entry */ X# define PC_NUM 0 /* integer */ X# define PC_FLAG 1 /* integer */ X# define PC_STRING 2 /* string */ X int idefault; /* this is the default integer or flag value */ X char *sdefault; /* this is the default integer or flag value */ X /* X * the variable is assumed to be a pointer to char; X * this is cast to pointer to int if neccessary. X */ X char **var; X} PC_ENTRY; X X/* X * Routines to look up printer names and printcap entries X * char ** All_printers(): reads the printcap database and extracts the X * names of all the printer entries. X * char *First_printer(): gets name of first printer X * Get_pc_entry(): given name of a printer and an array of PC_ENTRIES, X * it finds the printcap entry and extracts all the information X * for the variables listed in the array. X * Set_pc_entry(): same functionality, does not initialize variables. X */ X#define PRNAMELEN 32 /* Maximum of 32 characters for printer name */ X#define MAXPCNAMES 100 /* Maximum of 100 printers */ extern int Get_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */); extern int Set_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */); extern char **All_printers(); /* returns array printer names */ extern char *First_printer(); /* returns array printer names */ X/* X * All_pc_vars[]: all printcap variables, and is used by lpr and lpd; X * Status_pc_vars[]: a short set needed by lpq, lprm, and lpc. X * Server_pc_vars[]: a few needed by servers only X */ extern PC_ENTRY All_pc_vars[ /* All_pc_len */ ]; extern int All_pc_len; extern PC_ENTRY Status_pc_vars[ /* Status_pc_len */ ]; extern int Status_pc_len; extern PC_ENTRY Server_pc_vars[ /* Server_pc_len */ ]; extern int Server_pc_len; X X/*********************************************************************** X * File Locking Support: X * see lockfile.c for details. X ***********************************************************************/ extern FILE *Readlockfile(); /* reads file, returns FILE * */ extern FILE *Getlockfile(); /* locks file, returns FILE * */ extern int Checklockfile(); /* checks for lock and daemon */ extern FILE *Lockcf(); /* lock a control file */ extern int Exlockcf(); /* create and lock a control file */ X X/*********************************************************************** X * Parameter List Support X * struct parm parmlist[] X * is used when parsing a command received from a remote Host X * It is also used by lpr to determine the command file, and to keep X * track of the file/datafile name correspondence. X ***********************************************************************/ X#define MAXPARMS 50 struct parm{ X char *str; /* string parameter */ X int num; /* number parameter */ X char filename[CFNAMELEN+1]; /* file name for parameter */ X long size; /* size of file */ X}; extern struct parm Parms[MAXPARMS]; /* array of parmaters */ extern int Parmcount; /* number of parameters */ X X/*********************************************************************** X * Request types X * A request sent to the LPD daemon has the format: X * \Xprinter [options], where \X is a single character or byte value. X * The following are the values and commands X ***********************************************************************/ X#define REQ_START 1 /* start printer */ X#define REQ_RECV 2 /* transfer a job to the Host from a remote site */ X#define REQ_DSHORT 3 /* print short form of queue status */ X#define REQ_DLONG 4 /* print long form of queue status */ X#define REQ_REMOVE 5 /* remove jobs */ X#define REQ_CONTROL 6 /* do control operation */ X/************************************************************************** X * Control file format X * First character is kind of entry, remainder of line is X * the argument. X * X * 1 -- "R font file" for troff -ignore X * 2 -- "I font file" for troff -ignore X * 3 -- "B font file" for troff -ignore X * 4 -- "S font file" for troff -ignore X * C -- "class name" on banner page X * H -- "Host name" of machine where lpr was done X * I -- "indent" amount to indent output X * J -- "job name" on banner page X * L -- "literal" user's name to print on banner X * M -- "mail" to user when done printing X * N -- "name" of file (used by lpq) X * P -- "Person" user's login name X * R -- account id for charging X * U -- "unlink" name of file to remove after we print it X * W -- "width" page width for PR X * X -- "header" header title for PR X * Z -- xtra options to filters X * X * Lower case letters are formats X * f -- "file name" name of text file to print X * l -- "file name" text file with control chars X * p -- "file name" text file to print with pr(1) X * t -- "file name" troff(1) file to print X * n -- "file name" ditroff(1) file to print X * d -- "file name" dvi file to print X * g -- "file name" plot(1G) file to print X * v -- "file name" plain raster file to print X * c -- "file name" cifplot file to print X * X * CFparm is used to hold the upper case parameters X */ extern char CFparm[26][MAXPARMLEN+1]; X#define CLASSNAME CFparm['C'-'A'] X#define WHENSP CFparm['D'-'A'] X#define FROMHOST CFparm['H'-'A'] X#define INDENT CFparm['I'-'A'] X#define JOBNAME CFparm['J'-'A'] X#define BNRNAME CFparm['L'-'A'] X#define FILENAME CFparm['N'-'A'] X#define MAILNAME CFparm['M'-'A'] X#define LOGNAME CFparm['P'-'A'] X#define ACCNTNAME CFparm['R'-'A'] X#define NOHEADER CFparm['S'-'A'] X#define WHENUNSP CFparm['T'-'A'] X#define UNLNKFILE CFparm['U'-'A'] X#define PWIDTH CFparm['W'-'A'] X#define PRTITLE CFparm['X'-'A'] X#define ZOPTS CFparm['Z'-'A'] X X/* X * printjob return codes X */ X#define JBUSY -1 /* being done by other means */ X#define JFAIL 0 /* repeat with retry */ X#define JSUCC 1 /* done */ X#define JABORT 2 /* done, but problems */ X X/* X * Mail program X */ X#ifndef MAIL X#define MAIL "/usr/lib/sendmail" X#endif MAIL X X/* X * File Transfer Protocol Flags X */ X#define CEND 5 /* last file */ X#define CNAME 4 /* control file */ X#define DFILE 3 /* data file */ X#define CFILE 2 /* control file */ X X/* X * Local parameters to the spooling system X * Defaults for line printer capabilities data base X */ X#define DEFLOGF "log" X#define DEFLOCK "lock" X#define DEFSTAT "status" X#define DEFACCT "acct" X#define DEFFORMATS "flp" /* default formats */ X#define DEFMX 1000 X#define DEFRETRY 3 /* maximum number of retries */ X#define DEFMAXCOPIES 0 X#define DEFFF "\f" X#define DEFWIDTH 132 X#define DEFLENGTH 66 X#define DAEMON "daemon" /* daemon user id */ X#define DEFPRICE 20 /* cost in dollars per thousand pages */ X#define DEFPRIORITY 'Z' /* default priority level */ X#define DEFPR "/bin/pr" /* default pr program */ X X/* X * REAL, not TEST version X */ X X/* X * path name of files created by lpd. X */ X#define RMASTERLOCK "/usr/spool/lpd/lpd.lock." X#define RDEFLPDLOGF "/usr/spool/lpd/lpd.log." X#ifdef ETCPC X# define RPRINTCAP ETCPC X#else X# define RPRINTCAP "/usr/spool/lpd/printcap." X#endif X/* X * connection services to be used X */ X#define SERVERNAME "printer" X#define SERVERPROT "tcp" X/* name of the printer permissions file */ X#ifdef ETCPERMS X# define RPERMFILE ETCPERMS X#else X# define RPERMFILE "/usr/spool/lpd/printer_perms." X#endif X/* X * The remote client must call from a port in the following range. X * This is used for authentication purposes. The ports less than X * IPPORT_RESERVED are accessible only to SU processes. X */ X#define RMINPORTNO (IPPORT_RESERVED/2) X#define RMAXPORTNO (IPPORT_RESERVED) X X/* X * DEBUG Version, use to avoid screwing up normal operations X * path name of files created by lpd. X */ X#define TMASTERLOCK "/tmp/lpd.lock." X#define TDEFLPDLOGF "/tmp/lpd.log." X#define TPRINTCAP "/tmp/printcap." X/* X * connection services to be used X */ X#define TSERVICENAME "testlpr" X#define TPORTNUM 1600 /* test port number */ X/* name of the printer permissions file */ X#define TPERMFILE "/tmp/printer_perms." X/* X * The remote client must call from a port in the following range. X * This is used for authentication purposes. The ports less than X * IPPORT_RESERVED are accessible only to SU processes. X */ X#define TMINPORTNO (IPPORT_RESERVED+1) X#define TMAXPORTNO (2*IPPORT_RESERVED) END_OF_FILE if test 23350 -ne `wc -c <'src/lp.h'`; then echo shar: \"'src/lp.h'\" unpacked with wrong size! fi # end of 'src/lp.h' fi if test -f 'src/utils.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/utils.c'\" else echo shar: Extracting \"'src/utils.c'\" \(25393 characters\) sed "s/^X//" >'src/utils.c' <<'END_OF_FILE' X/*************************************************************************** X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell X *************************************************************************** X * MODULE: utils.c X * Utility routines used by several programs X *************************************************************************** X * Revision History: Created Sat Jan 9 15:02:12 CST 1988 X * $Log: utils.c,v $ X * Revision 3.2 88/06/24 17:55:27 papowell X * MODS for VAX 4.3BSD UNIX X * X * Revision 3.1 88/06/18 09:35:55 papowell X * Version 3.0- Distributed Sat Jun 18 1988 X * X * Revision 2.4 88/05/19 10:34:26 papowell X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed X * X * Revision 2.3 88/05/16 12:09:27 papowell X * Spelling mistake in error messages X * X * Revision 2.2 88/05/14 10:18:31 papowell X * Use long format for job file names; X * Added 'fd', no forward flag; X * Control file has to have hostname and origination agree. X * X * Revision 2.1 88/05/09 10:10:42 papowell X * PLP: Released Version X * X * Revision 1.7 88/04/27 20:27:34 papowell X * Modified to remove unused variables X * X * Revision 1.6 88/04/15 13:06:55 papowell X * Std_environ() call added, to ensure that fd 0 (stdin), 1 (stdout), 2(stderr) X * have valid file descriptors; if not open, then /dev/null is used. X * X * Revision 1.5 88/03/25 15:01:57 papowell X * Debugged Version: X * 1. Added the PLP control file first transfer X * 2. Checks for MX during file transfers X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities; X * apparently they open files and then assume that they will stay X * open. X * 4. Made sure that stdin, stdout, stderr was available at all times. X * X * Revision 1.4 88/03/12 10:03:45 papowell X * *** empty log message *** X * X * Revision 1.3 88/03/11 19:29:25 papowell X * Minor Changes, Updates X * X * Revision 1.2 88/03/05 15:01:28 papowell X * Minor Corrections, Lint Problems X * X * Revision 1.1 88/03/01 11:09:27 papowell X * Initial revision X * X ***************************************************************************/ X#ifndef lint static char id_str1[] = X "$Header: utils.c,v 3.2 88/06/24 17:55:27 papowell Exp $ PLP Copyright 1988 Patrick Powell"; X#endif lint X X#include "lp.h" X/* X * Time_str: return ctime() value, but without terminating '\n' X */ char * Time_str() X{ X time_t tvec; /* time */ X char *ctime(); X static char s[40]; X X (void)time(&tvec); X (void)strcpy(s,ctime(&tvec)); X s[strlen(s)-1] = 0; X return( s ); X} X X/*************************************************************************** X * Remove_job( FILE *fp; struct queue *q ) X * Remove a job and all associated files; if success == JSUCC, remove X * U links as well X * ACTIONS: X * 1. Read the control file X * 2. get data file names and unlink them if they match the job X * 3. Unlink the control file X ***************************************************************************/ X Remove_job( fp, q ) X FILE *fp; X struct queue *q; X{ X char parm[BUFSIZ]; /* line buffer */ X char *arg; /* pointer to the argument */ X int c; /* ACME Integers, Inc. */ X X if(Debug>5)log(XLOG_DEBUG,"Remove_job: %s", q->q_name ); X clearerr( fp ); X if( fseek( fp, 0L, 0 ) < 0 ){ X logerr_die( XLOG_INFO, X "Remove_job: fseek failed (%s)", q->q_name ); X } else { X /* X * read through the file, looking for things to remove X */ X while(fgets( parm, sizeof(parm), fp )){ X if( (arg = index(parm, '\n')) == 0 ){ X log( XLOG_INFO, "Remove_job: file bad (%s), no endline", X q->q_name); X continue; X } X *arg = 0; X arg = parm+1; X c = parm[0]; X /* X * is it a format line? X */ X if( !isascii( c ) || !islower( c ) ){ X continue; X } X if( Job_match( q->q_name, arg ) == 0){ X if(Debug>4)log(XLOG_DEBUG,"Remove_job: bad file name '%s'", X arg ); X continue; X } X (void)unlink_daemon( arg ); X } X } X if( unlink_daemon( q->q_name ) < 0 ){ X logerr( XLOG_INFO, "Remove_job: cannot unlink %s", q->q_name ); X } X} X/*************************************************************************** X * int Getq(); X * Scan the spool directory and make a list of server files sorted by X * priority, creation time, etc. X * Returns: the number of entries X * Side Effects: sets struct queue *Queue to point to an array of pointers X * to queue entries X ***************************************************************************/ static int arraysz; /* number of entries in array */ static struct queue qb; /* for zeroing purposes */ X Getq() X{ X struct direct *d; /* directory entry */ X int nitems; /* ACME Integers, Inc. */ X struct stat stbuf; /* for statting files */ X int compar(); /* for sorting files */ X DIR *dirp; /* used by directory routines */ X char l[BUFSIZ]; /* for reading the control file */ X char fullname[BUFSIZ]; /* for the full pathname */ X char *filepart; /* end of the pathname */ X FILE *cfp; /* control file FP */ X struct queue *q; /* pointer to queue entry */ X char *bp, *ep; /* ACME Pointers, Inc. */ X X if (SD == 0 || *SD == 0 ){ X fatal( XLOG_INFO, "no directory entry" ); X } X if ((dirp = opendir(SD)) == NULL){ X logerr_die( XLOG_INFO, "cannot open spool directory %s", SD ); X } X X /* X * get the directory name and copy to buffer X */ X if( strlen(SD) + sizeof(q->q_name) + 2 > sizeof(fullname) ){ X logerr_die( XLOG_NOTICE,"INTERNAL: Getq, file name too big" ); X } X (void)strcpy(fullname,SD); X filepart = &fullname[strlen(fullname)]; X *filepart++ = '/'; X /* X * assume you have 100 entries to start with X */ X if( arraysz == 0 ){ X arraysz = 100; X Queue = (struct queue *)malloc( X (unsigned)(arraysz * sizeof(struct queue))); X if (Queue == NULL){ X logerr_die( XLOG_INFO, "Getq: malloc failed" ); X } X } X /* X * set the item count to 0 and scan the directory X */ X nitems = 0; X while ((d = readdir(dirp)) != NULL) { X if(Debug>5)log(XLOG_DEBUG,"Getq: file %s", d->d_name ); X X if (d->d_name[0] != 'c' || d->d_name[1] != 'f'){ X continue; /* server control files only */ X } X /* X * Check to make sure the array has space left and X * realloc the maximum size. X */ X if( nitems >= arraysz ){ X /* try to get another buffer */ X arraysz = arraysz + 20; X Queue = (struct queue *)realloc((char *)Queue, X (unsigned)((arraysz)*sizeof(struct queue))); X if (Queue == NULL){ X logerr_die(XLOG_NOTICE,"malloc failed in Getq" ); X } X } X /* X * get next queue entry and clear it X */ X q = &Queue[nitems]; X *q = qb; /* zero it out the easy way */ X X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s", d->d_name ); X X /* copy the name of the file */ X if( strlen( d->d_name ) >= CFNAMELEN){ X logerr_die(XLOG_NOTICE,"control file name %s too long", d->d_name ); X } X (void)strcpy(q->q_name, d->d_name); X (void)strcpy(filepart,d->d_name); X if (stat(fullname, &stbuf) < 0){ X continue; /* Doesn't exist */ X } X /* get the modification time */ X q->q_time = stbuf.st_mtime; X /* set a priority */ X q->q_priority = d->d_name[2]; X /* get the job number */ X q->q_num = atoi( &d->d_name[3] ); X X /* X * now we open the control file and read the information X */ X if( (cfp = fopen_daemon( fullname, "r" )) == NULL ){ X /* it disappeared */ X continue; X } X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s readable", d->d_name ); X bp = q->q_data; X ep = bp + sizeof(q->q_data); X while( fgets( l, sizeof(l), cfp) ){ X /* clobber the \n */ X l[strlen(l)-1] = 0; X if( islower( l[0] ) ){ X /* get size of file to be printed */ X (void)strcpy(filepart, &l[1] ); X if( stat( fullname, &stbuf) < 0){ X (void)fclose(cfp); X if(Debug>5)log(XLOG_DEBUG, X "Getq: data file %s does not exist", l ); X } else { X q->q_size += stbuf.st_size; X } X } else switch( l[0] ){ X case 'N': /* name of file */ X bp = estrcp( bp, &l[1], ep ); X bp = estrcp( bp, " ", ep ); X break; X case 'P': /* name of user */ X (void)strncpy( q->q_user, &l[1], sizeof(q->q_user)-1); X break; X case 'D': /* when spooled */ X q->q_sp = (time_t)atol( &l[1] ); X break; X case 'T': /* when to be unspooled */ X q->q_unsp = (time_t)atol( &l[1] ); X break; X default: break; X } X } X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s is ok", d->d_name ); X X (void)fclose(cfp); X ++nitems; X } X closedir(dirp); X X /* X * sort the queue X */ X if (nitems){ X qsort((char *)Queue, nitems, sizeof(struct queue), compar); X } X return(nitems); X} X X X/* X * Compare queue entries by X * 1. Priority X * 2. Time X */ static compar(c1, c2) X char *c1, *c2; X{ X struct queue *p1, *p2; X X p1 = (struct queue *)c1; X p2 = (struct queue *)c2; X if ((p1)->q_priority < (p2)->q_priority) X return(-1); X if ((p1)->q_priority > (p2)->q_priority) X return(1); X if ((p1)->q_time < (p2)->q_time) X return(-1); X if ((p1)->q_time > (p2)->q_time) X return(1); X return(0); X} X X/*************************************************************************** X * Match_entry( struct queue *q ) X * check the user name and job number against the parmlist starting at start; X * Return: 1 if match found, 0 otherwise X ***************************************************************************/ int Match_entry( q ) X struct queue *q; X{ X int i; /* ACME Integer, Inc. */ X X if(Debug>4)log(XLOG_DEBUG,"Match_entry on %s, %d", q->q_user, q->q_num ); X for( i = 0; i < Parmcount; ++i ){ X if( (Parms[i].num >= 0 && Parms[i].num == q->q_num) X || strcmp( Parms[i].str, q->q_user ) == 0 ){ X return(1); X } X } X return(0); X} X X/*************************************************************************** X * bpread( int fd ; char *buf; int size ) X * Almost bombproof way to read command line from socket X * Returns: -1 if unable to read a line terminated with \n X * 0 if 0 length line or first character is null (i.e.- no input) X * otherwise: length of line X ***************************************************************************/ bpread( fd, buf, size ) X int fd; X char *buf; X int size; X{ X int n; /* ACME Integer, Inc. */ X int i; X X /* X * Bombproof line reading X */ X for( i = 0; i < size; ++i ){ X n = read(fd, &buf[i], 1); X if( n < 0 ){ X logerr(XLOG_INFO,"bpread: lost connection"); X return( -1 ); X } else if( n == 0 ){ X log(XLOG_INFO,"bpread: bad format %s", buf ); X return( 0 ); X } X if( buf[i] == '\n' ){ X buf[i] = 0; X if(Debug>3)log(XLOG_DEBUG,"bpread: '%d' %s", buf[0], &buf[1]); X return( i ); X } else if( buf[i] == 0 && i == 0 ){ X if(Debug>3)log(XLOG_DEBUG,"bpread: zero byte first"); X return( i ); X } X } X log(XLOG_INFO,"bpread: bad line %s", buf ); X return( -1 ); X} X/*************************************************************************** X * estrcp(char *s, *t, *e) X * copies t to s, and returns the end position X * Returns: end of string if the result is shorter than e, NULL otherwise X * Note: this is a very useful routine. Think about adding it to string X * functions. X ***************************************************************************/ char * estrcp( s,t,e ) X char *s, *t, *e; X{ X if( s ){ X while( (*s++ = *t++) && (s < e) ); X if( s < e ){ X return( s-1 ); X } else { X return( (char *)0 ); X } X } X return( s ); X} X/*************************************************************************** X * splitline( char *line ) X * splits a line into tokens, and places them in the Parms[] array. X * if firstarg is present then it is set to the first argument X * Side Effects: modifies Parms, Parmcount X ***************************************************************************/ X splitline( bp ) X char *bp; X{ X /* find the start */ X while (*bp) { X while( *bp && isspace(*bp)) X bp++; X if( *bp ){ X if( Parmcount >= MAXPARMS ){ X fatal(XLOG_INFO,"splitline: too many requests"); X } X Parms[Parmcount].str = bp; X if (isdigit(*bp)) { X Parms[Parmcount].num = atoi(bp); X } else { X Parms[Parmcount].num = -1; X } X Parmcount++; X } X while( *bp && !isspace(*bp)) X bp++; X if( *bp ) X *bp++ = 0; X } X} X/********************************************************************** X * Shift_parms( int n ) X * left shift the entries in the Parms[] array by n X * Side Effects: modifies Parms and Parmcount X **********************************************************************/ Shift_parms( n ) X int n; X{ X int i; /* ACME Chain and Integer, Inc. */ X while( Parmcount > 0 && n > 0 ){ X for( i = 1; i < Parmcount; ++i ){ X Parms[i-1] = Parms[i]; X } X --Parmcount; X --n; X } X} X printstatus() X{ X if( ST && *ST ){ X if(Debug>4)log(XLOG_DEBUG,"printstatus: ST %s", ST ); X pr_stat_file( ST ); X } X if( PS && *PS ){ X if(Debug>4)log(XLOG_DEBUG,"printstatus: PS %s", PS ); X pr_stat_file( PS ); X } X} X pr_stat_file( file ) X char *file; X{ X FILE *fp; X char buf[BUFSIZ]; X X if( (fp = fopen_daemon( file, "r" )) != NULL ){ X while( fgets( buf, sizeof(buf), fp) != NULL ){ X (void)fprintf(stdout, " %s", buf ); X } X (void)fflush(stdout); X (void)fclose( fp ); X } X} X/*************************************************************************** X * char *Sigstr(n) X * Return a printable form the the signal X ***************************************************************************/ X struct signame{ X char *str; X int value; X} signals[] = { X{ "SIGHUP", SIGHUP }, { "SIGINT", SIGINT }, { "SIGQUIT", SIGQUIT }, X{ "SIGILL", SIGILL }, { "SIGTRAP", SIGTRAP }, { "SIGIOT", SIGIOT }, X{ "SIGEMT", SIGEMT }, { "SIGFPE", SIGFPE }, { "SIGKILL", SIGKILL }, X{ "SIGBUS", SIGBUS }, { "SIGSEGV", SIGSEGV }, { "SIGSYS", SIGSYS }, X{ "SIGPIPE", SIGPIPE }, { "SIGALRM", SIGALRM }, { "SIGTERM", SIGTERM }, X{ "SIGURG", SIGURG }, { "SIGSTOP", SIGSTOP }, { "SIGTSTP", SIGTSTP }, X{ "SIGCONT", SIGCONT }, { "SIGCHLD", SIGCHLD }, { "SIGTTIN", SIGTTIN }, X{ "SIGTTOU", SIGTTOU }, { "SIGIO", SIGIO }, { "SIGXCPU", SIGXCPU }, X{ "SIGXFSZ", SIGXFSZ }, { "SIGVTALRM", SIGVTALRM }, { "SIGPROF", SIGPROF } }; int nsignals = sizeof( signals )/ sizeof( struct signame ); char * Sigstr( n ) X int n; X{ X int i; X static char buf[40]; X X for( i = 0; i < nsignals; ++i ){ X if( signals[i].value == n ){ X return( signals[i].str ); X } X } X (void)sprintf(buf,"unknown signal (%d)", n ); X return( buf ); X} X/*************************************************************************** X * Decode_status( union wait *status ) X * returns a printable string encoding return status X ***************************************************************************/ X char * Decode_status( status ) X union wait *status; X{ X static char msg[BUFSIZ]; X X (void)sprintf( msg, "user: %d, system: %d%s", X status->w_retcode, status->w_termsig, X status->w_coredump ? ", core dump, " : ", " ); X if( status->w_termsig ){ X (void)sprintf(msg+strlen(msg),"error- %s", X Sigstr((int)status->w_termsig)); X } X return( msg ); X} X X/* X * Checkactive() X * find the currently active files in the spool queue. X * 1. check for the single server possibility first. X * 2. find the Names of the servers X * 3. find the active files for each of the servers X */ X int Checkactive() X{ X int i; /* ACME Integers, Inc. */ X char buf[BUFSIZ]; /* Name of active file */ X static char server[BUFSIZ]; /* Name of server file */ X char *sp, *ep; /* ACME Pointer */ X int pid; X X pid = 0; X buf[0] = 0; X if(Checklockfile(LO,&pid,buf,sizeof(buf),&LO_statb) && buf[0] ){ X for( i = 0; i < Jobcount; ++i ){ X if( strcmp( buf, Queue[i].q_name ) == 0 ){ X Queue[i].q_daemon = pid; X Queue[i].q_server = Printer; X } else { X Queue[i].q_daemon = 0; X Queue[i].q_server = 0; X } X } X } X /* X * check for each of the servers X */ X if( SV && *SV ){ X (void)strcpy( server, SV ); X for( sp = server; sp; sp = ep ){ X if( ep = index( sp, ',' ) ){ X *ep = 0; X ++ep; X } X /* X * get the lock file and the status from the server X */ X buf[0] = 0; X if(Checklockfile(sp,&pid,buf,sizeof(buf),(struct stat *)0) X && buf[0] ){ X for( i = 0; i < Jobcount; ++i ){ X if( strcmp( buf, Queue[i].q_name ) == 0 ){ X Queue[i].q_daemon = pid; X Queue[i].q_server = sp; X } else { X Queue[i].q_daemon = 0; X Queue[i].q_server = 0; X } X } X } X } X } X return(pid); X} X X X/*************************************************************************** X * Get_Daemon() X * Get the DAEMON uid and gid X * Assume password entry has both values set for the user daemon X ***************************************************************************/ Get_Daemon() X{ X struct passwd *passwd, *getpwnam(); X if( Daemon_uid == 0 ){ X if( (passwd = getpwnam(DAEMON)) == 0 ){ X logerr_die( XLOG_INFO,"Get_Daemon: getpwnam(%s) failed", DAEMON ); X } X Daemon_uid = passwd->pw_uid; X Daemon_gid = passwd->pw_gid; X if(Debug>4)log(XLOG_INFO,"Get_Daemon: uid=%d, gid=%d", X Daemon_uid, Daemon_gid); X } X} X X/*************************************************************************** X * Job_match( char *control, *data) X * Check to see if the control and data file names are matching X * 1. data file must start with "df" X * 2. next must be letter X * 3. next must be 3 digit sequence number X * 4. control and data file sequence number must match X * return 1 if OK, 0 if not X ***************************************************************************/ X Job_match( control, data ) X char *control; X char *data; X{ X int c, i, j; /* ACME Chain and Integers, Inc. */ X X i = strlen( data ); X for( j = 0; j < i ; ++j ){ X c = data[j]; X if( !isascii( c ) || !isprint( c ) ){ X log(XLOG_INFO, "Job_match: bad char in '%s'", data ); X return( 0 ); X } X } X if( index( data, '/' ) ){ X /* X * tried to embed a / in the file name X */ X log(XLOG_INFO, "Job_match: / present '%s'", data ); X return( 0 ); X } X if( i > CFNAMELEN X || i <= STARTFR X || i != strlen( control ) X || index( "cd", data[0] ) == 0 X || (data[1] != 'f') X || !isalpha( data[STARTPR] ) X || strcmp( control+STARTID, data+STARTID ) ){ X log(XLOG_INFO, "Job_match: bad match control '%s', data '%s'", X control, data ); X return( 0 ); X } X for( j = 0; j < IDLEN; ++ j ){ X if( !isdigit( data[j+STARTID] ) ){ X log(XLOG_INFO, "Job_match: bad sequence control '%s', data '%s'", X control, data ); X return( 0 ); X } X } X if(Debug>5)log(XLOG_DEBUG,"Job_match: OK control '%s', data '%s'", X control, data ); X return( 1 ); X} X X/*************************************************************************** X * Std_environ() X * Make sure that fd 0, 1, 2 exist by opening /dev/null for them if they X * have not been provided. X * Set up the Host information as well X ***************************************************************************/ X Std_environ() X{ X int fd; X struct hostent *host_ent; /* host entry from data base */ X X /* X * close all file descriptors up to NOFILE X */ X for (fd = 3; fd < NOFILE; fd++){ X (void) close(fd); X } X while( (fd = open( "/dev/null", O_RDWR, 0 )) >= 0 && fd < 3 ); X if( fd < 0 ){ X logerr_die( XLOG_CRIT, "Std_environ: cannot open /dev/null" ); X } else { X (void)close(fd); X } X /* X * get the Host computer Name X */ X if( gethostname(Host, sizeof(Host)) < 0 ){ X logerr_die( XLOG_INFO, "Std_environ: gethostname failed" ); X } X host_ent = gethostbyname( Host ); X if( host_ent == 0 ){ X fatal( XLOG_INFO, "Std_environ: host entry for '%' not found", Host ); X } X if( strlen( host_ent->h_name ) > sizeof( Host ) ){ X fatal( XLOG_INFO, "Std_enviorn: host name is too long: '%s'", X host_ent->h_name); X } X (void)strcpy(Host, host_ent->h_name ); X /* X * Get Daemon UID X */ X Get_Daemon(); X} X X/*************************************************************************** X * int open_daemon() X * FILE *fopen_daemon() X * int unlink_daemon() X * Do the above actions as DAEMON. X * Note that this is very difficult to do, and ensure that all the error X * conditions are met. What you want to do is perform the following as X * an uninterrupted critical section. X * 1. setreuid( root, daemon) X * 2. perform the action X * 3. setreuid( whatever, root ) X * This will only work if X * 1. you are really root X * 2. you do not ever get interrupts X ***************************************************************************/ static uid_t ruid, euid; /* real and effective UIDs */ static int uid_parm; /* must be able to hold -1 */ static int omask; /* block these signals */ X X void Set_uid( new_uid ) X int new_uid; X{ X /* X * get the DAEMON UID, GID X */ X omask = sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP) X |sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); X ruid = getuid(); X euid = geteuid(); X X# ifdef SETREUID4BSD X uid_parm = euid; X# else X uid_parm = -1; X# endif SETREUID4BSD X /* X * check to see if we are running without SUID X */ X if( euid && euid != getuid() && euid != new_uid ){ X log( XLOG_INFO, "Set_uid: euid %d, ruid %d, bad SUID?", X euid, getuid() ); X /* X * NOTE: do not try and take normal exit!!! X */ X exit(1); X } else if( euid == 0 && setreuid( uid_parm, new_uid ) < 0 ){ X logerr( XLOG_INFO, "Set_uid: setreuid( %d, %d) failed", X uid_parm, new_uid ); X exit(1); X } X if(Debug>4)log(XLOG_DEBUG,"Set_uid: uid_parm %d, uid %d, euid %d", X uid_parm, getuid(), geteuid()); X} X/* X * set the UID to DAEMON X */ void Set_daemon() X{ X /* X * get the DAEMON UID, GID X */ X Get_Daemon(); X Set_uid( Daemon_uid ); X} X/* X * set UID back to normal. Note that there are two versions of setreuid X * available. The VAX 4.2/4.3 version allows you to swap RUID/EUID X * and will allow you only to set your UID if you are EUID root. X * The SUN 3.X and others will allow you ONE call to the SUID function, X * and will allow you to set the UID back to the original. The X * uid_parm flag determines which strategy to use. X * If uid_parm is -1, then you have to use setreuid( -1, euid ) X * If it is not, then we have to swap the EUID/UID, then set X * the UID and EUID explicitly X */ void Clear_uid() X{ X /* X * handle the easy one first: set euid back to original X */ X if( uid_parm == -1 ){ X if( setreuid( -1, euid ) < 0 ){ X logerr( XLOG_INFO, X "Clear_uid: setreuid( %d, %d) from %d, %d failed", X -1, euid, getuid(), geteuid() ); X /* X * avoid problems, exit early X */ X exit(1); X } X (void)sigsetmask(omask); X return; X } X /* X * otherwise we swap the UID and EUID, but first make sure that it is X * consistent; uid should be the old (original) euid on entry to set_uid X */ X if( getuid() != euid ){ X logerr( XLOG_INFO, X "Clear_uid: uid is %d, euid is %d, and uid should be %d", X getuid(), geteuid(), euid ); X exit(1); X } X /* X * swap the RUID and EUID X */ X if( setreuid( geteuid(), getuid() ) < 0 ){ X logerr( XLOG_INFO, X "Clear_uid: setreuid( %d, %d) from %d, %d failed", X geteuid(), getuid(), getuid(), geteuid() ); X /* X * avoid problems, exit early X */ X exit(1); X } X /* X * Set the RUID and EUID explicitly X */ X if( setreuid( ruid, euid ) < 0 ){ X logerr( XLOG_INFO, X "Clear_uid: setreuid( %d, %d) from %d, %d failed", X ruid, euid, getuid(), geteuid() ); X /* X * avoid problems, exit early X */ X exit(1); X } X (void)sigsetmask(omask); X} X X/* X * Open a file as daemon. X */ int open_daemon( name, flag, perms ) X char *name; X int flag; X int perms; X{ X int fd, err; X /* X * establish UID X */ X Set_daemon(); X /* X * now for the plunge into the unknown X */ X fd = open( name, flag, perms ); X err = errno; X Clear_uid(); X errno = err; X return( fd ); X} X X/* X * fopen a file; the file has been created, and we want to do this as X * daemon for permissions reasons. X */ XFILE * fopen_daemon( name, how ) X char *name; X char *how; X{ X int err; X FILE *fp; X /* X * establish UID X */ X Set_daemon(); X /* X * now for the plunge into the unknown X * NOTE: we are assuming that we only use this to READ a file already X * created. X */ X fp = fopen( name, how ); X err = errno; X /* X * done with the daemon stuff X */ X Clear_uid(); X errno = err; X return( fp ); X} X X/* X * UNLINK a file as DAEMON X */ unlink_daemon( name ) X char *name; X{ X int f, err; X /* X * establish UID X */ X Set_daemon(); X /* X * now for the plunge into the unknown X */ X f = unlink( name ); X err = errno; X /* X * done with the daemon stuff X */ X Clear_uid(); X errno = err; X return( f ); X} X X X/* X * CHMOD a file as DAEMON X */ chmod_daemon( name, perms ) X char *name; X int perms; X{ X int f, err; X /* X * establish UID X */ X Set_daemon(); X /* X * now for the plunge into the unknown X */ X f = chmod( name, perms ); X err = errno; X /* X * done with the daemon stuff X */ X Clear_uid(); X errno = err; X return( f ); X} X X/*************************************************************************** X * Rename_cf( char *tf ) X * rename the temporary file to a control file X ***************************************************************************/ X Rename_cf( tf ) X char *tf; X{ X char from[MAXPATHLEN+1]; X char to[MAXPATHLEN+1]; X int i, err; X X (void)sprintf( from, "%s/%s", SD, tf ); X (void)sprintf( to, "%s/c%s", SD, tf+1 ); X if(Debug>4)log(XLOG_DEBUG,"Rename_cf: from '%s' to '%s'",from, to); X Set_daemon(); X i = rename( from, to ); X err = errno; X Clear_uid(); X errno = err; X if( i < 0 ){ X logerr_die(XLOG_INFO,"Rename_cf: rename '%s' to '%s' failed",from, to); X } X} X X/*************************************************************************** X * Tailor_names() X * Appends the Host information to several file names. X ***************************************************************************/ static append_name( s, t ) X char *s, *t; X{ X if( (strlen(s) + strlen(t) + 2) > MAXPATHLEN ){ X fatal( XLOG_INFO,"append_name: names too long 's' + 't'", s, t); X } X (void)strcat( s, t); X} Tailor_names() X{ X append_name( Lpdlogf, Host ); X append_name( Masterlock, Host ); X append_name( Permfile, Host ); X append_name( Printcap, Host ); X} END_OF_FILE if test 25393 -ne `wc -c <'src/utils.c'`; then echo shar: \"'src/utils.c'\" unpacked with wrong size! fi # end of 'src/utils.c' fi echo shar: End of archive 15 \(of 16\). cp /dev/null ark15isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.