1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.17 */ 32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ 33 34 #include "stdio.h" 35 #include "string.h" 36 #include "errno.h" 37 #include "limits.h" 38 #include "unistd.h" 39 40 #include "lp.h" 41 42 extern char **environ; 43 44 static void envlist(int, char **); 45 46 /* 47 * We recognize the following key phrases in the alert prototype 48 * file, and replace them with appropriate values. 49 */ 50 #define NALRT_KEYS 7 51 # define ALRT_ENV 0 52 # define ALRT_PWD 1 53 # define ALRT_ULIMIT 2 54 # define ALRT_UMASK 3 55 # define ALRT_INTERVAL 4 56 # define ALRT_CMD 5 57 # define ALRT_USER 6 58 59 static struct { 60 char *v; 61 short len; 62 } shell_keys[NALRT_KEYS] = { 63 #define ENTRY(X) X, sizeof(X)-1 64 ENTRY("-ENVIRONMENT-"), 65 ENTRY("-PWD-"), 66 ENTRY("-ULIMIT-"), 67 ENTRY("-UMASK-"), 68 ENTRY("-INTERVAL-"), 69 ENTRY("-CMD-"), 70 ENTRY("-USER-"), 71 }; 72 73 /* 74 * These are used to bracket the administrator's command, so that 75 * we can find it easily. We're out of luck if the administrator 76 * includes an identical phrase in his or her command. 77 */ 78 #define ALRT_CMDSTART "## YOUR COMMAND STARTS HERE -- DON'T TOUCH ABOVE!!" 79 #define ALRT_CMDEND "## YOUR COMMAND ENDS HERE -- DON'T TOUCH BELOW!!" 80 81 /** 82 ** putalert() - WRITE ALERT TO FILES 83 **/ 84 85 int 86 putalert(char *parent, char *name, FALERT *alertp) 87 { 88 char *path, 89 cur_dir[PATH_MAX + 1], 90 buf[BUFSIZ]; 91 92 int cur_umask; 93 94 int fdout, fdin; 95 96 97 if (!parent || !*parent || !name || !*name) { 98 errno = EINVAL; 99 return (-1); 100 } 101 102 if (!alertp->shcmd) { 103 errno = EINVAL; 104 return (-1); 105 } 106 107 if (STREQU(alertp->shcmd, NAME_NONE)) 108 return (delalert(parent, name)); 109 110 /* 111 * See if the form/printer/print-wheel exists. 112 */ 113 114 if (!(path = makepath(parent, name, (char *)0))) 115 return (-1); 116 117 if (Access(path, F_OK) == -1) { 118 if (errno == ENOENT) 119 errno = ENOTDIR; /* not quite, but what else? */ 120 Free (path); 121 return (-1); 122 } 123 Free (path); 124 125 /* 126 * First, the shell command file. 127 */ 128 129 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 130 return (-1); 131 132 if ((fdout = open_locked(path, "w", MODE_NOEXEC)) < 0) { 133 Free (path); 134 return (-1); 135 } 136 Free (path); 137 138 /* 139 * We use a prototype file to build the shell command, 140 * so that the alerts are easily customized. The shell 141 * is expected to handle repeat alerts and failed alerts, 142 * because the Spooler doesn't. Also, the Spooler runs 143 * each alert with the UID and GID of the administrator 144 * who defined the alert. Otherwise, anything goes. 145 */ 146 147 if (!Lp_Bin) { 148 getpaths (); 149 if (!Lp_Bin) 150 return (-1); 151 } 152 if (!(path = makepath(Lp_Bin, ALERTPROTOFILE, (char *)0))) 153 return (-1); 154 155 if ((fdin = open_locked(path, "r", 0)) < 0) { 156 Free (path); 157 return (-1); 158 } 159 Free (path); 160 161 errno = 0; 162 while (fdgets(buf, BUFSIZ, fdin)) { 163 int key; 164 char *cp, 165 *dash; 166 167 cp = buf; 168 while ((dash = strchr(cp, '-'))) { 169 170 *dash = 0; 171 fdputs (cp, fdout); 172 *(cp = dash) = '-'; 173 174 for (key = 0; key < NALRT_KEYS; key++) 175 if (STRNEQU( 176 cp, 177 shell_keys[key].v, 178 shell_keys[key].len 179 )) { 180 register char *newline = 181 (cp != buf)? "\n" : ""; 182 183 cp += shell_keys[key].len; 184 185 switch (key) { 186 187 case ALRT_ENV: 188 fdprintf(fdout, newline); 189 envlist(fdout, environ); 190 break; 191 192 case ALRT_PWD: 193 getcwd (cur_dir, PATH_MAX); 194 fdprintf (fdout, "%s", cur_dir); 195 break; 196 197 case ALRT_ULIMIT: 198 fdprintf (fdout, "%ld", ulimit(1, (long)0)); 199 break; 200 201 case ALRT_UMASK: 202 umask (cur_umask = umask(0)); 203 fdprintf (fdout, "%03o", cur_umask); 204 break; 205 206 case ALRT_INTERVAL: 207 fdprintf(fdout, "%ld", (long)alertp->W); 208 break; 209 210 case ALRT_CMD: 211 fdprintf(fdout, newline); 212 fdprintf(fdout, "%s\n", ALRT_CMDSTART); 213 fdprintf(fdout, "%s\n", alertp->shcmd); 214 fdprintf(fdout, "%s\n", ALRT_CMDEND); 215 break; 216 217 case ALRT_USER: 218 fdprintf(fdout, "%s", getname()); 219 break; 220 221 } 222 223 break; 224 } 225 if (key >= NALRT_KEYS) 226 fdputc(*cp++, fdout); 227 228 } 229 fdputs(cp, fdout); 230 231 } 232 if (errno != 0) { 233 int save_errno = errno; 234 235 close(fdin); 236 close(fdout); 237 errno = save_errno; 238 return (-1); 239 } 240 close(fdin); 241 close(fdout); 242 243 /* 244 * Next, the variables file. 245 */ 246 247 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 248 return (-1); 249 250 if ((fdout = open_locked(path, "w", MODE_NOREAD)) < 0) { 251 Free (path); 252 return (-1); 253 } 254 Free (path); 255 256 fdprintf(fdout, "%d\n", alertp->Q > 0? alertp->Q : 1); 257 fdprintf(fdout, "%d\n", alertp->W >= 0? alertp->W : 0); 258 259 close(fdout); 260 261 return (0); 262 } 263 264 /** 265 ** getalert() - EXTRACT ALERT FROM FILES 266 **/ 267 268 FALERT * 269 getalert(char *parent, char *name) 270 { 271 int fd; 272 char *tmp; 273 static FALERT alert; 274 register char *path; 275 char buf[BUFSIZ]; 276 int len; 277 278 if (!parent || !*parent || !name || !*name) { 279 errno = EINVAL; 280 return (0); 281 } 282 283 /* 284 * See if the form/printer/print-wheel exists. 285 */ 286 287 if (!(path = makepath(parent, name, (char *)0))) 288 return (0); 289 290 if (Access(path, F_OK) == -1) { 291 if (errno == ENOENT) 292 errno = ENOTDIR; /* not quite, but what else? */ 293 Free (path); 294 return (0); 295 } 296 Free (path); 297 298 /* 299 * First, the shell command file. 300 */ 301 302 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 303 return (0); 304 305 if ((fd = open_locked(path, "r", 0)) < 0) { 306 Free (path); 307 return (0); 308 } 309 Free (path); 310 311 /* 312 * Skip over environment setting stuff, while loop, etc., 313 * to find the beginning of the command. 314 */ 315 errno = 0; 316 while ((tmp = fdgets(buf, BUFSIZ, fd)) && 317 !STRNEQU(buf, ALRT_CMDSTART, sizeof(ALRT_CMDSTART)-1)) 318 ; 319 if ((tmp == NULL) || (errno != 0)) { 320 int save_errno = errno; 321 322 close(fd); 323 errno = save_errno; 324 return (0); 325 } 326 327 alert.shcmd = sop_up_rest(fd, ALRT_CMDEND); 328 329 close(fd); 330 331 if (!alert.shcmd) 332 return (0); 333 334 /* 335 * Drop terminating newline. 336 */ 337 if (alert.shcmd[(len = strlen(alert.shcmd)) - 1] == '\n') 338 alert.shcmd[len - 1] = 0; 339 340 341 /* 342 * Next, the variables file. 343 */ 344 345 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 346 return (0); 347 348 if ((fd = open_locked(path, "r", 0)) < 0) { 349 Free (path); 350 return (0); 351 } 352 Free (path); 353 354 errno = 0; 355 (void)fdgets (buf, BUFSIZ, fd); 356 if (errno != 0) { 357 int save_errno = errno; 358 359 close(fd); 360 errno = save_errno; 361 return (0); 362 } 363 alert.Q = atoi(buf); 364 365 (void)fdgets (buf, BUFSIZ, fd); 366 if (errno != 0) { 367 int save_errno = errno; 368 369 close(fd); 370 errno = save_errno; 371 return (0); 372 } 373 alert.W = atoi(buf); 374 375 close(fd); 376 377 return (&alert); 378 } 379 380 /** 381 ** delalert() - DELETE ALERT FILES 382 **/ 383 384 int 385 delalert(char *parent, char *name) 386 { 387 char *path; 388 389 390 if (!parent || !*parent || !name || !*name) { 391 errno = EINVAL; 392 return (-1); 393 } 394 395 /* 396 * See if the form/printer/print-wheel exists. 397 */ 398 399 if (!(path = makepath(parent, name, (char *)0))) 400 return (-1); 401 402 if (Access(path, F_OK) == -1) { 403 if (errno == ENOENT) 404 errno = ENOTDIR; /* not quite, but what else? */ 405 Free (path); 406 return (-1); 407 } 408 Free (path); 409 410 /* 411 * Remove the two files. 412 */ 413 414 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 415 return (-1); 416 if (rmfile(path) == -1) { 417 Free (path); 418 return (-1); 419 } 420 Free (path); 421 422 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 423 return (-1); 424 if (rmfile(path) == -1) { 425 Free (path); 426 return (-1); 427 } 428 Free (path); 429 430 return (0); 431 } 432 433 /** 434 ** envlist() - PRINT OUT ENVIRONMENT LIST SAFELY 435 **/ 436 437 static void 438 envlist(int fd, char **list) 439 { 440 register char *env, 441 *value; 442 443 if (!list || !*list) 444 return; 445 446 while ((env = *list++)) { 447 if (!(value = strchr(env, '='))) 448 continue; 449 *value++ = 0; 450 if (!strchr(value, '\'')) 451 fdprintf(fd, (char *)gettext("export %s; %s='%s'\n"), 452 env, env, value); 453 *--value = '='; 454 } 455 } 456 457 /* 458 * printalert() - PRINT ALERT DESCRIPTION 459 * 460 * This is not used in the scheduler, so we don't need to switch to using 461 * file descriptors for scalability. 462 */ 463 464 void 465 printalert(FILE *fp, FALERT *alertp, int isfault) 466 { 467 if (!alertp->shcmd) { 468 if (isfault) 469 (void)fprintf (fp, (char *)gettext("On fault: no alert\n")); 470 else 471 (void)fprintf (fp, (char *)gettext("No alert\n")); 472 473 } else { 474 register char *copy = Strdup(alertp->shcmd), 475 *cp; 476 477 if (isfault) 478 (void)fprintf (fp, (char *)gettext("On fault: ")); 479 else 480 if (alertp->Q > 1) 481 (void)fprintf ( 482 fp, 483 (char *)gettext("When %d are queued: "), 484 alertp->Q 485 ); 486 else 487 (void)fprintf (fp, (char *)gettext("Upon any being queued: ")); 488 489 if (copy && (cp = strchr(copy, ' '))) 490 while (*cp == ' ') 491 *cp++ = 0; 492 493 if ( 494 copy 495 && syn_name(cp) 496 && ( 497 STREQU(copy, NAME_WRITE) 498 || STREQU(copy, NAME_MAIL) 499 ) 500 ) 501 (void)fprintf (fp, "%s to %s ", copy, cp); 502 else 503 (void)fprintf (fp, (char *)gettext("alert with \"%s\" "), alertp->shcmd); 504 505 if (alertp->W > 0) 506 (void)fprintf (fp, (char *)gettext("every %d minutes\n"), alertp->W); 507 else 508 (void)fprintf (fp, (char *)gettext("once\n")); 509 510 Free (copy); 511 } 512 return; 513 } 514