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