Home | History | Annotate | Download | only in lpsched
      1     0   stevel /*
      2     0   stevel  * CDDL HEADER START
      3     0   stevel  *
      4     0   stevel  * The contents of this file are subject to the terms of the
      5  2660   jacobs  * Common Development and Distribution License (the "License").
      6  2660   jacobs  * You may not use this file except in compliance with the License.
      7     0   stevel  *
      8     0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0   stevel  * or http://www.opensolaris.org/os/licensing.
     10     0   stevel  * See the License for the specific language governing permissions
     11     0   stevel  * and limitations under the License.
     12     0   stevel  *
     13     0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0   stevel  *
     19     0   stevel  * CDDL HEADER END
     20     0   stevel  */
     21  2660   jacobs 
     22     0   stevel /*
     23  2660   jacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24     0   stevel  * Use is subject to license terms.
     25     0   stevel  */
     26   320  ceastha 
     27     0   stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28     0   stevel /*	  All Rights Reserved  	*/
     29     0   stevel 
     30     0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31     0   stevel 
     32     0   stevel #include "stdarg.h"
     33     0   stevel #include "stdlib.h"
     34     0   stevel #include "fcntl.h"
     35     0   stevel #include <sys/param.h>
     36     0   stevel #include "lpsched.h"
     37     0   stevel 
     38     0   stevel 
     39     0   stevel static void check_link();
     40     0   stevel 
     41     0   stevel /**
     42     0   stevel  ** lpfsck()
     43     0   stevel  **/
     44     0   stevel 
     45     0   stevel #define	F	0
     46     0   stevel #define D	1
     47     0   stevel #define P	2
     48     0   stevel #define S	3
     49     0   stevel 
     50     0   stevel static void		proto (int, int, ...);
     51     0   stevel static int		va_makepath(va_list *, char **);
     52     0   stevel static void		_rename (char *, char *, ...);
     53     0   stevel 
     54     0   stevel void
     55     0   stevel lpfsck(void)
     56     0   stevel {
     57     0   stevel 	struct stat		stbuf;
     58     0   stevel 	int			real_am_in_background = am_in_background;
     59     0   stevel 
     60     0   stevel 
     61     0   stevel 	/*
     62     0   stevel 	 * Force log messages to go into the log file instead of stdout.
     63     0   stevel 	 */
     64     0   stevel 	am_in_background = 1;
     65     0   stevel 
     66     0   stevel 	/*
     67     0   stevel 	 * Most of these lines repeat the prototype file from the
     68     0   stevel 	 * packaging and should match those items exactly.
     69     0   stevel 	 * (In fact, they probably ought to be generated from that file,
     70     0   stevel 	 * but that work is for a rainy day...)
     71     0   stevel 	 */
     72     0   stevel 
     73     0   stevel 	/*
     74     0   stevel 	 * DIRECTORIES:
     75     0   stevel 	 */
     76     0   stevel proto (D, 0,  Lp_A, NULL,			    0775, Lp_Uid, Lp_Gid);
     77     0   stevel proto (D, 1,  Lp_A_Classes, NULL,		    0775, Lp_Uid, Lp_Gid);
     78     0   stevel proto (D, 1,  Lp_A_Forms, NULL,			    0775, Lp_Uid, Lp_Gid);
     79     0   stevel proto (D, 1,  Lp_A_Interfaces, NULL,		    0775, Lp_Uid, Lp_Gid);
     80     0   stevel proto (D, 1,  Lp_A_Printers, NULL,		    0775, Lp_Uid, Lp_Gid);
     81     0   stevel proto (D, 1,  Lp_A_PrintWheels, NULL,		    0775, Lp_Uid, Lp_Gid);
     82     0   stevel proto (D, 0,  "/var/lp", NULL,			    0775, Lp_Uid, Lp_Gid);
     83     0   stevel proto (D, 1,  Lp_Logs, NULL,			    0775, Lp_Uid, Lp_Gid);
     84     0   stevel proto (D, 1,  Lp_Spooldir, NULL,		    0775, Lp_Uid, Lp_Gid);
     85     0   stevel proto (D, 1,  Lp_Admins, NULL,			    0775, Lp_Uid, Lp_Gid);
     86     0   stevel proto (D, 1,  Lp_Requests, NULL,		    0775, Lp_Uid, Lp_Gid);
     87     0   stevel proto (D, 1,  Lp_Requests, Local_System, NULL,	    0770, Lp_Uid, Lp_Gid);
     88     0   stevel proto (D, 1,  Lp_System, NULL,			    0775, Lp_Uid, Lp_Gid);
     89     0   stevel proto (D, 1,  Lp_Tmp, NULL,			    0771, Lp_Uid, Lp_Gid);
     90     0   stevel proto (D, 1,  Lp_Tmp, Local_System, NULL,	    0775, Lp_Uid, Lp_Gid);
     91     0   stevel 
     92     0   stevel 	/*
     93     0   stevel 	 * DIRECTORIES: not described in the packaging
     94     0   stevel 	 */
     95     0   stevel proto (D, 0,  Lp_Spooldir, FIFOSDIR, NULL,	    0775, Lp_Uid, Lp_Gid);
     96     0   stevel 
     97     0   stevel 	/*
     98     0   stevel 	 * THE MAIN FIFO:
     99     0   stevel 	 */
    100     0   stevel proto (P, 1,  Lp_FIFO, NULL,			    0666, Lp_Uid, Lp_Gid);
    101     0   stevel 
    102     0   stevel 	/*
    103     0   stevel 	 * SYMBOLIC LINKS:
    104     0   stevel 	 * Watch out! These names are given in the reverse
    105     0   stevel 	 * order found in the prototype file (sorry!)
    106     0   stevel 	 */
    107     0   stevel proto (S, 1,  Lp_Model, NULL,			"/etc/lp/model", NULL);
    108     0   stevel proto (S, 1,  Lp_Logs, NULL,			"/etc/lp/logs", NULL);
    109     0   stevel /*     S, 1,  Lp_Tmp, Local_System, ...    DONE BELOW */
    110     0   stevel proto (S, 1,  Lp_Bin, NULL,			Lp_Spooldir, "bin", NULL);
    111     0   stevel proto (S, 1,  Lp_A, NULL,			Lp_Admins, "lp", NULL);
    112     0   stevel 
    113     0   stevel 	/*
    114     0   stevel 	 * OTHER FILES:
    115     0   stevel 	 */
    116     0   stevel 
    117     0   stevel 	/*
    118     0   stevel 	 * SPECIAL CASE:
    119     0   stevel 	 * If the "temp" symbolic link already exists,
    120     0   stevel 	 * but is not correct, assume the machine's nodename changed.
    121     0   stevel 	 * Rename directories that include the nodename, if possible,
    122     0   stevel 	 * so that unprinted requests are saved. Then change the
    123     0   stevel 	 * symbolic link.
    124     0   stevel 	 * Watch out for a ``symbolic link'' that isn't!
    125     0   stevel 	 */
    126     0   stevel 	if (Lstat(Lp_Temp, &stbuf) == 0)
    127     0   stevel 	    switch (stbuf.st_mode & S_IFMT) {
    128     0   stevel 
    129     0   stevel 	    default:
    130     0   stevel 		Unlink (Lp_Temp);
    131     0   stevel 		break;
    132     0   stevel 
    133     0   stevel 	    case S_IFDIR:
    134     0   stevel 		Rmdir (Lp_Temp);
    135     0   stevel 		break;
    136     0   stevel 
    137     0   stevel 	    case S_IFLNK:
    138     0   stevel 		check_link();
    139     0   stevel 		break;
    140     0   stevel 	    }
    141     0   stevel 
    142     0   stevel 	proto(S, 1, Lp_Tmp, Local_System, NULL,	Lp_Temp, NULL);
    143     0   stevel 
    144     0   stevel 	am_in_background = real_am_in_background;
    145     0   stevel 	return;
    146     0   stevel }
    147     0   stevel 
    148     0   stevel static void
    149     0   stevel check_link()
    150     0   stevel {
    151     0   stevel 	int len;
    152     0   stevel 	char symbolic[MAXPATHLEN + 1];
    153     0   stevel 	char *real_dir;
    154     0   stevel 	char *old_system;
    155     0   stevel 
    156     0   stevel 	if ((len = Readlink(Lp_Temp, symbolic, MAXPATHLEN)) <= 0) {
    157     0   stevel 		Unlink(Lp_Temp);
    158     0   stevel 		return;
    159     0   stevel 	}
    160     0   stevel 
    161     0   stevel 	/*
    162     0   stevel 	 * If the symbolic link contained trailing slashes, remove
    163     0   stevel 	 * them.
    164     0   stevel 	 */
    165     0   stevel 	while ((len > 1) && (symbolic[len - 1] == '/')) {
    166     0   stevel 		len--;
    167     0   stevel 	}
    168     0   stevel 	symbolic[len] = 0;
    169     0   stevel 
    170     0   stevel 	/* check that symlink points into /var/spool/lp/tmp */
    171     0   stevel 	if (strncmp(Lp_Tmp, symbolic, strlen(Lp_Tmp)) != 0) {
    172     0   stevel 		Unlink(Lp_Temp);
    173     0   stevel 		return;
    174     0   stevel 	}
    175     0   stevel 
    176     0   stevel 	/*
    177     0   stevel 	 * Check that symlink points to something.
    178     0   stevel 	 * There should be at least 2 characters
    179     0   stevel 	 * after the string '/var/spool/lp/tmp':
    180     0   stevel 	 * a '/' and another character.
    181     0   stevel 	 */
    182     0   stevel 	if (len <= strlen(Lp_Tmp) + 1) {
    183     0   stevel 		Unlink(Lp_Temp);
    184     0   stevel 		return;
    185     0   stevel 	}
    186     0   stevel 
    187     0   stevel 	real_dir = makepath(Lp_Tmp, Local_System, NULL);
    188     0   stevel 	if (!STREQU(real_dir, symbolic)) {
    189     0   stevel 		if (!(old_system = strrchr(symbolic, '/')))
    190     0   stevel 			old_system = symbolic;
    191     0   stevel 		else
    192     0   stevel 			old_system++;
    193     0   stevel 
    194     0   stevel 		/*
    195     0   stevel 		 * The "rename()" system call (buried
    196     0   stevel 		 * inside the "_rename()" routine) should
    197     0   stevel 		 * succeed, even though we blindly created
    198     0   stevel 		 * the new directory earlier, as the only
    199     0   stevel 		 * directory entries should be . and ..
    200     0   stevel 		 * (although if someone already created
    201     0   stevel 		 * them, we'll note the fact).
    202     0   stevel 		 */
    203     0   stevel 		_rename(old_system, Local_System, Lp_Tmp, NULL);
    204     0   stevel 		_rename(old_system, Local_System, Lp_Requests, NULL);
    205     0   stevel 
    206     0   stevel 		Unlink(Lp_Temp);
    207     0   stevel 	}
    208     0   stevel 	Free(real_dir);
    209     0   stevel }
    210     0   stevel 
    211     0   stevel 
    212     0   stevel /**
    213     0   stevel  ** proto()
    214     0   stevel  **/
    215     0   stevel 
    216     0   stevel static void
    217     0   stevel proto(int type, int rm_ok, ...)
    218     0   stevel {
    219     0   stevel 	va_list			ap;
    220     0   stevel 
    221     0   stevel 	char			*path,
    222     0   stevel 				*symbolic;
    223     0   stevel 
    224     0   stevel 	int			exist,
    225     0   stevel 				err;
    226     0   stevel 
    227     0   stevel 	mode_t			mode;
    228     0   stevel 
    229     0   stevel 	uid_t			uid;
    230     0   stevel 
    231     0   stevel 	gid_t			gid;
    232     0   stevel 
    233     0   stevel 	struct stat		stbuf;
    234     0   stevel 
    235     0   stevel 
    236   320  ceastha 	va_start(ap, rm_ok);
    237     0   stevel 
    238     0   stevel 	if ((err = va_makepath(&ap, &path)) < 0)
    239     0   stevel 		fail ("\"%s\" is a truncated name!\n", path);
    240     0   stevel 
    241     0   stevel 	exist = (stat(path, &stbuf) == 0);
    242     0   stevel 
    243     0   stevel 	switch (type) {
    244     0   stevel 
    245     0   stevel 	case S:
    246     0   stevel 		if (!exist)
    247     0   stevel 			fail ("%s is missing!\n", path);
    248     0   stevel 		if ((err = va_makepath(&ap, &symbolic)) < 0)
    249     0   stevel 			fail ("\"%s\" is a truncated name!\n", symbolic);
    250     0   stevel 		Symlink (path, symbolic);
    251     0   stevel 		Free (symbolic);
    252     0   stevel 		Free (path);
    253     0   stevel 		return;
    254     0   stevel 
    255     0   stevel 	case D:
    256   871   casper 		if (exist && !S_ISDIR(stbuf.st_mode)) {
    257     0   stevel 			if (!rm_ok)
    258     0   stevel 				fail ("%s is not a directory!\n", path);
    259     0   stevel 			else {
    260     0   stevel 				Unlink (path);
    261     0   stevel 				exist = 0;
    262     0   stevel 			}
    263   871   casper 		}
    264     0   stevel 		if (!exist)
    265     0   stevel 			Mkdir (path, 0);
    266     0   stevel 		break;
    267     0   stevel 
    268     0   stevel 	case F:
    269   871   casper 		if (exist && !S_ISREG(stbuf.st_mode)) {
    270     0   stevel 			if (!rm_ok)
    271     0   stevel 				fail ("%s is not a file!\n", path);
    272     0   stevel 			else {
    273     0   stevel 				Unlink (path);
    274     0   stevel 				exist = 0;
    275     0   stevel 			}
    276   871   casper 		}
    277     0   stevel 		if (!exist)
    278     0   stevel 			Close(Creat(path, 0));
    279     0   stevel 		break;
    280     0   stevel 
    281     0   stevel 	case P:
    282     0   stevel 		/*
    283     0   stevel 		 * Either a pipe or a file.
    284     0   stevel 		 */
    285   871   casper 		if (exist &&
    286   871   casper 		    !S_ISREG(stbuf.st_mode) && !S_ISFIFO(stbuf.st_mode)) {
    287     0   stevel 			if (!rm_ok)
    288     0   stevel 				fail ("%s is not a file or pipe!\n", path);
    289     0   stevel 			else {
    290     0   stevel 				Unlink (path);
    291     0   stevel 				exist = 0;
    292     0   stevel 			}
    293   871   casper 		}
    294     0   stevel 		if (!exist)
    295     0   stevel 			Close(Creat(path, 0));
    296     0   stevel 		break;
    297     0   stevel 
    298     0   stevel 	}
    299     0   stevel 
    300     0   stevel 	mode = va_arg(ap, mode_t);
    301     0   stevel 	uid = va_arg(ap, uid_t);
    302     0   stevel 	gid = va_arg(ap, gid_t);
    303   547   jacobs 	(void) chownmod(path, uid, gid, mode);
    304     0   stevel 
    305     0   stevel 	Free (path);
    306     0   stevel 	return;
    307     0   stevel }
    308     0   stevel 
    309     0   stevel /*
    310     0   stevel  * va_makepath()
    311     0   stevel  *
    312     0   stevel  * Takes a variable length list of path components and attempts to string them
    313     0   stevel  * together into a path.  It returns a heap-allocated string via the output
    314     0   stevel  * parameter 'ret', and returns an integer success value: < 0 indicates failure,
    315     0   stevel  * 0 indicates success.  Note that 'ret' will never be NULL (unless the system
    316     0   stevel  * is so overloaded that it can't allocate a single byte), and should always be
    317     0   stevel  * free()d.
    318     0   stevel  */
    319     0   stevel static int
    320     0   stevel va_makepath (va_list *pap, char **ret)
    321     0   stevel {
    322     0   stevel 	char			*component;
    323     0   stevel 	char 			buf[MAXPATHLEN];
    324     0   stevel 	int			buflen;
    325     0   stevel 
    326     0   stevel 	memset(buf, NULL, sizeof (buf));
    327     0   stevel 	while ((component = va_arg((*pap), char *)) != NULL) {
    328     0   stevel 		if (strlcat(buf, component, sizeof (buf)) >= sizeof (buf) ||
    329     0   stevel 			strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
    330     0   stevel 			if ((*ret = strdup(buf)) == NULL)
    331     0   stevel 				*ret = strdup("");
    332     0   stevel 			return (-1);
    333     0   stevel 		}
    334     0   stevel 	}
    335     0   stevel 
    336     0   stevel 	/* remove the trailing slash */
    337     0   stevel 	buflen = strlen(buf);
    338     0   stevel 	if ((buflen > 1) && (buf[buflen - 1] == '/')) {
    339     0   stevel 		buf[buflen - 1] = '\0';
    340     0   stevel 	}
    341     0   stevel 
    342     0   stevel 	if ((*ret = strdup(buf)) == NULL) {
    343     0   stevel 		*ret = strdup("");
    344     0   stevel 		return (-1);
    345     0   stevel 	}
    346     0   stevel 	return (0);
    347     0   stevel }
    348     0   stevel 
    349     0   stevel /**
    350     0   stevel  ** _rename()
    351     0   stevel  **/
    352     0   stevel 
    353     0   stevel static void
    354     0   stevel _rename(char *old_system, char *new_system, ...)
    355     0   stevel {
    356     0   stevel 	va_list			ap;
    357     0   stevel 
    358     0   stevel 	char *			prefix;
    359     0   stevel 	char *			old;
    360     0   stevel 	char *			new;
    361     0   stevel 	int			err;
    362     0   stevel 
    363     0   stevel 
    364     0   stevel 	va_start (ap, new_system);
    365     0   stevel 	if ((err = va_makepath(&ap, &prefix)) < 0)
    366     0   stevel 		fail (
    367     0   stevel 			"Rename failed; prefix \"%s\" is a truncated name.\n",
    368     0   stevel 			prefix
    369     0   stevel 		);
    370     0   stevel 	va_end (ap);
    371     0   stevel 
    372     0   stevel 	old = makepath(prefix, old_system, (char *)0);
    373     0   stevel 	new = makepath(prefix, new_system, (char *)0);
    374     0   stevel 
    375     0   stevel 	if (Rename(old, new) == 0)
    376     0   stevel 		note ("Renamed %s to %s.\n", old, new);
    377     0   stevel 	else if (errno == EEXIST)
    378     0   stevel 		note (
    379     0   stevel 			"Rename of %s to %s failed because %s exists.\n",
    380     0   stevel 			old,
    381     0   stevel 			new,
    382     0   stevel 			new
    383     0   stevel 		);
    384     0   stevel 	else
    385     0   stevel 		fail (
    386     0   stevel 			"Rename of %s to %s failed (%s).\n",
    387     0   stevel 			old,
    388     0   stevel 			new,
    389     0   stevel 			PERROR
    390     0   stevel 		);
    391     0   stevel 
    392     0   stevel 	Free (new);
    393     0   stevel 	Free (old);
    394     0   stevel 	Free (prefix);
    395     0   stevel 
    396     0   stevel 	return;
    397     0   stevel }
    398