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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #pragma ident "%Z%%M% %I% %E% SMI"
30
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <signal.h>
41 #include <unistd.h>
42 #include <sac.h>
43 #include <spawn.h>
44 #include "misc.h"
45 #include "structs.h"
46 #include "adm.h"
47 #include "extern.h"
48
49
50 /*
51 * functions
52 */
53
54 char *pflags();
55 char *getfield();
56 void add_pm();
57 void cleandirs();
58 void rem_pm();
59 void start_pm();
60 void kill_pm();
61 void enable_pm();
62 void disable_pm();
63 void list_pms();
64 void read_db();
65 void sendcmd();
66 void checkresp();
67 void single_print();
68 void catch();
69 void usage();
70 static int invoke_rm(char *);
71
72 # define START 0x1 /* -s seen */
73 # define KILL 0x2 /* -k seen */
74 # define ENABLE 0x4 /* -e seen */
75 # define DISABLE 0x8 /* -d seen */
76 # define PLIST 0x10 /* -l seen */
77 # define LIST 0x20 /* -L seen */
78 # define DBREAD 0x40 /* -x seen */
79 # define CONFIG 0x80 /* -G seen */
80 # define PCONFIG 0x100 /* -g seen */
81 # define ADD 0x200 /* -a or other required options seen */
82 # define REMOVE 0x400 /* -r seen */
83
84 /*
85 * common error messages
86 */
87
88 # define NOTPRIV "User not privileged for operation"
89 # define SACERR "Can not contact SAC"
90 # define BADINP "Embedded newlines not allowed"
91
92
93 int Saferrno; /* internal `errno' for exit */
94
95
96 /*
97 * main - scan args for sacadm and call appropriate handling code
98 */
99
100 int
main(int argc,char * argv[])101 main(int argc, char *argv[])
102 {
103 int c; /* option letter */
104 uid_t uid; /* invoker's real uid */
105 int ret; /* return code from check_version */
106 int flag = 0; /* flag to record requested operations */
107 int errflg = 0; /* error indicator */
108 int version = -1; /* argument to -v */
109 int count = 0; /* argument to -n */
110 int badcnt = 0; /* count of bad args to -f */
111 int sawaflag = 0; /* true if actually saw -a */
112 int conflag = 0; /* true if output should be in condensed form */
113 long flags = 0; /* arguments to -f */
114 FILE *fp; /* scratch file pointer */
115 char *pmtag = NULL; /* argument to -p */
116 char *type = NULL; /* argument to -t */
117 char *script = NULL; /* argument to -z */
118 char *command = NULL; /* argument to -c */
119 char *comment = " "; /* argument to -y */
120 char badargs[BADFARGSIZE]; /* place to hold bad args to -f */
121 char buf[SIZE]; /* scratch buffer */
122 register char *p; /* scratch pointer */
123
124 if (argc == 1)
125 usage(argv[0]);
126 while ((c = getopt(argc, argv, "ac:def:GgkLln:p:rst:v:xy:z:")) != -1) {
127 switch (c) {
128 case 'a':
129 flag |= ADD;
130 sawaflag = 1;
131 break;
132 case 'c':
133 flag |= ADD;
134 if (strchr(optarg, '\n')) {
135 Saferrno = E_BADARGS;
136 error(BADINP);
137 }
138 command = optarg;
139 if (*command != '/') {
140 Saferrno = E_BADARGS;
141 error("command must be a full pathname");
142 }
143 break;
144 case 'd':
145 flag |= DISABLE;
146 break;
147 case 'e':
148 flag |= ENABLE;
149 break;
150 case 'f':
151 flag |= ADD;
152 while (*optarg) {
153 switch (*optarg++) {
154 case 'd':
155 flags |= D_FLAG;
156 break;
157 case 'x':
158 flags |= X_FLAG;
159 break;
160 default:
161 if (badcnt < (BADFARGSIZE -1))
162 badargs[badcnt++] = *(optarg - 1);
163 break;
164 }
165 }
166 /* null terminate just in case anything is there */
167 badargs[badcnt] = '\0';
168 break;
169 case 'G':
170 flag |= CONFIG;
171 break;
172 case 'g':
173 flag |= PCONFIG;
174 break;
175 case 'k':
176 flag |= KILL;
177 break;
178 case 'L':
179 flag |= LIST;
180 break;
181 case 'l':
182 flag |= PLIST;
183 break;
184 case 'n':
185 flag |= ADD;
186 count = atoi(optarg);
187 if (count < 0) {
188 Saferrno = E_BADARGS;
189 error("restart count can not be negative");
190 }
191 break;
192 case 'p':
193 pmtag = optarg;
194 if (strchr(optarg, '\n')) {
195 Saferrno = E_BADARGS;
196 error(BADINP);
197 }
198 if (strlen(pmtag) > PMTAGSIZE) {
199 pmtag[PMTAGSIZE] = '\0';
200 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag);
201 }
202 for (p = pmtag; *p; p++) {
203 if (!isalnum(*p)) {
204 Saferrno = E_BADARGS;
205 error("port monitor tag must be alphanumeric");
206 }
207 }
208 break;
209 case 'r':
210 flag |= REMOVE;
211 break;
212 case 's':
213 flag |= START;
214 break;
215 case 't':
216 type = optarg;
217 if (strchr(optarg, '\n')) {
218 Saferrno = E_BADARGS;
219 error(BADINP);
220 }
221 if (strlen(type) > PMTYPESIZE) {
222 type[PMTYPESIZE] = '\0';
223 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type);
224 }
225 for (p = type; *p; p++) {
226 if (!isalnum(*p)) {
227 Saferrno = E_BADARGS;
228 error("port monitor type must be alphanumeric");
229 }
230 }
231 break;
232 case 'v':
233 flag |= ADD;
234 version = atoi(optarg);
235 if (version < 0) {
236 Saferrno = E_BADARGS;
237 error("version number can not be negative");
238 }
239 break;
240 case 'x':
241 flag |= DBREAD;
242 break;
243 case 'y':
244 flag |= ADD;
245 if (strchr(optarg, '\n')) {
246 Saferrno = E_BADARGS;
247 error(BADINP);
248 }
249 comment = optarg;
250 break;
251 case 'z':
252 if (strchr(optarg, '\n')) {
253 Saferrno = E_BADARGS;
254 error(BADINP);
255 }
256 script = optarg;
257 break;
258 case '?':
259 errflg++;
260 }
261 }
262 if (errflg || (optind < argc))
263 usage(argv[0]);
264
265 if (badcnt) {
266 /* bad flags were given to -f */
267 Saferrno = E_BADARGS;
268 (void) sprintf(buf,
269 "Invalid request, %s are not valid arguments for \"-f\"",
270 badargs);
271 error(buf);
272 }
273
274 if ((ret = check_version(VERSION, SACTAB)) == 1) {
275 Saferrno = E_SAFERR;
276 error("_sactab version number is incorrect");
277 }
278 else if (ret == 2) {
279 (void) sprintf(buf, "could not open %s", SACTAB);
280 Saferrno = E_SYSERR;
281 error(buf);
282 }
283 else if (ret == 3) {
284 (void) sprintf(buf, "%s file is corrupt", SACTAB);
285 Saferrno = E_SAFERR;
286 error(buf);
287 }
288 uid = getuid();
289 switch (flag) {
290 case ADD:
291 if (uid) {
292 Saferrno = E_NOPRIV;
293 error(NOTPRIV);
294 }
295 if (!sawaflag || !pmtag || !type || !command || (version < 0))
296 usage(argv[0]);
297 add_pm(pmtag, type, command, version, flags, count, script, comment);
298 break;
299 case REMOVE:
300 if (uid) {
301 Saferrno = E_NOPRIV;
302 error(NOTPRIV);
303 }
304 if (!pmtag || type || script)
305 usage(argv[0]);
306 rem_pm(pmtag);
307 break;
308 case START:
309 if (uid) {
310 Saferrno = E_NOPRIV;
311 error(NOTPRIV);
312 }
313 if (!pmtag || type || script)
314 usage(argv[0]);
315 start_pm(pmtag);
316 break;
317 case KILL:
318 if (uid) {
319 Saferrno = E_NOPRIV;
320 error(NOTPRIV);
321 }
322 if (!pmtag || type || script)
323 usage(argv[0]);
324 kill_pm(pmtag);
325 break;
326 case ENABLE:
327 if (uid) {
328 Saferrno = E_NOPRIV;
329 error(NOTPRIV);
330 }
331 if (!pmtag || type || script)
332 usage(argv[0]);
333 enable_pm(pmtag);
334 break;
335 case DISABLE:
336 if (uid) {
337 Saferrno = E_NOPRIV;
338 error(NOTPRIV);
339 }
340 if (!pmtag || type || script)
341 usage(argv[0]);
342 disable_pm(pmtag);
343 break;
344 case LIST:
345 conflag = 1;
346 /* fall through */
347 case PLIST:
348 if ((pmtag && type) || script)
349 usage(argv[0]);
350 list_pms(pmtag, type, conflag);
351 break;
352 case DBREAD:
353 if (uid) {
354 Saferrno = E_NOPRIV;
355 error(NOTPRIV);
356 }
357 if (type || script)
358 usage(argv[0]);
359 read_db(pmtag);
360 break;
361 case CONFIG:
362 if (script && uid) {
363 Saferrno = E_NOPRIV;
364 error(NOTPRIV);
365 }
366 if (type || pmtag)
367 usage(argv[0]);
368 (void) do_config(script, "_sysconfig");
369 break;
370 case PCONFIG:
371 if (script && uid) {
372 Saferrno = E_NOPRIV;
373 error(NOTPRIV);
374 }
375 if (!pmtag || type)
376 usage(argv[0]);
377 fp = fopen(SACTAB, "r");
378 if (fp == NULL) {
379 Saferrno = E_SYSERR;
380 error("Could not open _sactab");
381 }
382 if (!find_pm(fp, pmtag)) {
383 Saferrno = E_NOEXIST;
384 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
385 error(buf);
386 }
387 (void) fclose(fp);
388 (void) sprintf(buf, "%s/_config", pmtag);
389 (void) do_config(script, buf);
390 break;
391 default:
392 /* we only get here if more than one flag bit was set */
393 usage(argv[0]);
394 /* NOTREACHED */
395 }
396 quit();
397 /* NOTREACHED */
398 return (0);
399 }
400
401
402 /*
403 * usage - print out a usage message
404 *
405 * args: cmdname - the name command was invoked with
406 */
407
408 void
usage(cmdname)409 usage(cmdname)
410 char *cmdname;
411 {
412 (void) fprintf(stderr, "Usage:\t%s -a -p pmtag -t type -c cmd -v ver [ -f dx ] [ -n count ]\n", cmdname);
413 (void) fprintf(stderr, "\t\t[ -y comment ] [ -z script]\n");
414 (void) fprintf(stderr, "\t%s -r -p pmtag\n", cmdname);
415 (void) fprintf(stderr, "\t%s -s -p pmtag\n", cmdname);
416 (void) fprintf(stderr, "\t%s -k -p pmtag\n", cmdname);
417 (void) fprintf(stderr, "\t%s -e -p pmtag\n", cmdname);
418 (void) fprintf(stderr, "\t%s -d -p pmtag\n", cmdname);
419 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ]\n", cmdname);
420 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ]\n", cmdname);
421 (void) fprintf(stderr, "\t%s -g -p pmtag [ -z script ]\n", cmdname);
422 (void) fprintf(stderr, "\t%s -G [ -z script ]\n", cmdname);
423 (void) fprintf(stderr, "\t%s -x [ -p pmtag ]\n", cmdname);
424 Saferrno = E_BADARGS;
425 quit();
426 }
427
428
429 /*
430 * add_pm - add a port monitor entry
431 *
432 * args: tag - port monitor's tag
433 * type - port monitor's type
434 * command - command string to invoke port monitor
435 * version - version number of port monitor's pmtab
436 * flags - port monitor flags
437 * count - restart count
438 * script - port monitor's configuration script
439 * comment - comment describing port monitor
440 */
441
442 void
add_pm(tag,type,command,version,flags,count,script,comment)443 add_pm(tag, type, command, version, flags, count, script, comment)
444 char *tag;
445 char *type;
446 char *command;
447 int version;
448 long flags;
449 int count;
450 char *script;
451 char *comment;
452 {
453 FILE *fp; /* file pointer for _sactab */
454 int fd; /* scratch file descriptor */
455 struct stat statbuf; /* file status info */
456 char buf[SIZE]; /* scratch buffer */
457 char fname[SIZE]; /* scratch buffer for building names */
458 register int i; /* scratch variable */
459 int retval = 0; /* return value from invoke_rm() function */
460
461 fp = fopen(SACTAB, "r");
462 if (fp == NULL) {
463 Saferrno = E_SYSERR;
464 error("Could not open _sactab");
465 }
466 if (find_pm(fp, tag)) {
467 Saferrno = E_DUP;
468 (void) sprintf(buf, "Invalid request, %s already exists", tag);
469 error(buf);
470 }
471 (void) fclose(fp);
472
473 /*
474 * create the directories for it if needed and put in initial files
475 * (/etc/saf and /var/saf)
476 */
477
478 for (i = 0; i < 2; i++) {
479 /* i == 0 do /etc/saf i == 1 do /var/saf */
480 (void) sprintf(fname, "%s/%s", (i == 0 ) ? HOME : ALTHOME, tag);
481 if (access(fname, 0) == 0) {
482 /* something is there, find out what it is */
483 if (stat(fname, &statbuf) < 0) {
484 Saferrno = E_SYSERR;
485 (void) sprintf(buf, "could not stat <%s>", fname);
486 error(buf);
487 }
488 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
489 Saferrno = E_SYSERR;
490 (void) sprintf(buf, "<%s> exists and is not a directory", fname);
491 error(buf);
492 }
493 /* note: this removes the directory too */
494 if ((retval = invoke_rm(fname)) != 0) {
495 Saferrno = E_SYSERR;
496 if (snprintf(buf, sizeof (buf),
497 "could not remove files under <%s>",
498 fname) >= sizeof (buf)) {
499 snprintf(buf, sizeof (buf),
500 "tag too long");
501 }
502 error(buf);
503 }
504 }
505
506 /*
507 * create the directory
508 */
509
510 if (mkdir(fname, 0755) < 0) {
511 Saferrno = E_SYSERR;
512 (void) sprintf(buf, "could not create directory <%s>", fname);
513 cleandirs(tag);
514 error(buf);
515 }
516 }
517
518 /*
519 * put in the config script, if specified
520 */
521
522 if (script) {
523 (void) sprintf(fname, "%s/_config", tag);
524 if (do_config(script, fname)) {
525 cleandirs(tag);
526 /* do_config put out any messages */
527 quit();
528 }
529 }
530
531 /*
532 * create the communications pipe, but first make sure that the
533 * permissions we specify are what we get
534 */
535
536 (void) umask(0);
537 (void) sprintf(fname, "%s/%s/_pmpipe", HOME, tag);
538 if (mknod(fname, S_IFIFO | 0600, 0) < 0) {
539 Saferrno = E_SYSERR;
540 cleandirs(tag);
541 error("could not create communications pipe");
542 }
543
544 /*
545 * create the _pid file
546 */
547
548 (void) sprintf(fname, "%s/%s/_pid", HOME, tag);
549 if ((fd = creat(fname, 0644)) < 0) {
550 Saferrno = E_SYSERR;
551 cleandirs(tag);
552 error("could not create _pid file");
553 }
554 (void) close(fd);
555
556 /*
557 * create the _pmtab file
558 */
559
560 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tag);
561 if ((fd = creat(fname, 0644)) < 0) {
562 Saferrno = E_SYSERR;
563 cleandirs(tag);
564 error("could not create _pmtab file");
565 }
566 (void) sprintf(buf, "%s%d\n", VSTR, version);
567 if (write(fd, buf, (unsigned) strlen(buf)) != strlen(buf)) {
568 (void) close(fd);
569 (void) unlink(fname);
570 Saferrno = E_SYSERR;
571 cleandirs(tag);
572 error("error initializing _pmtab");
573 }
574 (void) close(fd);
575
576 /*
577 * isolate the command name, but remember it since strtok() trashes it
578 */
579
580 if (strlcpy(buf, command, sizeof (buf)) >= sizeof (buf)) {
581 Saferrno = E_SYSERR;
582 cleandirs(tag);
583 error("command string too long");
584 }
585
586 (void) strtok(command, " \t");
587
588 /*
589 * check out the command - let addition succeed if it doesn't exist (assume
590 * it will be added later); fail anything else
591 */
592
593 if (access(command, 0) == 0) {
594 if (stat(command, &statbuf) < 0) {
595 Saferrno = E_SYSERR;
596 (void) fprintf(stderr, "Could not stat <%s>\n", command);
597 cleandirs(tag);
598 quit();
599 }
600 if (!(statbuf.st_mode & 0111)) {
601 Saferrno = E_BADARGS;
602 (void) fprintf(stderr, "%s not executable\n", command);
603 cleandirs(tag);
604 quit();
605 }
606 if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
607 Saferrno = E_BADARGS;
608 (void) fprintf(stderr, "%s not a regular file\n", command);
609 cleandirs(tag);
610 quit();
611 }
612 }
613 else {
614 (void) fprintf(stderr, "warning - %s does not exist\n", command);
615 }
616
617 /*
618 * add the line
619 */
620
621 fp = fopen(SACTAB, "a");
622 if (fp == NULL) {
623 Saferrno = E_SYSERR;
624 cleandirs(tag);
625 error("Could not open _sactab");
626 }
627 (void) fprintf(fp, "%s:%s:%s:%d:%s\t#%s\n", tag, type,
628 (flags ? pflags(flags, FALSE) : ""), count, buf,
629 (comment ? comment : ""));
630 (void) fclose(fp);
631
632
633 /*
634 * tell the SAC to read _sactab if its there (i.e. single user)
635 */
636
637 if (sac_home())
638 read_db(NULL);
639 return;
640 }
641
642
643 /*
644 * cleandirs - remove anything that might have been created (i.e. failed
645 * addition. Saferrno is set elsewhere; this is strictly an attempt
646 * to clean up what mess we've left, so don't check to see if the
647 * cleanup worked.
648 *
649 * args: tag - tag of port monitor whose trees should be removed
650 */
651
652 void
cleandirs(tag)653 cleandirs(tag)
654 char *tag;
655 {
656 char buf[SIZE]; /* scratch buffer */
657
658 /* note: this removes the directory too, first zap /etc/saf/<tag> */
659 if (snprintf(buf, sizeof (buf), "%s/%s", HOME, tag) >= sizeof (buf))
660 (void) fprintf(stderr, "tag too long\n");
661 else
662 (void) invoke_rm(buf);
663
664 /* now remove /var/saf/<tag> */
665 if (snprintf(buf, sizeof (buf), "%s/%s", ALTHOME, tag) >= sizeof (buf))
666 (void) fprintf(stderr, "tag too long\n");
667 else
668 (void) rmdir(buf);
669 }
670
671
672 /*
673 * rem_pm - remove a port monitor
674 *
675 * args: tag - tag of port monitor to be removed
676 */
677
678 void
rem_pm(tag)679 rem_pm(tag)
680 char *tag;
681 {
682 FILE *fp; /* file pointer for _sactab */
683 FILE *tfp; /* file pointer for temp file */
684 int line; /* line number entry is on */
685 char *tname; /* temp file name */
686 char buf[SIZE]; /* scratch buffer */
687
688 fp = fopen(SACTAB, "r");
689 if (fp == NULL) {
690 Saferrno = E_SYSERR;
691 error("Could not open _sactab");
692 }
693 if ((line = find_pm(fp, tag)) == 0) {
694 Saferrno = E_NOEXIST;
695 (void) sprintf(buf, "Invalid request, %s does not exist", tag);
696 error(buf);
697 }
698 tname = make_tempname("_sactab");
699 tfp = open_temp(tname);
700 if (line != 1) {
701 if (copy_file(fp, tfp, 1, line - 1)) {
702 (void) unlink(tname);
703 Saferrno = E_SYSERR;
704 error("error accessing temp file");
705 }
706 }
707 if (copy_file(fp, tfp, line + 1, -1)) {
708 (void) unlink(tname);
709 Saferrno = E_SYSERR;
710 error("error accessing temp file");
711 }
712 (void) fclose(fp);
713 if (fclose(tfp) == EOF) {
714 (void) unlink(tname);
715 Saferrno = E_SYSERR;
716 error("error closing tempfile");
717 }
718 /* note - replace only returns if successful */
719 replace("_sactab", tname);
720
721 /*
722 * tell the SAC to read _sactab if its there (i.e. single user)
723 */
724
725 if (sac_home())
726 read_db(NULL);
727 return;
728 }
729
730
731 /*
732 * start_pm - start a particular port monitor
733 *
734 * args: tag - tag of port monitor to be started
735 */
736
737 void
start_pm(tag)738 start_pm(tag)
739 char *tag;
740 {
741 struct admcmd cmd; /* command structure */
742 register struct admcmd *ap = &cmd; /* and a pointer to it */
743
744 ap->ac_mtype = AC_START;
745 (void) strcpy(ap->ac_tag, tag);
746 ap->ac_pid = getpid();
747 sendcmd(ap, NULL, tag);
748 return;
749 }
750
751
752 /*
753 * kill_pm - stop a particular port monitor
754 *
755 * args: tag - tag of port monitor to be stopped
756 */
757
758 void
kill_pm(tag)759 kill_pm(tag)
760 char *tag;
761 {
762 struct admcmd cmd; /* command structure */
763 register struct admcmd *ap = &cmd; /* and a pointer to it */
764
765 ap->ac_mtype = AC_KILL;
766 (void) strcpy(ap->ac_tag, tag);
767 ap->ac_pid = getpid();
768 sendcmd(ap, NULL, tag);
769 return;
770 }
771
772
773 /*
774 * enable_pm - enable a particular port monitor
775 *
776 * args: tag - tag of port monitor to be enabled
777 */
778
779 void
enable_pm(tag)780 enable_pm(tag)
781 char *tag;
782 {
783 struct admcmd cmd; /* command structure */
784 register struct admcmd *ap = &cmd; /* and a pointer to it */
785
786 ap->ac_mtype = AC_ENABLE;
787 (void) strcpy(ap->ac_tag, tag);
788 ap->ac_pid = getpid();
789 sendcmd(ap, NULL, tag);
790 return;
791 }
792
793
794 /*
795 * disable_pm - disable a particular port monitor
796 *
797 * args: tag - tag of port monitor to be disabled
798 */
799
800 void
disable_pm(tag)801 disable_pm(tag)
802 char *tag;
803 {
804 struct admcmd cmd; /* command structure */
805 register struct admcmd *ap = &cmd; /* and a pointer to it */
806
807 ap->ac_mtype = AC_DISABLE;
808 (void) strcpy(ap->ac_tag, tag);
809 ap->ac_pid = getpid();
810 sendcmd(ap, NULL, tag);
811 return;
812 }
813
814
815 /*
816 * read_db - tell SAC or a port monitor to read its administrative file.
817 *
818 * args: tag - tag of port monitor that should read its administrative
819 * file. If NULL, it means SAC should.
820 */
821
822 void
read_db(tag)823 read_db(tag)
824 char *tag;
825 {
826 struct admcmd cmd; /* command structure */
827 register struct admcmd *ap = &cmd; /* and a pointer to it */
828
829 ap->ac_mtype = (tag) ? AC_PMREAD : AC_SACREAD;
830 if (tag)
831 (void) strcpy(ap->ac_tag, tag);
832 ap->ac_pid = getpid();
833 sendcmd(ap, NULL, tag);
834 return;
835 }
836
837
838 /*
839 * list_pms - request information about port monitors from SAC and output
840 * requested info
841 *
842 * args: pmtag - tag of port monitor to be listed (may be null)
843 * pmtype - type of port monitors to be listed (may be null)
844 * oflag - true if output should be easily parseable
845 */
846
847 void
list_pms(pmtag,pmtype,oflag)848 list_pms(pmtag, pmtype, oflag)
849 char *pmtag;
850 char *pmtype;
851 int oflag;
852 {
853 struct admcmd acmd; /* command structure */
854 register struct admcmd *ap = &acmd; /* and a pointer to it */
855 int nprint = 0; /* count # of PMs printed */
856 char *p; /* scratch pointer */
857 char *tag; /* returned tag */
858 char *type; /* returned type */
859 char *flags; /* returned flags */
860 char *rsmax; /* returned restart count */
861 char *state; /* returned state */
862 char *cmd; /* returned command string */
863 char *comment; /* returned comment string */
864
865 /*
866 * if sac isn't there (single user), provide info direct from _sactab
867 * note: when this routine returns, the process exits, so there is no
868 * need to free up any memory
869 */
870
871 p = NULL;
872 if (sac_home()) {
873 ap->ac_mtype = AC_STATUS;
874 ap->ac_tag[0] = '\0';
875 ap->ac_pid = getpid();
876 sendcmd(ap, &p, NULL);
877 }
878 else {
879 single_print(&p);
880 }
881
882 /*
883 * SAC sends back info in condensed form, we have to separate it out
884 * fields come in ':' separated, records are separated by newlines
885 */
886
887 while (p && *p) {
888 tag = getfield(&p, ':'); /* PM tag */
889 type = getfield(&p, ':'); /* PM type */
890 flags = getfield(&p, ':'); /* flags */
891 rsmax = getfield(&p, ':'); /* restart count */
892 state = pstate((unchar) atoi(getfield(&p, ':'))); /* state in nice output format */
893 cmd = getfield(&p, ':'); /* command */
894 comment = getfield(&p, '\n'); /* comment */
895
896
897 /*
898 * print out if no selectors specified, else check to see if
899 * a selector matched
900 */
901
902 if ((!pmtag && !pmtype) || (pmtag && !strcmp(pmtag, tag)) || (pmtype && !strcmp(pmtype, type))) {
903 if (oflag) {
904 (void) printf("%s:%s:%s:%s:%s:%s#%s\n", tag, type, pflags(atol(flags), FALSE),
905 rsmax, state, cmd, comment);
906 }
907 else {
908 if (nprint == 0) {
909 (void) printf("PMTAG PMTYPE FLGS RCNT STATUS COMMAND\n");
910 }
911 (void) printf("%-14s %-14s %-4s %-4s %-10s %s #%s\n", tag, type, pflags(atol(flags), TRUE),
912 rsmax, state, cmd, comment);
913 }
914 nprint++;
915 }
916 }
917 /*
918 * if we didn't find any valid ones, indicate an error (note: 1 and
919 * only 1 of the if statements should be true)
920 */
921 if (nprint == 0) {
922 if (pmtype)
923 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtype);
924 else if (pmtag)
925 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtag);
926 else if (!pmtag && !pmtype)
927 (void) fprintf(stderr, "No port monitors defined\n");
928 Saferrno = E_NOEXIST;
929 }
930 return;
931 }
932
933
934 /*
935 * getfield - retrieve and return a field from the sac "status" string (input
936 * argument is modified to point to next field as a side-effect)
937 *
938 * args: p - address of remaining portion of string
939 * sepchar - field terminator character
940 */
941
942 char *
getfield(p,sepchar)943 getfield(p, sepchar)
944 char **p;
945 char sepchar;
946 {
947 char *savep; /* for saving argument */
948
949 savep = *p;
950 *p = strchr(*p, sepchar);
951 if (*p == NULL) {
952 Saferrno = E_SAFERR;
953 (void) fprintf(stderr, "Improper message from SAC\n");
954 return(NULL);
955 }
956 **p = '\0';
957 (*p)++;
958 return(savep);
959 }
960
961
962 /*
963 * single_print - print out _sactab if sac not at home (should only happen
964 * in single user mode
965 *
966 * args: p - address of pointer where formatted data should be
967 * placed (space allocated here)
968 */
969
970 void
single_print(p)971 single_print(p)
972 char **p;
973 {
974 FILE *fp; /* file pointer for _sactab */
975 struct stat statbuf; /* file status info */
976 register char *tp1; /* scratch pointer */
977 register char *tp2; /* scratch pointer */
978 struct sactab stab; /* place to hold parsed info */
979 register struct sactab *sp = &stab; /* and a pointer to it */
980 char buf[SIZE]; /* scratch buffer */
981
982 fp = fopen(SACTAB, "r");
983 if (fp == NULL) {
984 Saferrno = E_SYSERR;
985 error("Could not open _sactab");
986 }
987 if (fstat(fileno(fp), &statbuf) < 0) {
988 Saferrno = E_SYSERR;
989 error("could not stat _sactab");
990 }
991
992 /*
993 * allocate space to build return string, twice file size should be more
994 * than enough (and make sure it's zero'ed out)
995 */
996
997 tp1 = calloc(2 * statbuf.st_size, sizeof(char));
998 if (tp1 == NULL) {
999 Saferrno = E_SYSERR;
1000 error("could not allocate storage");
1001 }
1002
1003 /*
1004 * read the file and build the string
1005 */
1006
1007 while (fgets(buf, SIZE, fp)) {
1008 tp2 = trim(buf);
1009 if (*tp2 == '\0')
1010 continue;
1011 parse(tp2, &stab);
1012 (void) sprintf(buf, "%s:%s:%d:%d:%d:%s:%s\n", sp->sc_tag, sp->sc_type,
1013 sp->sc_flags, sp->sc_rsmax, SSTATE, sp->sc_cmd, sp->sc_comment);
1014 (void) strcat(tp1, buf);
1015 free(sp->sc_cmd);
1016 free(sp->sc_comment);
1017 }
1018 if (!feof(fp)) {
1019 Saferrno = E_SYSERR;
1020 error("error reading _sactab");
1021 }
1022 (void) fclose(fp);
1023
1024 /*
1025 * point at the just-built string
1026 */
1027
1028 *p = tp1;
1029 return;
1030 }
1031
1032
1033 /*
1034 * openpipe - open up command pipe to SAC
1035 */
1036
1037 int
openpipe()1038 openpipe()
1039 {
1040 int fd; /* file descriptor associated with command pipe */
1041
1042 fd = open(CMDPIPE, O_RDWR);
1043 if (fd < 0) {
1044 Saferrno = E_SYSERR;
1045 error(SACERR);
1046 }
1047
1048 /*
1049 * lock pipe to insure serial access, lock will disappear if process dies
1050 */
1051
1052 if (lockf(fd, F_LOCK, 0) < 0) {
1053 Saferrno = E_SYSERR;
1054 error("unable to lock command pipe");
1055 }
1056 return(fd);
1057 }
1058
1059
1060 /*
1061 * sendcmd - send a command to the SAC
1062 *
1063 * args: ap - pointer to command to send
1064 * info - pointer to return information from the SAC
1065 * tag - tag of port monitor to which the command applies (may
1066 * be NULL)
1067 */
1068
1069 void
sendcmd(ap,info,tag)1070 sendcmd(ap, info, tag)
1071 struct admcmd *ap;
1072 char **info;
1073 char *tag;
1074 {
1075 int fd; /* file descriptor of command pipe */
1076
1077 fd = openpipe();
1078 if (write(fd, ap, sizeof(struct admcmd)) < 0) {
1079 Saferrno = E_SYSERR;
1080 error(SACERR);
1081 }
1082 checkresp(fd, info, tag);
1083
1084 /*
1085 * unlock the command pipe - not really necessary since we're about to close
1086 */
1087
1088 (void) lockf(fd, F_ULOCK, 0);
1089 (void) close(fd);
1090 return;
1091 }
1092
1093
1094 /*
1095 * checkresp - check the SAC's response to our command
1096 *
1097 * args: fd - file descriptor of command pipe
1098 * info - pointer to return and info send along by SAC
1099 * tag - tag of port monitor that the command had been
1100 * for, only used for error reporting
1101 */
1102
1103 void
checkresp(fd,info,tag)1104 checkresp(fd, info, tag)
1105 int fd;
1106 char **info;
1107 char *tag;
1108 {
1109 struct admack ack; /* acknowledgment struct */
1110 register struct admack *ak = &ack; /* and a pointer to it */
1111 pid_t pid; /* my pid */
1112 struct sigaction sigact; /* signal handler setup */
1113
1114 /*
1115 * make sure this ack is meant for me, put an alarm around the read
1116 * so we don't hang out forever.
1117 */
1118
1119 pid = getpid();
1120 sigact.sa_flags = 0;
1121 sigact.sa_handler = catch;
1122 (void) sigemptyset(&sigact.sa_mask);
1123 (void) sigaddset(&sigact.sa_mask, SIGALRM);
1124 (void) sigaction(SIGALRM, &sigact, NULL);
1125 (void) alarm(10);
1126 do {
1127 if (read(fd, ak, sizeof(ack)) != sizeof(ack)) {
1128 Saferrno = E_SACNOTRUN;
1129 error(SACERR);
1130 }
1131 } while (pid != ak->ak_pid);
1132 (void) alarm(0);
1133
1134 /*
1135 * check out what happened
1136 */
1137
1138 switch (ak->ak_resp) {
1139 case AK_ACK:
1140 /* everything was A-OK */
1141 if (info && ak->ak_size) {
1142 /* there is return info and a place to put it */
1143 if ((*info = malloc((unsigned) (ak->ak_size + 1))) == NULL) {
1144 Saferrno = E_SYSERR;
1145 error("could not allocate storage");
1146 }
1147 if (read(fd, *info, (unsigned) ak->ak_size) != ak->ak_size) {
1148 Saferrno = E_SYSERR;
1149 error(SACERR);
1150 }
1151 /* make sure "string" is null-terminated */
1152 (*info)[ak->ak_size] = '\0';
1153 }
1154 return;
1155 /* something went wrong - see what */
1156 case AK_PMRUN:
1157 Saferrno = E_PMRUN;
1158 (void) fprintf(stderr, "Port monitor, %s, is already running\n", tag);
1159 break;
1160 case AK_PMNOTRUN:
1161 Saferrno = E_PMNOTRUN;
1162 (void) fprintf(stderr, "Port monitor, %s, is not running\n", tag);
1163 break;
1164 case AK_NOPM:
1165 Saferrno = E_NOEXIST;
1166 (void) fprintf(stderr, "Invalid request, %s does not exist\n", tag);
1167 break;
1168 case AK_UNKNOWN:
1169 Saferrno = E_SAFERR;
1170 (void) fprintf(stderr, "Internal error - sent invalid command\n");
1171 break;
1172 case AK_NOCONTACT:
1173 Saferrno = E_SAFERR;
1174 (void) fprintf(stderr, "Could not contact %s\n", tag);
1175 break;
1176 case AK_PMLOCK:
1177 Saferrno = E_SAFERR;
1178 (void) fprintf(stderr, "Could not start %s - _pid file locked\n", tag);
1179 break;
1180 case AK_RECOVER:
1181 Saferrno = E_RECOVER;
1182 (void) fprintf(stderr, "Port monitor, %s, is in recovery\n", tag);
1183 break;
1184 case AK_REQFAIL:
1185 Saferrno = E_SAFERR;
1186 (void) fprintf(stderr, "This request could not be completed - see sac log file for details\n");
1187 break;
1188 default:
1189 Saferrno = E_SAFERR;
1190 (void) fprintf(stderr, "unknown response\n");
1191 break;
1192 }
1193 }
1194
1195
1196 /*
1197 * catch - catcher for SIGALRM, don't need to do anything
1198 */
1199
1200 void
catch()1201 catch()
1202 {
1203 }
1204
1205
1206 /*
1207 * pflags - put port monitor flags into intelligible form for output
1208 *
1209 * args: flags - binary representation of flags
1210 * dflag - true if a "-" should be returned if no flags
1211 */
1212
1213 char *
pflags(flags,dflag)1214 pflags(flags, dflag)
1215 long flags;
1216 int dflag;
1217 {
1218 register int i; /* scratch counter */
1219 static char buf[SIZE]; /* formatted flags */
1220
1221 if (flags == 0) {
1222 if (dflag)
1223 return("-");
1224 else
1225 return("");
1226 }
1227 i = 0;
1228 if (flags & D_FLAG) {
1229 buf[i++] = 'd';
1230 flags &= ~D_FLAG;
1231 }
1232 if (flags & X_FLAG) {
1233 buf[i++] = 'x';
1234 flags &= ~X_FLAG;
1235 }
1236 if (flags) {
1237 (void) fprintf(stderr, "Bad information from SAC\n");
1238 exit(1);
1239 }
1240 buf[i] = '\0';
1241 return(buf);
1242 }
1243
1244
1245 /*
1246 * sac_home - returns true is sac has a lock on its logfile, false
1247 * otherwise (useful to avoid errors for administrative actions in
1248 * single user mode)
1249 */
1250
1251 int
sac_home()1252 sac_home()
1253 {
1254 int fd; /* fd to sac logfile */
1255
1256 fd = open(LOGFILE, O_RDONLY);
1257 if (fd < 0) {
1258 fprintf(stderr, "warning - could not ascertain sac status\n");
1259 return(FALSE);
1260 }
1261 if (lockf(fd, F_TEST, 0) < 0) {
1262 /* everything is ok */
1263 (void) close(fd);
1264 return(TRUE);
1265 }
1266 else {
1267 /* no one home */
1268 (void) close(fd);
1269 return(FALSE);
1270 }
1271 }
1272
1273 /*
1274 * invoke_rm - deletes the argument directory and all its files/subdirectories
1275 */
1276 static int
invoke_rm(char * fname)1277 invoke_rm(char *fname)
1278 {
1279 pid_t cpid; /* process ID of the child process */
1280 int cstatus; /* status of child process */
1281 char *argvec[4];
1282
1283 argvec[0] = "rm";
1284 argvec[1] = "-rf";
1285 argvec[2] = fname;
1286 argvec[3] = NULL;
1287
1288 if (posix_spawn(&cpid, "/usr/bin/rm", NULL, NULL,
1289 (char *const *)argvec, NULL))
1290 return (-1);
1291 if (waitpid(cpid, &cstatus, 0) == -1)
1292 return (-1);
1293
1294 return ((WIFEXITED(cstatus) == 0) ? 99 : WEXITSTATUS(cstatus));
1295 }
1296