Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / saf / pmadm.c
blobf0eeb3e89df20e0751d866ec23cd75ea0211e0e7
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include "extern.h"
39 #include "misc.h"
40 #include <sac.h>
41 #include "structs.h"
43 #define ADD 0x1 /* -a or other required options seen */
44 #define REMOVE 0x2 /* -r seen */
45 #define ENABLE 0x4 /* -e seen */
46 #define DISABLE 0x8 /* -d seen */
47 #define PLIST 0x10 /* -l seen */
48 #define LIST 0x20 /* -L seen */
49 #define CONFIG 0x40 /* -g seen */
51 # define U_FLAG 0x1 /* -fu seen */
52 # define X_FLAG 0x2 /* -fx seen */
55 * functions
58 char *pflags();
59 char *pspec();
60 struct taglist *find_type();
61 void usage();
62 void parseline();
63 void add_svc();
64 void rem_svc();
65 void ed_svc();
66 void list_svcs();
67 void doconf();
70 * format of a _pmtab entry - used to hold parsed info
73 struct pmtab {
74 char *p_tag; /* service tag */
75 long p_flags; /* flags */
76 char *p_id; /* logname to start service as */
77 char *p_res1; /* reserved field */
78 char *p_res2; /* reserved field */
79 char *p_res3; /* reserved field */
80 char *p_pmspec; /* port monitor specific info */
84 * format of a tag list, which is a list of port monitor tags of
85 * a designated type
88 struct taglist {
89 struct taglist *t_next; /* next in list */
90 char t_tag[PMTAGSIZE + 1]; /* PM tag */
91 char t_type[PMTYPESIZE + 1]; /* PM type */
95 * common error messages
98 # define NOTPRIV "User not privileged for operation"
99 # define BADINP "Embedded newlines not allowed"
101 int Saferrno; /* internal `errno' for exit */
105 * main - scan args for pmadm and call appropriate handling code
109 main(int argc, char *argv[])
111 int c; /* option letter */
112 int ret; /* return code from check_version */
113 uid_t uid; /* invoker's real uid */
114 int flag = 0; /* flag to record requested operations */
115 int errflg = 0; /* error indicator */
116 int badcnt = 0; /* count of bad args to -f */
117 int version = -1; /* argument to -v */
118 int sawaflag = 0; /* true if actually saw -a */
119 int conflag = 0; /* true if output should be in condensed form */
120 long flags = 0; /* arguments to -f */
121 char *pmtag = NULL; /* argument to -p */
122 char *type = NULL; /* argument to -t */
123 char *script = NULL; /* argument to -z */
124 char *comment = " "; /* argument to -y */
125 char *id = NULL; /* argument to -i */
126 char *svctag = NULL; /* argument to -s */
127 char *pmspec = NULL; /* argument to -m */
128 char badargs[SIZE]; /* place to hold bad args to -f */
129 char buf[SIZE]; /* scratch buffer */
130 register char *p; /* scratch pointer */
132 if (argc == 1)
133 usage(argv[0]);
134 while ((c = getopt(argc, argv, "adef:gi:Llm:p:rs:t:v:y:z:")) != -1) {
135 switch (c) {
136 case 'a':
137 flag |= ADD;
138 sawaflag = 1;
139 break;
140 case 'd':
141 flag |= DISABLE;
142 break;
143 case 'e':
144 flag |= ENABLE;
145 break;
146 case 'f':
147 flag |= ADD;
148 while (*optarg) {
149 switch (*optarg++) {
150 case 'u':
151 flags |= U_FLAG;
152 break;
153 case 'x':
154 flags |= X_FLAG;
155 break;
156 default:
157 badargs[badcnt++] = *(optarg - 1);
158 break;
161 /* null terminate just in case anything is there */
162 badargs[badcnt] = '\0';
163 break;
164 case 'g':
165 flag |= CONFIG;
166 break;
167 case 'i':
168 if (strchr(optarg, '\n')) {
169 Saferrno = E_BADARGS;
170 error(BADINP);
172 flag |= ADD;
173 id = optarg;
174 break;
175 case 'L':
176 flag |= LIST;
177 break;
178 case 'l':
179 flag |= PLIST;
180 break;
181 case 'm':
182 if (strchr(optarg, '\n')) {
183 Saferrno = E_BADARGS;
184 error(BADINP);
186 if (*optarg == '\0') {
187 /* this will generate a usage message below */
188 errflg++;
189 break;
191 flag |= ADD;
192 pmspec = optarg;
193 break;
194 case 'p':
195 if (strchr(optarg, '\n')) {
196 Saferrno = E_BADARGS;
197 error(BADINP);
199 pmtag = optarg;
200 if (strlen(pmtag) > PMTAGSIZE) {
201 pmtag[PMTAGSIZE] = '\0';
202 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag);
204 for (p = pmtag; *p; p++) {
205 if (!isalnum(*p)) {
206 Saferrno = E_BADARGS;
207 error("port monitor tag must be alphanumeric");
210 break;
211 case 'r':
212 flag |= REMOVE;
213 break;
214 case 's':
215 if (strchr(optarg, '\n')) {
216 Saferrno = E_BADARGS;
217 error(BADINP);
219 svctag = optarg;
220 if (strlen(svctag) > SVCTAGSIZE) {
221 svctag[SVCTAGSIZE] = '\0';
222 (void) fprintf(stderr, "svctag too long, truncated to <%s>\n", svctag);
224 for (p = svctag; *p; p++) {
225 if (!isalnum(*p)) {
226 Saferrno = E_BADARGS;
227 error("service tag must be alphanumeric");
230 break;
231 case 't':
232 if (strchr(optarg, '\n')) {
233 Saferrno = E_BADARGS;
234 error(BADINP);
236 type = optarg;
237 if (strlen(type) > PMTYPESIZE) {
238 type[PMTYPESIZE] = '\0';
239 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type);
241 for (p = type; *p; p++) {
242 if (!isalnum(*p)) {
243 Saferrno = E_BADARGS;
244 error("port monitor type must be alphanumeric");
247 break;
248 case 'v':
249 flag |= ADD;
250 version = atoi(optarg);
251 if (version < 0) {
252 Saferrno = E_BADARGS;
253 error("version number can not be negative");
255 break;
256 case 'y':
257 if (strchr(optarg, '\n')) {
258 Saferrno = E_BADARGS;
259 error(BADINP);
261 flag |= ADD;
262 comment = optarg;
263 break;
264 case 'z':
265 if (strchr(optarg, '\n')) {
266 Saferrno = E_BADARGS;
267 error(BADINP);
269 script = optarg;
270 break;
271 case '?':
272 errflg++;
275 if (errflg || (optind < argc))
276 usage(argv[0]);
278 if (badcnt) {
279 /* bad flags were given to -f */
280 (void) sprintf(buf, "Invalid request, %s are not valid arguments for \"-f\"", badargs);
281 Saferrno = E_BADARGS;
282 error(buf);
285 uid = getuid();
288 * don't do anything if _sactab isn't the version we understand
291 if ((ret = check_version(VERSION, SACTAB)) == 1) {
292 Saferrno = E_SAFERR;
293 error("_sactab version number is incorrect");
295 else if (ret == 2) {
296 (void) sprintf(buf, "could not open %s", SACTAB);
297 Saferrno = E_SYSERR;
298 error(buf);
300 else if (ret == 3) {
301 (void) sprintf(buf, "%s file is corrupt", SACTAB);
302 Saferrno = E_SAFERR;
303 error(buf);
306 switch (flag) {
307 case ADD:
308 if (uid) {
309 Saferrno = E_NOPRIV;
310 error(NOTPRIV);
312 if (!sawaflag || (pmtag && type) || (!pmtag && !type) || !svctag || !id || !pmspec || (version < 0))
313 usage(argv[0]);
314 add_svc(pmtag, type, svctag, id, pmspec, flags, version, comment, script);
315 break;
316 case REMOVE:
317 if (uid) {
318 Saferrno = E_NOPRIV;
319 error(NOTPRIV);
321 if (!pmtag || !svctag || type || script)
322 usage(argv[0]);
323 rem_svc(pmtag, svctag);
324 break;
325 case ENABLE:
326 if (uid) {
327 Saferrno = E_NOPRIV;
328 error(NOTPRIV);
330 if (!pmtag || !svctag || type || script)
331 usage(argv[0]);
332 ed_svc(pmtag, svctag, ENABLE);
333 break;
334 case DISABLE:
335 if (uid) {
336 Saferrno = E_NOPRIV;
337 error(NOTPRIV);
339 if (!pmtag || !svctag || type || script)
340 usage(argv[0]);
341 ed_svc(pmtag, svctag, DISABLE);
342 break;
343 case LIST:
344 conflag = 1;
345 /* fall through */
346 case PLIST:
347 if ((pmtag && type) || script)
348 usage(argv[0]);
349 list_svcs(pmtag, type, svctag, conflag);
350 break;
351 case CONFIG:
352 if (script && uid) {
353 Saferrno = E_NOPRIV;
354 error(NOTPRIV);
356 if ((pmtag && type) || (!pmtag && !type) || !svctag || (type && !script))
357 usage(argv[0]);
358 doconf(script, pmtag, type, svctag);
359 break;
360 default:
361 /* we only get here if more than one flag bit was set */
362 usage(argv[0]);
363 /* NOTREACHED */
365 quit();
366 /* NOTREACHED */
371 * usage - print out a usage message
373 * args: cmdname - the name command was invoked with
376 void
377 usage(cmdname)
378 char *cmdname;
380 (void) fprintf(stderr, "Usage:\t%s -a [ -p pmtag | -t type ] -s svctag -i id -m \"pmspecific\"\n", cmdname);
381 (void) fprintf(stderr, "\t\t-v version [ -f xu ] [ -y comment ] [ -z script]\n");
382 (void) fprintf(stderr, "\t%s -r -p pmtag -s svctag\n", cmdname);
383 (void) fprintf(stderr, "\t%s -e -p pmtag -s svctag\n", cmdname);
384 (void) fprintf(stderr, "\t%s -d -p pmtag -s svctag\n", cmdname);
385 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname);
386 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname);
387 (void) fprintf(stderr, "\t%s -g -p pmtag -s svctag [ -z script ]\n", cmdname);
388 (void) fprintf(stderr, "\t%s -g -s svctag -t type -z script\n", cmdname);
389 Saferrno = E_BADARGS;
390 quit();
395 * add_svc - add a service entry
397 * args: tag - port monitor's tag (may be null)
398 * type - port monitor's type (may be null)
399 * svctag - service's tag
400 * id - identity under which service should run
401 * pmspec - uninterpreted port monitor-specific info
402 * flags - service flags
403 * version - version number of port monitor's pmtab
404 * comment - comment describing service
405 * script - service's configuration script
408 void
409 add_svc(tag, type, svctag, id, pmspec, flags, version, comment, script)
410 char *tag;
411 char *type;
412 char *svctag;
413 char *id;
414 char *pmspec;
415 long flags;
416 int version;
417 char *comment;
418 char *script;
420 FILE *fp; /* scratch file pointer */
421 struct taglist tl; /* 'list' for degenerate case (1 PM) */
422 register struct taglist *tp = NULL; /* working pointer */
423 int ret; /* return code from check_version */
424 char buf[SIZE]; /* scratch buffer */
425 char fname[SIZE]; /* scratch buffer for building names */
426 int added; /* count number added */
428 fp = fopen(SACTAB, "r");
429 if (fp == NULL) {
430 Saferrno = E_SYSERR;
431 error("Could not open _sactab");
433 if (tag && !find_pm(fp, tag)) {
434 (void) sprintf(buf, "Invalid request, %s does not exist", tag);
435 Saferrno = E_NOEXIST;
436 error(buf);
438 if (type && !(tp = find_type(fp, type))) {
439 (void) sprintf(buf, "Invalid request, %s does not exist", type);
440 Saferrno = E_NOEXIST;
441 error(buf);
443 (void) fclose(fp);
445 if (tag) {
448 * treat the case of 1 PM as a degenerate case of a list of PMs from a
449 * type specification. Build the 'list' here.
452 tp = &tl;
453 tp->t_next = NULL;
454 (void) strcpy(tp->t_tag, tag);
457 added = 0;
458 while (tp) {
459 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
460 if ((ret = check_version(version, fname)) == 1) {
461 (void) sprintf(buf, "%s version number is incorrect", fname);
462 Saferrno = E_SAFERR;
463 error(buf);
465 else if (ret == 2) {
466 (void) sprintf(buf, "could not open %s", fname);
467 Saferrno = E_SYSERR;
468 error(buf);
470 else if (ret == 3) {
471 (void) sprintf(buf, "%s file is corrupt", fname);
472 Saferrno = E_SAFERR;
473 error(buf);
475 fp = fopen(fname, "r");
476 if (fp == NULL) {
477 (void) sprintf(buf, "Could not open %s", fname);
478 Saferrno = E_SYSERR;
479 error(buf);
481 if (find_svc(fp, tp->t_tag, svctag)) {
482 if (tag) {
483 /* special case of tag only */
484 (void) sprintf(buf, "Invalid request, %s already exists under %s", svctag, tag);
485 Saferrno = E_DUP;
486 error(buf);
488 else {
489 (void) fprintf(stderr, "warning - %s already exists under %s - ignoring\n", svctag, tp->t_tag);
490 tp = tp->t_next;
491 (void) fclose(fp);
492 continue;
495 (void) fclose(fp);
498 * put in the config script, if specified
501 if (script) {
502 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag);
503 if (do_config(script, fname)) {
504 /* do_config put out any messages */
505 tp = tp->t_next;
506 continue;
511 * add the line
514 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
515 fp = fopen(fname, "a");
516 if (fp == NULL) {
517 (void) sprintf(buf, "Could not open %s", fname);
518 Saferrno = E_SYSERR;
519 error(buf);
521 (void) fprintf(fp, "%s:%s:%s:reserved:reserved:reserved:%s#%s\n",
522 svctag, (flags ? pflags(flags, FALSE) : ""), id, pmspec,
523 (comment ? comment : ""));
524 (void) fclose(fp);
525 added++;
528 * tell the SAC to to tell PM to read _pmtab
531 (void) tell_sac(tp->t_tag);
532 tp = tp->t_next;
534 if (added == 0) {
535 Saferrno = E_SAFERR;
536 error("No services added");
538 return;
543 * rem_svc - remove a service
545 * args: pmtag - tag of port monitor responsible for the service
546 * svctag - tag of the service to be removed
549 void
550 rem_svc(pmtag, svctag)
551 char *pmtag;
552 char *svctag;
554 FILE *fp; /* scratch file pointer */
555 FILE *tfp; /* file pointer for temp file */
556 int line; /* line number entry is on */
557 char *tname; /* temp file name */
558 char buf[SIZE]; /* scratch buffer */
559 char fname[SIZE]; /* path to correct _pmtab */
561 fp = fopen(SACTAB, "r");
562 if (fp == NULL) {
563 Saferrno = E_SYSERR;
564 error("Could not open _sactab");
566 if (!find_pm(fp, pmtag)) {
567 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
568 Saferrno = E_NOEXIST;
569 error(buf);
571 (void) fclose(fp);
573 (void) sprintf(fname, "%s/_pmtab", pmtag);
574 (void) sprintf(buf, "%s/%s", HOME, fname);
575 fp = fopen(buf, "r");
576 if (fp == NULL) {
577 (void) sprintf(buf, "Could not open %s/%s", HOME, fname);
578 Saferrno = E_SYSERR;
579 error(buf);
581 if ((line = find_svc(fp, pmtag, svctag)) == 0) {
582 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag);
583 Saferrno = E_NOEXIST;
584 error(buf);
586 tname = make_tempname(fname);
587 tfp = open_temp(tname);
588 if (line != 1) {
589 if (copy_file(fp, tfp, 1, line - 1)) {
590 (void) unlink(tname);
591 Saferrno = E_SYSERR;
592 error("error accessing temp file");
595 if (copy_file(fp, tfp, line + 1, -1)) {
596 (void) unlink(tname);
597 Saferrno = E_SYSERR;
598 error("error accessing temp file");
600 (void) fclose(fp);
601 if (fclose(tfp) == EOF) {
602 (void) unlink(tname);
603 Saferrno = E_SYSERR;
604 error("error closing tempfile");
606 /* note - replace only returns if successful */
607 replace(fname, tname);
610 * tell the SAC to to tell PM to read _pmtab
613 if (tell_sac(pmtag)) {
616 * if we got rid of the service, try to remove the config script too.
617 * Don't check return status since it may not have existed anyhow.
620 (void) sprintf(buf, "%s/%s/%s", HOME, pmtag, svctag);
621 (void) unlink(buf);
622 return;
629 * ed_svc - enable or disable a particular service
631 * args: pmtag - tag of port monitor responsible for the service
632 * svctag - tag of service to be enabled or disabled
633 * flag - operation to perform (ENABLE or DISABLE)
636 void
637 ed_svc(pmtag, svctag, flag)
638 char *pmtag;
639 char *svctag;
640 int flag;
642 FILE *fp; /* scratch file pointer */
643 FILE *tfp; /* file pointer for temp file */
644 int line; /* line number entry is on */
645 register char *from; /* working pointer */
646 register char *to; /* working pointer */
647 char *tname; /* temp file name */
648 char *p; /* scratch pointer */
649 char buf[SIZE]; /* scratch buffer */
650 char tbuf[SIZE]; /* scratch buffer */
651 char fname[SIZE]; /* path to correct _pmtab */
653 fp = fopen(SACTAB, "r");
654 if (fp == NULL) {
655 Saferrno = E_SYSERR;
656 error("Could not open _sactab");
658 if (!find_pm(fp, pmtag)) {
659 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
660 Saferrno = E_NOEXIST;
661 error(buf);
663 (void) fclose(fp);
665 (void) sprintf(fname, "%s/_pmtab", pmtag);
666 (void) sprintf(buf, "%s/%s", HOME, fname);
667 fp = fopen(buf, "r");
668 if (fp == NULL) {
669 (void) sprintf(buf, "Could not open %s/%s", HOME, fname);
670 Saferrno = E_SYSERR;
671 error(buf);
673 if ((line = find_svc(fp, pmtag, svctag)) == 0) {
674 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag);
675 Saferrno = E_NOEXIST;
676 error(buf);
678 tname = make_tempname(fname);
679 tfp = open_temp(tname);
680 if (line != 1) {
681 if (copy_file(fp, tfp, 1, line - 1)) {
682 (void) unlink(tname);
683 Saferrno = E_SYSERR;
684 error("error accessing temp file");
689 * Note: find_svc above has already read and parsed this entry, thus
690 * we know it to be well-formed, so just change the flags as appropriate
693 if (fgets(buf, SIZE, fp) == NULL) {
694 (void) unlink(tname);
695 Saferrno = E_SYSERR;
696 error("error accessing temp file");
698 from = buf;
699 to = tbuf;
702 * copy initial portion of entry
705 p = strchr(from, DELIMC);
706 for ( ; from <= p; )
707 *to++ = *from++;
710 * isolate and fix the flags
713 p = strchr(from, DELIMC);
714 for ( ; from < p; ) {
715 if (*from == 'x') {
716 from++;
717 continue;
719 *to++ = *from++;
723 * above we removed x flag, if this was a disable operation, stick it in
724 * and also copy the field delimiter
727 if (flag == DISABLE)
728 *to++ = 'x';
729 *to++ = *from++;
732 * copy the rest of the line
735 for ( ; from < &buf[SIZE - 1] ;)
736 *to++ = *from++;
737 /*** *to = '\0'; BUG: Don't uncomment it ****/
739 (void) fprintf(tfp, "%s", tbuf);
741 if (copy_file(fp, tfp, line + 1, -1)) {
742 (void) unlink(tname);
743 Saferrno = E_SYSERR;
744 error("error accessing temp file");
746 (void) fclose(fp);
747 if (fclose(tfp) == EOF) {
748 (void) unlink(tname);
749 Saferrno = E_SYSERR;
750 error("error closing tempfile");
752 /* note - replace only returns if successful */
753 replace(fname, tname);
757 * tell the SAC to to tell PM to read _pmtab
760 (void) tell_sac(pmtag);
765 * doconf - take a config script and have it put where it belongs or
766 * output an existing one
768 * args: script - name of file containing script (if NULL, means
769 * output existing one instead)
770 * tag - tag of port monitor that is responsible for the
771 * designated service (may be null)
772 * type - type of port monitor that is responsible for the
773 * designated service (may be null)
774 * svctag - tag of service whose config script we're operating on
777 void
778 doconf(script, tag, type, svctag)
779 char *script;
780 char *tag;
781 char *type;
782 char *svctag;
784 FILE *fp; /* scratch file pointer */
785 int added; /* count of config scripts added */
786 struct taglist tl; /* 'list' for degenerate case (1 PM) */
787 register struct taglist *tp = NULL; /* working pointer */
788 char buf[SIZE]; /* scratch buffer */
789 char fname[SIZE]; /* scratch buffer for names */
791 fp = fopen(SACTAB, "r");
792 if (fp == NULL) {
793 Saferrno = E_SYSERR;
794 error("Could not open _sactab");
796 if (tag && !find_pm(fp, tag)) {
797 (void) sprintf(buf, "Invalid request, %s does not exist", tag);
798 Saferrno = E_NOEXIST;
799 error(buf);
801 if (type && !(tp = find_type(fp, type))) {
802 (void) sprintf(buf, "Invalid request, %s does not exist", type);
803 Saferrno = E_NOEXIST;
804 error(buf);
806 (void) fclose(fp);
808 if (tag) {
811 * treat the case of 1 PM as a degenerate case of a list of PMs from a
812 * type specification. Build the 'list' here.
815 tp = &tl;
816 tp->t_next = NULL;
817 (void) strcpy(tp->t_tag, tag);
820 added = 0;
821 while (tp) {
822 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
823 fp = fopen(fname, "r");
824 if (fp == NULL) {
825 (void) sprintf(buf, "Could not open %s", fname);
826 Saferrno = E_SYSERR;
827 error(buf);
829 if (!find_svc(fp, tp->t_tag, svctag)) {
830 if (tag) {
831 /* special case of tag only */
832 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, tag);
833 Saferrno = E_NOEXIST;
834 error(buf);
836 else {
837 (void) fprintf(stderr, "warning - %s does not exist under %s - ignoring\n", svctag, tp->t_tag);
838 Saferrno = E_NOEXIST;
839 tp = tp->t_next;
840 (void) fclose(fp);
841 continue;
844 (void) fclose(fp);
846 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag);
849 * do_config does all the real work (keep track if any errors occurred)
852 if (do_config(script, fname) == 0)
853 added++;
854 tp = tp->t_next;
856 if (added == 0) {
857 Saferrno = E_SAFERR;
858 error("No configuration scripts installed");
860 return;
865 * tell_sac - use sacadm to tell the sac to tell a port monitor to read
866 * its _pmtab. Return TRUE on success, FALSE on failure.
868 * args: tag - tag of port monitor to be notified
873 tell_sac(char *tag)
875 pid_t pid; /* returned pid from fork */
876 int status; /* return status from sacadm child */
878 if ((pid = fork()) < 0) {
879 (void) fprintf(stderr, "warning - fork failed - could not notify <%s> about modified table\n", tag);
880 (void) fprintf(stderr, "try executing the command \"sacadm -x -p %s\"\n", tag);
881 Saferrno = E_SYSERR;
882 return(FALSE);
884 else if (pid) {
885 /* parent */
886 (void) wait(&status);
887 if (status) {
888 if (((status >> 8) & 0xff) == E_PMNOTRUN) {
889 (void) fprintf(stderr, "warning - port monitor, %s is not running\n", tag);
890 return (FALSE);
892 if (((status >> 8) & 0xff) == E_SACNOTRUN) {
893 Saferrno = E_SACNOTRUN;
894 } else {
895 Saferrno = E_SYSERR;
897 (void) fprintf(stderr,
898 "warning - could not notify <%s> about modified"
899 " table\n", tag);
900 (void) fprintf(stderr, "try executing the command"
901 " \"sacadm -x -p %s\"\n", tag);
902 return(FALSE);
904 else {
905 return(TRUE);
908 else {
909 /* set IFS for security */
910 (void) putenv("IFS=\" \"");
911 /* muffle sacadm warning messages */
912 (void) fclose(stderr);
913 (void) fopen("/dev/null", "w");
914 (void) execl("/usr/sbin/sacadm", "sacadm", "-x", "-p", tag, 0);
917 * if we got here, it didn't work, exit status will clue in parent to
918 * put out the warning
921 exit(1);
923 /* NOTREACHED */
928 * list_svcs - list information about services
930 * args: pmtag - tag of port monitor responsible for the service
931 * (may be null)
932 * type - type of port monitor responsible for the service
933 * (may be null)
934 * svctag - tag of service to be listed (may be null)
935 * oflag - true if output should be easily parseable
938 void
939 list_svcs(pmtag, type, svctag, oflag)
940 char *pmtag;
941 char *type;
942 char *svctag;
944 FILE *fp; /* scratch file pointer */
945 register struct taglist *tp; /* pointer to PM list */
946 int nprint = 0; /* count # of svcs printed */
947 struct pmtab pmtab; /* place to hold parsed info */
948 register struct pmtab *pp = &pmtab; /* and a pointer to it */
949 register char *p; /* working pointer */
950 char buf[SIZE]; /* scratch buffer */
951 char fname[SIZE]; /* scratch buffer for building names */
953 fp = fopen(SACTAB, "r");
954 if (fp == NULL) {
955 Saferrno = E_SYSERR;
956 error("Could not open _sactab");
958 if (pmtag && !find_pm(fp, pmtag)) {
959 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
960 Saferrno = E_NOEXIST;
961 error(buf);
963 rewind(fp);
964 if (type) {
965 tp = find_type(fp, type);
966 if (tp == NULL) {
967 (void) sprintf(buf, "Invalid request, %s does not exist", type);
968 Saferrno = E_NOEXIST;
969 error(buf);
972 else
973 tp = find_type(fp, NULL);
974 (void) fclose(fp);
976 while (tp) {
977 if (pmtag && strcmp(tp->t_tag, pmtag)) {
978 /* not interested in this port monitor */
979 tp = tp->t_next;
980 continue;
982 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
983 fp = fopen(fname, "r");
984 if (fp == NULL) {
985 (void) sprintf(buf, "Could not open %s", fname);
986 Saferrno = E_SYSERR;
987 error(buf);
989 while (fgets(buf, SIZE, fp)) {
990 p = trim(buf);
991 if (*p == '\0')
992 continue;
993 parseline(p, pp, tp->t_tag);
994 if (!svctag || !strcmp(pp->p_tag, svctag)) {
995 if (oflag) {
996 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s#%s\n",
997 tp->t_tag, tp->t_type, pp->p_tag,
998 pflags(pp->p_flags, FALSE),
999 pp->p_id, pp->p_res1, pp->p_res2,
1000 pp->p_res3,pp->p_pmspec, Comment);
1002 else {
1003 if (nprint == 0) {
1004 (void) printf("PMTAG PMTYPE SVCTAG FLGS ID <PMSPECIFIC>\n");
1006 (void) printf("%-14s %-14s %-14s %-4s %-8s %s #%s\n", tp->t_tag, tp->t_type, pp->p_tag,
1007 pflags(pp->p_flags, TRUE), pp->p_id, pspec(pp->p_pmspec), Comment);
1009 nprint++;
1012 if (!feof(fp)) {
1013 (void) sprintf(buf, "error reading %s", fname);
1014 Saferrno = E_SYSERR;
1015 error(buf);
1017 else {
1018 (void) fclose(fp);
1019 tp = tp->t_next;
1022 /* if we didn't find any valid ones, indicate an error */
1023 if (nprint == 0) {
1024 if (svctag)
1025 (void) fprintf(stderr, "Service <%s> does not exist\n", svctag);
1026 else
1027 (void) fprintf(stderr, "No services defined\n");
1028 Saferrno = E_NOEXIST;
1030 return;
1035 * find_svc - find an entry in _pmtab for a particular service tag
1037 * args: fp - file pointer for _pmtab
1038 * tag - port monitor tag (for error reporting)
1039 * svctag - tag of service we're looking for
1043 find_svc(FILE *fp, char *tag, char *svctag)
1045 register char *p; /* working pointer */
1046 int line = 0; /* line number we found entry on */
1047 struct pmtab pmtab; /* place to hold parsed info */
1048 static char buf[SIZE]; /* scratch buffer */
1050 while (fgets(buf, SIZE, fp)) {
1051 line++;
1052 p = trim(buf);
1053 if (*p == '\0')
1054 continue;
1055 parseline(p, &pmtab, tag);
1056 if (!(strcmp(pmtab.p_tag, svctag)))
1057 return(line);
1059 if (!feof(fp)) {
1060 (void) sprintf(buf, "error reading %s/%s/_pmtab", HOME, tag);
1061 Saferrno = E_SYSERR;
1062 error(buf);
1063 /* NOTREACHED */
1064 return (0);
1065 } else
1066 return (0);
1071 * parseline - parse a line from _pmtab. This routine will return if the
1072 * parse wa successful, otherwise it will output an error and
1073 * exit.
1075 * args: p - pointer to the data read from the file (note - this is
1076 * a static data region, so we can point into it)
1077 * pp - pointer to a structure in which the separated fields
1078 * are placed
1079 * tag - port monitor tag (for error reporting)
1081 * A line in the file has the following format:
1083 * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment
1087 void
1088 parseline(p, pp, tag)
1089 register char *p;
1090 register struct pmtab *pp;
1091 char *tag;
1093 char buf[SIZE]; /* scratch buffer */
1096 * get the service tag
1099 p = nexttok(p, DELIM, FALSE);
1100 if (p == NULL) {
1101 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1102 Saferrno = E_SAFERR;
1103 error(buf);
1105 if (strlen(p) > PMTAGSIZE) {
1106 p[PMTAGSIZE] = '\0';
1107 (void) fprintf(stderr, "tag too long, truncated to <%s>", p);
1109 pp->p_tag = p;
1112 * get the flags
1115 p = nexttok(NULL, DELIM, FALSE);
1116 if (p == NULL) {
1117 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1118 Saferrno = E_SAFERR;
1119 error(buf);
1121 pp->p_flags = 0;
1122 while (*p) {
1123 switch (*p++) {
1124 case 'u':
1125 pp->p_flags |= U_FLAG;
1126 break;
1127 case 'x':
1128 pp->p_flags |= X_FLAG;
1129 break;
1130 default:
1131 (void) sprintf(buf, "Unrecognized flag <%c>", *(p - 1));
1132 Saferrno = E_SAFERR;
1133 error(buf);
1134 break;
1139 * get the identity
1142 p = nexttok(NULL, DELIM, FALSE);
1143 if (p == NULL) {
1144 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1145 Saferrno = E_SAFERR;
1146 error(buf);
1148 pp->p_id = p;
1151 * get the first reserved field
1154 p = nexttok(NULL, DELIM, FALSE);
1155 if (p == NULL) {
1156 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1157 Saferrno = E_SAFERR;
1158 error(buf);
1160 pp->p_res1 = p;
1163 * get the second reserved field
1166 p = nexttok(NULL, DELIM, FALSE);
1167 if (p == NULL) {
1168 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1169 Saferrno = E_SAFERR;
1170 error(buf);
1172 pp->p_res2 = p;
1175 * get the third reserved field
1178 p = nexttok(NULL, DELIM, FALSE);
1179 if (p == NULL) {
1180 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1181 Saferrno = E_SAFERR;
1182 error(buf);
1184 pp->p_res3 = p;
1187 * the rest is the port monitor specific info
1190 p = nexttok(NULL, DELIM, TRUE);
1191 if (p == NULL) {
1192 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1193 Saferrno = E_SAFERR;
1194 error(buf);
1196 pp->p_pmspec = p;
1197 return;
1202 * pspec - format port monitor specific information
1204 * args: spec - port monitor specific info, separated by
1205 * field separater character (may be escaped by \)
1208 char *
1209 pspec(spec)
1210 char *spec;
1212 static char buf[SIZE]; /* returned string */
1213 register char *from; /* working pointer */
1214 register char *to; /* working pointer */
1215 int newflag; /* flag indicating new field */
1217 to = buf;
1218 from = spec;
1219 newflag = 1;
1220 while (*from) {
1221 switch (*from) {
1222 case ':':
1223 if (newflag) {
1224 *to++ = '-';
1226 *to++ = ' ';
1227 from++;
1228 newflag = 1;
1229 break;
1230 case '\\':
1231 if (*(from + 1) == ':') {
1232 *to++ = ':';
1233 /* skip over \: */
1234 from += 2;
1236 else
1237 *to++ = *from++;
1238 newflag = 0;
1239 break;
1240 default:
1241 newflag = 0;
1242 *to++ = *from++;
1245 *to = '\0';
1246 return(buf);
1251 * pflags - put service flags into intelligible form for output
1253 * args: flags - binary representation of flags
1254 * dflag - true if a "-" should be returned if no flags
1257 char *
1258 pflags(flags, dflag)
1259 long flags;
1260 int dflag;
1262 register int i; /* scratch counter */
1263 static char buf[SIZE]; /* formatted flags */
1265 if (flags == 0) {
1266 if (dflag)
1267 return("-");
1268 else
1269 return("");
1271 i = 0;
1272 if (flags & U_FLAG) {
1273 buf[i++] = 'u';
1274 flags &= ~U_FLAG;
1276 if (flags & X_FLAG) {
1277 buf[i++] = 'x';
1278 flags &= ~X_FLAG;
1280 if (flags) {
1281 Saferrno = E_SAFERR;
1282 error("Internal error in pflags");
1284 buf[i] = '\0';
1285 return(buf);
1290 * find_type - find entries in _sactab for a particular port monitor type
1292 * args: fp - file pointer for _sactab
1293 * type - type of port monitor we're looking for (if type is
1294 * null, it means find all PMs)
1297 struct taglist *
1298 find_type(fp, type)
1299 FILE *fp;
1300 char *type;
1302 register char *p; /* working pointer */
1303 struct sactab stab; /* place to hold parsed info */
1304 register struct sactab *sp = &stab; /* and a pointer to it */
1305 char buf[SIZE]; /* scratch buffer */
1306 struct taglist *thead; /* linked list of tags */
1307 register struct taglist *temp; /* scratch pointer */
1309 thead = NULL;
1310 while (fgets(buf, SIZE, fp)) {
1311 p = trim(buf);
1312 if (*p == '\0')
1313 continue;
1314 parse(p, sp);
1315 if ((type == NULL) || !(strcmp(sp->sc_type, type))) {
1316 temp = (struct taglist *) malloc(sizeof(struct taglist));
1317 if (temp == NULL) {
1318 Saferrno = E_SYSERR;
1319 error("malloc failed");
1321 temp->t_next = thead;
1322 (void) strcpy(temp->t_tag, sp->sc_tag);
1323 (void) strcpy(temp->t_type, sp->sc_type);
1324 thead = temp;
1327 if (!feof(fp)) {
1328 Saferrno = E_SYSERR;
1329 error("error reading _sactab");
1330 /* NOTREACHED */
1331 return (0);
1332 } else
1333 return (thead ? thead : NULL);