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