1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
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"
42
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 */
50
51 # define U_FLAG 0x1 /* -fu seen */
52 # define X_FLAG 0x2 /* -fx seen */
53
54 /*
55 * functions
56 */
57
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();
68
69 /*
70 * format of a _pmtab entry - used to hold parsed info
71 */
72
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 */
81 };
82
83 /*
84 * format of a tag list, which is a list of port monitor tags of
85 * a designated type
86 */
87
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 */
92 };
93
94 /*
95 * common error messages
96 */
97
98 # define NOTPRIV "User not privileged for operation"
99 # define BADINP "Embedded newlines not allowed"
100
101 int Saferrno; /* internal `errno' for exit */
102
103
104 /*
105 * main - scan args for pmadm and call appropriate handling code
106 */
107
108 int
main(int argc,char * argv[])109 main(int argc, char *argv[])
110 {
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 */
131
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;
159 }
160 }
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);
171 }
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);
185 }
186 if (*optarg == '\0') {
187 /* this will generate a usage message below */
188 errflg++;
189 break;
190 }
191 flag |= ADD;
192 pmspec = optarg;
193 break;
194 case 'p':
195 if (strchr(optarg, '\n')) {
196 Saferrno = E_BADARGS;
197 error(BADINP);
198 }
199 pmtag = optarg;
200 if (strlen(pmtag) > PMTAGSIZE) {
201 pmtag[PMTAGSIZE] = '\0';
202 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag);
203 }
204 for (p = pmtag; *p; p++) {
205 if (!isalnum(*p)) {
206 Saferrno = E_BADARGS;
207 error("port monitor tag must be alphanumeric");
208 }
209 }
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);
218 }
219 svctag = optarg;
220 if (strlen(svctag) > SVCTAGSIZE) {
221 svctag[SVCTAGSIZE] = '\0';
222 (void) fprintf(stderr, "svctag too long, truncated to <%s>\n", svctag);
223 }
224 for (p = svctag; *p; p++) {
225 if (!isalnum(*p)) {
226 Saferrno = E_BADARGS;
227 error("service tag must be alphanumeric");
228 }
229 }
230 break;
231 case 't':
232 if (strchr(optarg, '\n')) {
233 Saferrno = E_BADARGS;
234 error(BADINP);
235 }
236 type = optarg;
237 if (strlen(type) > PMTYPESIZE) {
238 type[PMTYPESIZE] = '\0';
239 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type);
240 }
241 for (p = type; *p; p++) {
242 if (!isalnum(*p)) {
243 Saferrno = E_BADARGS;
244 error("port monitor type must be alphanumeric");
245 }
246 }
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");
254 }
255 break;
256 case 'y':
257 if (strchr(optarg, '\n')) {
258 Saferrno = E_BADARGS;
259 error(BADINP);
260 }
261 flag |= ADD;
262 comment = optarg;
263 break;
264 case 'z':
265 if (strchr(optarg, '\n')) {
266 Saferrno = E_BADARGS;
267 error(BADINP);
268 }
269 script = optarg;
270 break;
271 case '?':
272 errflg++;
273 }
274 }
275 if (errflg || (optind < argc))
276 usage(argv[0]);
277
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);
283 }
284
285 uid = getuid();
286
287 /*
288 * don't do anything if _sactab isn't the version we understand
289 */
290
291 if ((ret = check_version(VERSION, SACTAB)) == 1) {
292 Saferrno = E_SAFERR;
293 error("_sactab version number is incorrect");
294 }
295 else if (ret == 2) {
296 (void) sprintf(buf, "could not open %s", SACTAB);
297 Saferrno = E_SYSERR;
298 error(buf);
299 }
300 else if (ret == 3) {
301 (void) sprintf(buf, "%s file is corrupt", SACTAB);
302 Saferrno = E_SAFERR;
303 error(buf);
304 }
305
306 switch (flag) {
307 case ADD:
308 if (uid) {
309 Saferrno = E_NOPRIV;
310 error(NOTPRIV);
311 }
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);
320 }
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);
329 }
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);
338 }
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);
355 }
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 */
364 }
365 quit();
366 /* NOTREACHED */
367 }
368
369
370 /*
371 * usage - print out a usage message
372 *
373 * args: cmdname - the name command was invoked with
374 */
375
376 void
usage(cmdname)377 usage(cmdname)
378 char *cmdname;
379 {
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();
391 }
392
393
394 /*
395 * add_svc - add a service entry
396 *
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
406 */
407
408 void
add_svc(tag,type,svctag,id,pmspec,flags,version,comment,script)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;
419 {
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 */
427
428 fp = fopen(SACTAB, "r");
429 if (fp == NULL) {
430 Saferrno = E_SYSERR;
431 error("Could not open _sactab");
432 }
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);
437 }
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);
442 }
443 (void) fclose(fp);
444
445 if (tag) {
446
447 /*
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.
450 */
451
452 tp = &tl;
453 tp->t_next = NULL;
454 (void) strcpy(tp->t_tag, tag);
455 }
456
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);
464 }
465 else if (ret == 2) {
466 (void) sprintf(buf, "could not open %s", fname);
467 Saferrno = E_SYSERR;
468 error(buf);
469 }
470 else if (ret == 3) {
471 (void) sprintf(buf, "%s file is corrupt", fname);
472 Saferrno = E_SAFERR;
473 error(buf);
474 }
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);
480 }
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);
487 }
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;
493 }
494 }
495 (void) fclose(fp);
496
497 /*
498 * put in the config script, if specified
499 */
500
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;
507 }
508 }
509
510 /*
511 * add the line
512 */
513
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);
520 }
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++;
526
527 /*
528 * tell the SAC to to tell PM to read _pmtab
529 */
530
531 (void) tell_sac(tp->t_tag);
532 tp = tp->t_next;
533 }
534 if (added == 0) {
535 Saferrno = E_SAFERR;
536 error("No services added");
537 }
538 return;
539 }
540
541
542 /*
543 * rem_svc - remove a service
544 *
545 * args: pmtag - tag of port monitor responsible for the service
546 * svctag - tag of the service to be removed
547 */
548
549 void
rem_svc(pmtag,svctag)550 rem_svc(pmtag, svctag)
551 char *pmtag;
552 char *svctag;
553 {
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 */
560
561 fp = fopen(SACTAB, "r");
562 if (fp == NULL) {
563 Saferrno = E_SYSERR;
564 error("Could not open _sactab");
565 }
566 if (!find_pm(fp, pmtag)) {
567 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
568 Saferrno = E_NOEXIST;
569 error(buf);
570 }
571 (void) fclose(fp);
572
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);
580 }
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);
585 }
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");
593 }
594 }
595 if (copy_file(fp, tfp, line + 1, -1)) {
596 (void) unlink(tname);
597 Saferrno = E_SYSERR;
598 error("error accessing temp file");
599 }
600 (void) fclose(fp);
601 if (fclose(tfp) == EOF) {
602 (void) unlink(tname);
603 Saferrno = E_SYSERR;
604 error("error closing tempfile");
605 }
606 /* note - replace only returns if successful */
607 replace(fname, tname);
608
609 /*
610 * tell the SAC to to tell PM to read _pmtab
611 */
612
613 if (tell_sac(pmtag)) {
614
615 /*
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.
618 */
619
620 (void) sprintf(buf, "%s/%s/%s", HOME, pmtag, svctag);
621 (void) unlink(buf);
622 return;
623 }
624 }
625
626
627
628 /*
629 * ed_svc - enable or disable a particular service
630 *
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)
634 */
635
636 void
ed_svc(pmtag,svctag,flag)637 ed_svc(pmtag, svctag, flag)
638 char *pmtag;
639 char *svctag;
640 int flag;
641 {
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 */
652
653 fp = fopen(SACTAB, "r");
654 if (fp == NULL) {
655 Saferrno = E_SYSERR;
656 error("Could not open _sactab");
657 }
658 if (!find_pm(fp, pmtag)) {
659 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
660 Saferrno = E_NOEXIST;
661 error(buf);
662 }
663 (void) fclose(fp);
664
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);
672 }
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);
677 }
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");
685 }
686 }
687
688 /*
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
691 */
692
693 if (fgets(buf, SIZE, fp) == NULL) {
694 (void) unlink(tname);
695 Saferrno = E_SYSERR;
696 error("error accessing temp file");
697 }
698 from = buf;
699 to = tbuf;
700
701 /*
702 * copy initial portion of entry
703 */
704
705 p = strchr(from, DELIMC);
706 for ( ; from <= p; )
707 *to++ = *from++;
708
709 /*
710 * isolate and fix the flags
711 */
712
713 p = strchr(from, DELIMC);
714 for ( ; from < p; ) {
715 if (*from == 'x') {
716 from++;
717 continue;
718 }
719 *to++ = *from++;
720 }
721
722 /*
723 * above we removed x flag, if this was a disable operation, stick it in
724 * and also copy the field delimiter
725 */
726
727 if (flag == DISABLE)
728 *to++ = 'x';
729 *to++ = *from++;
730
731 /*
732 * copy the rest of the line
733 */
734
735 for ( ; from < &buf[SIZE - 1] ;)
736 *to++ = *from++;
737 /*** *to = '\0'; BUG: Don't uncomment it ****/
738
739 (void) fprintf(tfp, "%s", tbuf);
740
741 if (copy_file(fp, tfp, line + 1, -1)) {
742 (void) unlink(tname);
743 Saferrno = E_SYSERR;
744 error("error accessing temp file");
745 }
746 (void) fclose(fp);
747 if (fclose(tfp) == EOF) {
748 (void) unlink(tname);
749 Saferrno = E_SYSERR;
750 error("error closing tempfile");
751 }
752 /* note - replace only returns if successful */
753 replace(fname, tname);
754
755
756 /*
757 * tell the SAC to to tell PM to read _pmtab
758 */
759
760 (void) tell_sac(pmtag);
761 }
762
763
764 /*
765 * doconf - take a config script and have it put where it belongs or
766 * output an existing one
767 *
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
775 */
776
777 void
doconf(script,tag,type,svctag)778 doconf(script, tag, type, svctag)
779 char *script;
780 char *tag;
781 char *type;
782 char *svctag;
783 {
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 */
790
791 fp = fopen(SACTAB, "r");
792 if (fp == NULL) {
793 Saferrno = E_SYSERR;
794 error("Could not open _sactab");
795 }
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);
800 }
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);
805 }
806 (void) fclose(fp);
807
808 if (tag) {
809
810 /*
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.
813 */
814
815 tp = &tl;
816 tp->t_next = NULL;
817 (void) strcpy(tp->t_tag, tag);
818 }
819
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);
828 }
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);
835 }
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;
842 }
843 }
844 (void) fclose(fp);
845
846 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag);
847
848 /*
849 * do_config does all the real work (keep track if any errors occurred)
850 */
851
852 if (do_config(script, fname) == 0)
853 added++;
854 tp = tp->t_next;
855 }
856 if (added == 0) {
857 Saferrno = E_SAFERR;
858 error("No configuration scripts installed");
859 }
860 return;
861 }
862
863
864 /*
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.
867 *
868 * args: tag - tag of port monitor to be notified
869 */
870
871
872 int
tell_sac(char * tag)873 tell_sac(char *tag)
874 {
875 pid_t pid; /* returned pid from fork */
876 int status; /* return status from sacadm child */
877
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);
883 }
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);
891 }
892 if (((status >> 8) & 0xff) == E_SACNOTRUN) {
893 Saferrno = E_SACNOTRUN;
894 } else {
895 Saferrno = E_SYSERR;
896 }
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);
903 }
904 else {
905 return(TRUE);
906 }
907 }
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);
915
916 /*
917 * if we got here, it didn't work, exit status will clue in parent to
918 * put out the warning
919 */
920
921 exit(1);
922 }
923 /* NOTREACHED */
924 }
925
926
927 /*
928 * list_svcs - list information about services
929 *
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
936 */
937
938 void
list_svcs(pmtag,type,svctag,oflag)939 list_svcs(pmtag, type, svctag, oflag)
940 char *pmtag;
941 char *type;
942 char *svctag;
943 {
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 */
952
953 fp = fopen(SACTAB, "r");
954 if (fp == NULL) {
955 Saferrno = E_SYSERR;
956 error("Could not open _sactab");
957 }
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);
962 }
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);
970 }
971 }
972 else
973 tp = find_type(fp, NULL);
974 (void) fclose(fp);
975
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;
981 }
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);
988 }
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);
1001 }
1002 else {
1003 if (nprint == 0) {
1004 (void) printf("PMTAG PMTYPE SVCTAG FLGS ID <PMSPECIFIC>\n");
1005 }
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);
1008 }
1009 nprint++;
1010 }
1011 }
1012 if (!feof(fp)) {
1013 (void) sprintf(buf, "error reading %s", fname);
1014 Saferrno = E_SYSERR;
1015 error(buf);
1016 }
1017 else {
1018 (void) fclose(fp);
1019 tp = tp->t_next;
1020 }
1021 }
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;
1029 }
1030 return;
1031 }
1032
1033
1034 /*
1035 * find_svc - find an entry in _pmtab for a particular service tag
1036 *
1037 * args: fp - file pointer for _pmtab
1038 * tag - port monitor tag (for error reporting)
1039 * svctag - tag of service we're looking for
1040 */
1041
1042 int
find_svc(FILE * fp,char * tag,char * svctag)1043 find_svc(FILE *fp, char *tag, char *svctag)
1044 {
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 */
1049
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);
1058 }
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);
1067 }
1068
1069
1070 /*
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.
1074 *
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)
1080 *
1081 * A line in the file has the following format:
1082 *
1083 * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment
1084 */
1085
1086
1087 void
parseline(p,pp,tag)1088 parseline(p, pp, tag)
1089 register char *p;
1090 register struct pmtab *pp;
1091 char *tag;
1092 {
1093 char buf[SIZE]; /* scratch buffer */
1094
1095 /*
1096 * get the service tag
1097 */
1098
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);
1104 }
1105 if (strlen(p) > PMTAGSIZE) {
1106 p[PMTAGSIZE] = '\0';
1107 (void) fprintf(stderr, "tag too long, truncated to <%s>", p);
1108 }
1109 pp->p_tag = p;
1110
1111 /*
1112 * get the flags
1113 */
1114
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);
1120 }
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;
1135 }
1136 }
1137
1138 /*
1139 * get the identity
1140 */
1141
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);
1147 }
1148 pp->p_id = p;
1149
1150 /*
1151 * get the first reserved field
1152 */
1153
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);
1159 }
1160 pp->p_res1 = p;
1161
1162 /*
1163 * get the second reserved field
1164 */
1165
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);
1171 }
1172 pp->p_res2 = p;
1173
1174 /*
1175 * get the third reserved field
1176 */
1177
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);
1183 }
1184 pp->p_res3 = p;
1185
1186 /*
1187 * the rest is the port monitor specific info
1188 */
1189
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);
1195 }
1196 pp->p_pmspec = p;
1197 return;
1198 }
1199
1200
1201 /*
1202 * pspec - format port monitor specific information
1203 *
1204 * args: spec - port monitor specific info, separated by
1205 * field separater character (may be escaped by \)
1206 */
1207
1208 char *
pspec(spec)1209 pspec(spec)
1210 char *spec;
1211 {
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 */
1216
1217 to = buf;
1218 from = spec;
1219 newflag = 1;
1220 while (*from) {
1221 switch (*from) {
1222 case ':':
1223 if (newflag) {
1224 *to++ = '-';
1225 }
1226 *to++ = ' ';
1227 from++;
1228 newflag = 1;
1229 break;
1230 case '\\':
1231 if (*(from + 1) == ':') {
1232 *to++ = ':';
1233 /* skip over \: */
1234 from += 2;
1235 }
1236 else
1237 *to++ = *from++;
1238 newflag = 0;
1239 break;
1240 default:
1241 newflag = 0;
1242 *to++ = *from++;
1243 }
1244 }
1245 *to = '\0';
1246 return(buf);
1247 }
1248
1249
1250 /*
1251 * pflags - put service flags into intelligible form for output
1252 *
1253 * args: flags - binary representation of flags
1254 * dflag - true if a "-" should be returned if no flags
1255 */
1256
1257 char *
pflags(flags,dflag)1258 pflags(flags, dflag)
1259 long flags;
1260 int dflag;
1261 {
1262 register int i; /* scratch counter */
1263 static char buf[SIZE]; /* formatted flags */
1264
1265 if (flags == 0) {
1266 if (dflag)
1267 return("-");
1268 else
1269 return("");
1270 }
1271 i = 0;
1272 if (flags & U_FLAG) {
1273 buf[i++] = 'u';
1274 flags &= ~U_FLAG;
1275 }
1276 if (flags & X_FLAG) {
1277 buf[i++] = 'x';
1278 flags &= ~X_FLAG;
1279 }
1280 if (flags) {
1281 Saferrno = E_SAFERR;
1282 error("Internal error in pflags");
1283 }
1284 buf[i] = '\0';
1285 return(buf);
1286 }
1287
1288
1289 /*
1290 * find_type - find entries in _sactab for a particular port monitor type
1291 *
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)
1295 */
1296
1297 struct taglist *
find_type(fp,type)1298 find_type(fp, type)
1299 FILE *fp;
1300 char *type;
1301 {
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 */
1308
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");
1320 }
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;
1325 }
1326 }
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);
1334 }
1335