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
putalert(char * parent,char * name,FALERT * alertp)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 *
getalert(char * parent,char * name)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
delalert(char * parent,char * name)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
envlist(int fd,char ** list)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
printalert(FILE * fp,FALERT * alertp,int isfault)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