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 #include <stdio.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include "extern.h"
37 #include "misc.h"
38 #include <sac.h>
39 #include "structs.h"
40
41 #define ADD 0x1 /* -a or other required options seen */
42 #define REMOVE 0x2 /* -r seen */
43 #define ENABLE 0x4 /* -e seen */
44 #define DISABLE 0x8 /* -d seen */
45 #define PLIST 0x10 /* -l seen */
46 #define LIST 0x20 /* -L seen */
47 #define CONFIG 0x40 /* -g seen */
48
49 # define U_FLAG 0x1 /* -fu seen */
50 # define X_FLAG 0x2 /* -fx seen */
51
52 /*
53 * functions
54 */
55
56 char *pflags();
57 char *pspec();
58 struct taglist *find_type();
59 void usage();
60 void parseline();
61 void add_svc();
62 void rem_svc();
63 void ed_svc();
64 void list_svcs();
65 void doconf();
66
67 /*
68 * format of a _pmtab entry - used to hold parsed info
69 */
70
71 struct pmtab {
72 char *p_tag; /* service tag */
73 long p_flags; /* flags */
74 char *p_id; /* logname to start service as */
75 char *p_res1; /* reserved field */
76 char *p_res2; /* reserved field */
77 char *p_res3; /* reserved field */
78 char *p_pmspec; /* port monitor specific info */
79 };
80
81 /*
82 * format of a tag list, which is a list of port monitor tags of
83 * a designated type
84 */
85
86 struct taglist {
87 struct taglist *t_next; /* next in list */
88 char t_tag[PMTAGSIZE + 1]; /* PM tag */
89 char t_type[PMTYPESIZE + 1]; /* PM type */
90 };
91
92 /*
93 * common error messages
94 */
95
96 # define NOTPRIV "User not privileged for operation"
97 # define BADINP "Embedded newlines not allowed"
98
99 int Saferrno; /* internal `errno' for exit */
100
101
102 /*
103 * main - scan args for pmadm and call appropriate handling code
104 */
105
106 int
main(int argc,char * argv[])107 main(int argc, char *argv[])
108 {
109 int c; /* option letter */
110 int ret; /* return code from check_version */
111 uid_t uid; /* invoker's real uid */
112 int flag = 0; /* flag to record requested operations */
113 int errflg = 0; /* error indicator */
114 int badcnt = 0; /* count of bad args to -f */
115 int version = -1; /* argument to -v */
116 int sawaflag = 0; /* true if actually saw -a */
117 int conflag = 0; /* true if output should be in condensed form */
118 long flags = 0; /* arguments to -f */
119 char *pmtag = NULL; /* argument to -p */
120 char *type = NULL; /* argument to -t */
121 char *script = NULL; /* argument to -z */
122 char *comment = " "; /* argument to -y */
123 char *id = NULL; /* argument to -i */
124 char *svctag = NULL; /* argument to -s */
125 char *pmspec = NULL; /* argument to -m */
126 char badargs[SIZE]; /* place to hold bad args to -f */
127 char buf[SIZE]; /* scratch buffer */
128 register char *p; /* scratch pointer */
129
130 if (argc == 1)
131 usage(argv[0]);
132 while ((c = getopt(argc, argv, "adef:gi:Llm:p:rs:t:v:y:z:")) != -1) {
133 switch (c) {
134 case 'a':
135 flag |= ADD;
136 sawaflag = 1;
137 break;
138 case 'd':
139 flag |= DISABLE;
140 break;
141 case 'e':
142 flag |= ENABLE;
143 break;
144 case 'f':
145 flag |= ADD;
146 while (*optarg) {
147 switch (*optarg++) {
148 case 'u':
149 flags |= U_FLAG;
150 break;
151 case 'x':
152 flags |= X_FLAG;
153 break;
154 default:
155 badargs[badcnt++] = *(optarg - 1);
156 break;
157 }
158 }
159 /* null terminate just in case anything is there */
160 badargs[badcnt] = '\0';
161 break;
162 case 'g':
163 flag |= CONFIG;
164 break;
165 case 'i':
166 if (strchr(optarg, '\n')) {
167 Saferrno = E_BADARGS;
168 error(BADINP);
169 }
170 flag |= ADD;
171 id = optarg;
172 break;
173 case 'L':
174 flag |= LIST;
175 break;
176 case 'l':
177 flag |= PLIST;
178 break;
179 case 'm':
180 if (strchr(optarg, '\n')) {
181 Saferrno = E_BADARGS;
182 error(BADINP);
183 }
184 if (*optarg == '\0') {
185 /* this will generate a usage message below */
186 errflg++;
187 break;
188 }
189 flag |= ADD;
190 pmspec = optarg;
191 break;
192 case 'p':
193 if (strchr(optarg, '\n')) {
194 Saferrno = E_BADARGS;
195 error(BADINP);
196 }
197 pmtag = optarg;
198 if (strlen(pmtag) > PMTAGSIZE) {
199 pmtag[PMTAGSIZE] = '\0';
200 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag);
201 }
202 for (p = pmtag; *p; p++) {
203 if (!isalnum(*p)) {
204 Saferrno = E_BADARGS;
205 error("port monitor tag must be alphanumeric");
206 }
207 }
208 break;
209 case 'r':
210 flag |= REMOVE;
211 break;
212 case 's':
213 if (strchr(optarg, '\n')) {
214 Saferrno = E_BADARGS;
215 error(BADINP);
216 }
217 svctag = optarg;
218 if (strlen(svctag) > SVCTAGSIZE) {
219 svctag[SVCTAGSIZE] = '\0';
220 (void) fprintf(stderr, "svctag too long, truncated to <%s>\n", svctag);
221 }
222 for (p = svctag; *p; p++) {
223 if (!isalnum(*p)) {
224 Saferrno = E_BADARGS;
225 error("service tag must be alphanumeric");
226 }
227 }
228 break;
229 case 't':
230 if (strchr(optarg, '\n')) {
231 Saferrno = E_BADARGS;
232 error(BADINP);
233 }
234 type = optarg;
235 if (strlen(type) > PMTYPESIZE) {
236 type[PMTYPESIZE] = '\0';
237 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type);
238 }
239 for (p = type; *p; p++) {
240 if (!isalnum(*p)) {
241 Saferrno = E_BADARGS;
242 error("port monitor type must be alphanumeric");
243 }
244 }
245 break;
246 case 'v':
247 flag |= ADD;
248 version = atoi(optarg);
249 if (version < 0) {
250 Saferrno = E_BADARGS;
251 error("version number can not be negative");
252 }
253 break;
254 case 'y':
255 if (strchr(optarg, '\n')) {
256 Saferrno = E_BADARGS;
257 error(BADINP);
258 }
259 flag |= ADD;
260 comment = optarg;
261 break;
262 case 'z':
263 if (strchr(optarg, '\n')) {
264 Saferrno = E_BADARGS;
265 error(BADINP);
266 }
267 script = optarg;
268 break;
269 case '?':
270 errflg++;
271 }
272 }
273 if (errflg || (optind < argc))
274 usage(argv[0]);
275
276 if (badcnt) {
277 /* bad flags were given to -f */
278 (void) sprintf(buf, "Invalid request, %s are not valid arguments for \"-f\"", badargs);
279 Saferrno = E_BADARGS;
280 error(buf);
281 }
282
283 uid = getuid();
284
285 /*
286 * don't do anything if _sactab isn't the version we understand
287 */
288
289 if ((ret = check_version(VERSION, SACTAB)) == 1) {
290 Saferrno = E_SAFERR;
291 error("_sactab version number is incorrect");
292 }
293 else if (ret == 2) {
294 (void) sprintf(buf, "could not open %s", SACTAB);
295 Saferrno = E_SYSERR;
296 error(buf);
297 }
298 else if (ret == 3) {
299 (void) sprintf(buf, "%s file is corrupt", SACTAB);
300 Saferrno = E_SAFERR;
301 error(buf);
302 }
303
304 switch (flag) {
305 case ADD:
306 if (uid) {
307 Saferrno = E_NOPRIV;
308 error(NOTPRIV);
309 }
310 if (!sawaflag || (pmtag && type) || (!pmtag && !type) || !svctag || !id || !pmspec || (version < 0))
311 usage(argv[0]);
312 add_svc(pmtag, type, svctag, id, pmspec, flags, version, comment, script);
313 break;
314 case REMOVE:
315 if (uid) {
316 Saferrno = E_NOPRIV;
317 error(NOTPRIV);
318 }
319 if (!pmtag || !svctag || type || script)
320 usage(argv[0]);
321 rem_svc(pmtag, svctag);
322 break;
323 case ENABLE:
324 if (uid) {
325 Saferrno = E_NOPRIV;
326 error(NOTPRIV);
327 }
328 if (!pmtag || !svctag || type || script)
329 usage(argv[0]);
330 ed_svc(pmtag, svctag, ENABLE);
331 break;
332 case DISABLE:
333 if (uid) {
334 Saferrno = E_NOPRIV;
335 error(NOTPRIV);
336 }
337 if (!pmtag || !svctag || type || script)
338 usage(argv[0]);
339 ed_svc(pmtag, svctag, DISABLE);
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_svcs(pmtag, type, svctag, conflag);
348 break;
349 case CONFIG:
350 if (script && uid) {
351 Saferrno = E_NOPRIV;
352 error(NOTPRIV);
353 }
354 if ((pmtag && type) || (!pmtag && !type) || !svctag || (type && !script))
355 usage(argv[0]);
356 doconf(script, pmtag, type, svctag);
357 break;
358 default:
359 /* we only get here if more than one flag bit was set */
360 usage(argv[0]);
361 /* NOTREACHED */
362 }
363 quit();
364 /* NOTREACHED */
365 }
366
367
368 /*
369 * usage - print out a usage message
370 *
371 * args: cmdname - the name command was invoked with
372 */
373
374 void
usage(cmdname)375 usage(cmdname)
376 char *cmdname;
377 {
378 (void) fprintf(stderr, "Usage:\t%s -a [ -p pmtag | -t type ] -s svctag -i id -m \"pmspecific\"\n", cmdname);
379 (void) fprintf(stderr, "\t\t-v version [ -f xu ] [ -y comment ] [ -z script]\n");
380 (void) fprintf(stderr, "\t%s -r -p pmtag -s svctag\n", cmdname);
381 (void) fprintf(stderr, "\t%s -e -p pmtag -s svctag\n", cmdname);
382 (void) fprintf(stderr, "\t%s -d -p pmtag -s svctag\n", cmdname);
383 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname);
384 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname);
385 (void) fprintf(stderr, "\t%s -g -p pmtag -s svctag [ -z script ]\n", cmdname);
386 (void) fprintf(stderr, "\t%s -g -s svctag -t type -z script\n", cmdname);
387 Saferrno = E_BADARGS;
388 quit();
389 }
390
391
392 /*
393 * add_svc - add a service entry
394 *
395 * args: tag - port monitor's tag (may be null)
396 * type - port monitor's type (may be null)
397 * svctag - service's tag
398 * id - identity under which service should run
399 * pmspec - uninterpreted port monitor-specific info
400 * flags - service flags
401 * version - version number of port monitor's pmtab
402 * comment - comment describing service
403 * script - service's configuration script
404 */
405
406 void
add_svc(tag,type,svctag,id,pmspec,flags,version,comment,script)407 add_svc(tag, type, svctag, id, pmspec, flags, version, comment, script)
408 char *tag;
409 char *type;
410 char *svctag;
411 char *id;
412 char *pmspec;
413 long flags;
414 int version;
415 char *comment;
416 char *script;
417 {
418 FILE *fp; /* scratch file pointer */
419 struct taglist tl; /* 'list' for degenerate case (1 PM) */
420 register struct taglist *tp = NULL; /* working pointer */
421 int ret; /* return code from check_version */
422 char buf[SIZE]; /* scratch buffer */
423 char fname[SIZE]; /* scratch buffer for building names */
424 int added; /* count number added */
425
426 fp = fopen(SACTAB, "r");
427 if (fp == NULL) {
428 Saferrno = E_SYSERR;
429 error("Could not open _sactab");
430 }
431 if (tag && !find_pm(fp, tag)) {
432 (void) sprintf(buf, "Invalid request, %s does not exist", tag);
433 Saferrno = E_NOEXIST;
434 error(buf);
435 }
436 if (type && !(tp = find_type(fp, type))) {
437 (void) sprintf(buf, "Invalid request, %s does not exist", type);
438 Saferrno = E_NOEXIST;
439 error(buf);
440 }
441 (void) fclose(fp);
442
443 if (tag) {
444
445 /*
446 * treat the case of 1 PM as a degenerate case of a list of PMs from a
447 * type specification. Build the 'list' here.
448 */
449
450 tp = &tl;
451 tp->t_next = NULL;
452 (void) strcpy(tp->t_tag, tag);
453 }
454
455 added = 0;
456 while (tp) {
457 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
458 if ((ret = check_version(version, fname)) == 1) {
459 (void) sprintf(buf, "%s version number is incorrect", fname);
460 Saferrno = E_SAFERR;
461 error(buf);
462 }
463 else if (ret == 2) {
464 (void) sprintf(buf, "could not open %s", fname);
465 Saferrno = E_SYSERR;
466 error(buf);
467 }
468 else if (ret == 3) {
469 (void) sprintf(buf, "%s file is corrupt", fname);
470 Saferrno = E_SAFERR;
471 error(buf);
472 }
473 fp = fopen(fname, "r");
474 if (fp == NULL) {
475 (void) sprintf(buf, "Could not open %s", fname);
476 Saferrno = E_SYSERR;
477 error(buf);
478 }
479 if (find_svc(fp, tp->t_tag, svctag)) {
480 if (tag) {
481 /* special case of tag only */
482 (void) sprintf(buf, "Invalid request, %s already exists under %s", svctag, tag);
483 Saferrno = E_DUP;
484 error(buf);
485 }
486 else {
487 (void) fprintf(stderr, "warning - %s already exists under %s - ignoring\n", svctag, tp->t_tag);
488 tp = tp->t_next;
489 (void) fclose(fp);
490 continue;
491 }
492 }
493 (void) fclose(fp);
494
495 /*
496 * put in the config script, if specified
497 */
498
499 if (script) {
500 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag);
501 if (do_config(script, fname)) {
502 /* do_config put out any messages */
503 tp = tp->t_next;
504 continue;
505 }
506 }
507
508 /*
509 * add the line
510 */
511
512 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
513 fp = fopen(fname, "a");
514 if (fp == NULL) {
515 (void) sprintf(buf, "Could not open %s", fname);
516 Saferrno = E_SYSERR;
517 error(buf);
518 }
519 (void) fprintf(fp, "%s:%s:%s:reserved:reserved:reserved:%s#%s\n",
520 svctag, (flags ? pflags(flags, FALSE) : ""), id, pmspec,
521 (comment ? comment : ""));
522 (void) fclose(fp);
523 added++;
524
525 /*
526 * tell the SAC to to tell PM to read _pmtab
527 */
528
529 (void) tell_sac(tp->t_tag);
530 tp = tp->t_next;
531 }
532 if (added == 0) {
533 Saferrno = E_SAFERR;
534 error("No services added");
535 }
536 return;
537 }
538
539
540 /*
541 * rem_svc - remove a service
542 *
543 * args: pmtag - tag of port monitor responsible for the service
544 * svctag - tag of the service to be removed
545 */
546
547 void
rem_svc(pmtag,svctag)548 rem_svc(pmtag, svctag)
549 char *pmtag;
550 char *svctag;
551 {
552 FILE *fp; /* scratch file pointer */
553 FILE *tfp; /* file pointer for temp file */
554 int line; /* line number entry is on */
555 char *tname; /* temp file name */
556 char buf[SIZE]; /* scratch buffer */
557 char fname[SIZE]; /* path to correct _pmtab */
558
559 fp = fopen(SACTAB, "r");
560 if (fp == NULL) {
561 Saferrno = E_SYSERR;
562 error("Could not open _sactab");
563 }
564 if (!find_pm(fp, pmtag)) {
565 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
566 Saferrno = E_NOEXIST;
567 error(buf);
568 }
569 (void) fclose(fp);
570
571 (void) sprintf(fname, "%s/_pmtab", pmtag);
572 (void) sprintf(buf, "%s/%s", HOME, fname);
573 fp = fopen(buf, "r");
574 if (fp == NULL) {
575 (void) sprintf(buf, "Could not open %s/%s", HOME, fname);
576 Saferrno = E_SYSERR;
577 error(buf);
578 }
579 if ((line = find_svc(fp, pmtag, svctag)) == 0) {
580 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag);
581 Saferrno = E_NOEXIST;
582 error(buf);
583 }
584 tname = make_tempname(fname);
585 tfp = open_temp(tname);
586 if (line != 1) {
587 if (copy_file(fp, tfp, 1, line - 1)) {
588 (void) unlink(tname);
589 Saferrno = E_SYSERR;
590 error("error accessing temp file");
591 }
592 }
593 if (copy_file(fp, tfp, line + 1, -1)) {
594 (void) unlink(tname);
595 Saferrno = E_SYSERR;
596 error("error accessing temp file");
597 }
598 (void) fclose(fp);
599 if (fclose(tfp) == EOF) {
600 (void) unlink(tname);
601 Saferrno = E_SYSERR;
602 error("error closing tempfile");
603 }
604 /* note - replace only returns if successful */
605 replace(fname, tname);
606
607 /*
608 * tell the SAC to to tell PM to read _pmtab
609 */
610
611 if (tell_sac(pmtag)) {
612
613 /*
614 * if we got rid of the service, try to remove the config script too.
615 * Don't check return status since it may not have existed anyhow.
616 */
617
618 (void) sprintf(buf, "%s/%s/%s", HOME, pmtag, svctag);
619 (void) unlink(buf);
620 return;
621 }
622 }
623
624
625
626 /*
627 * ed_svc - enable or disable a particular service
628 *
629 * args: pmtag - tag of port monitor responsible for the service
630 * svctag - tag of service to be enabled or disabled
631 * flag - operation to perform (ENABLE or DISABLE)
632 */
633
634 void
ed_svc(pmtag,svctag,flag)635 ed_svc(pmtag, svctag, flag)
636 char *pmtag;
637 char *svctag;
638 int flag;
639 {
640 FILE *fp; /* scratch file pointer */
641 FILE *tfp; /* file pointer for temp file */
642 int line; /* line number entry is on */
643 register char *from; /* working pointer */
644 register char *to; /* working pointer */
645 char *tname; /* temp file name */
646 char *p; /* scratch pointer */
647 char buf[SIZE]; /* scratch buffer */
648 char tbuf[SIZE]; /* scratch buffer */
649 char fname[SIZE]; /* path to correct _pmtab */
650
651 fp = fopen(SACTAB, "r");
652 if (fp == NULL) {
653 Saferrno = E_SYSERR;
654 error("Could not open _sactab");
655 }
656 if (!find_pm(fp, pmtag)) {
657 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
658 Saferrno = E_NOEXIST;
659 error(buf);
660 }
661 (void) fclose(fp);
662
663 (void) sprintf(fname, "%s/_pmtab", pmtag);
664 (void) sprintf(buf, "%s/%s", HOME, fname);
665 fp = fopen(buf, "r");
666 if (fp == NULL) {
667 (void) sprintf(buf, "Could not open %s/%s", HOME, fname);
668 Saferrno = E_SYSERR;
669 error(buf);
670 }
671 if ((line = find_svc(fp, pmtag, svctag)) == 0) {
672 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag);
673 Saferrno = E_NOEXIST;
674 error(buf);
675 }
676 tname = make_tempname(fname);
677 tfp = open_temp(tname);
678 if (line != 1) {
679 if (copy_file(fp, tfp, 1, line - 1)) {
680 (void) unlink(tname);
681 Saferrno = E_SYSERR;
682 error("error accessing temp file");
683 }
684 }
685
686 /*
687 * Note: find_svc above has already read and parsed this entry, thus
688 * we know it to be well-formed, so just change the flags as appropriate
689 */
690
691 if (fgets(buf, SIZE, fp) == NULL) {
692 (void) unlink(tname);
693 Saferrno = E_SYSERR;
694 error("error accessing temp file");
695 }
696 from = buf;
697 to = tbuf;
698
699 /*
700 * copy initial portion of entry
701 */
702
703 p = strchr(from, DELIMC);
704 for ( ; from <= p; )
705 *to++ = *from++;
706
707 /*
708 * isolate and fix the flags
709 */
710
711 p = strchr(from, DELIMC);
712 for ( ; from < p; ) {
713 if (*from == 'x') {
714 from++;
715 continue;
716 }
717 *to++ = *from++;
718 }
719
720 /*
721 * above we removed x flag, if this was a disable operation, stick it in
722 * and also copy the field delimiter
723 */
724
725 if (flag == DISABLE)
726 *to++ = 'x';
727 *to++ = *from++;
728
729 /*
730 * copy the rest of the line
731 */
732
733 for ( ; from < &buf[SIZE - 1] ;)
734 *to++ = *from++;
735 /*** *to = '\0'; BUG: Don't uncomment it ****/
736
737 (void) fprintf(tfp, "%s", tbuf);
738
739 if (copy_file(fp, tfp, line + 1, -1)) {
740 (void) unlink(tname);
741 Saferrno = E_SYSERR;
742 error("error accessing temp file");
743 }
744 (void) fclose(fp);
745 if (fclose(tfp) == EOF) {
746 (void) unlink(tname);
747 Saferrno = E_SYSERR;
748 error("error closing tempfile");
749 }
750 /* note - replace only returns if successful */
751 replace(fname, tname);
752
753
754 /*
755 * tell the SAC to to tell PM to read _pmtab
756 */
757
758 (void) tell_sac(pmtag);
759 }
760
761
762 /*
763 * doconf - take a config script and have it put where it belongs or
764 * output an existing one
765 *
766 * args: script - name of file containing script (if NULL, means
767 * output existing one instead)
768 * tag - tag of port monitor that is responsible for the
769 * designated service (may be null)
770 * type - type of port monitor that is responsible for the
771 * designated service (may be null)
772 * svctag - tag of service whose config script we're operating on
773 */
774
775 void
doconf(script,tag,type,svctag)776 doconf(script, tag, type, svctag)
777 char *script;
778 char *tag;
779 char *type;
780 char *svctag;
781 {
782 FILE *fp; /* scratch file pointer */
783 int added; /* count of config scripts added */
784 struct taglist tl; /* 'list' for degenerate case (1 PM) */
785 register struct taglist *tp = NULL; /* working pointer */
786 char buf[SIZE]; /* scratch buffer */
787 char fname[SIZE]; /* scratch buffer for names */
788
789 fp = fopen(SACTAB, "r");
790 if (fp == NULL) {
791 Saferrno = E_SYSERR;
792 error("Could not open _sactab");
793 }
794 if (tag && !find_pm(fp, tag)) {
795 (void) sprintf(buf, "Invalid request, %s does not exist", tag);
796 Saferrno = E_NOEXIST;
797 error(buf);
798 }
799 if (type && !(tp = find_type(fp, type))) {
800 (void) sprintf(buf, "Invalid request, %s does not exist", type);
801 Saferrno = E_NOEXIST;
802 error(buf);
803 }
804 (void) fclose(fp);
805
806 if (tag) {
807
808 /*
809 * treat the case of 1 PM as a degenerate case of a list of PMs from a
810 * type specification. Build the 'list' here.
811 */
812
813 tp = &tl;
814 tp->t_next = NULL;
815 (void) strcpy(tp->t_tag, tag);
816 }
817
818 added = 0;
819 while (tp) {
820 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
821 fp = fopen(fname, "r");
822 if (fp == NULL) {
823 (void) sprintf(buf, "Could not open %s", fname);
824 Saferrno = E_SYSERR;
825 error(buf);
826 }
827 if (!find_svc(fp, tp->t_tag, svctag)) {
828 if (tag) {
829 /* special case of tag only */
830 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, tag);
831 Saferrno = E_NOEXIST;
832 error(buf);
833 }
834 else {
835 (void) fprintf(stderr, "warning - %s does not exist under %s - ignoring\n", svctag, tp->t_tag);
836 Saferrno = E_NOEXIST;
837 tp = tp->t_next;
838 (void) fclose(fp);
839 continue;
840 }
841 }
842 (void) fclose(fp);
843
844 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag);
845
846 /*
847 * do_config does all the real work (keep track if any errors occurred)
848 */
849
850 if (do_config(script, fname) == 0)
851 added++;
852 tp = tp->t_next;
853 }
854 if (added == 0) {
855 Saferrno = E_SAFERR;
856 error("No configuration scripts installed");
857 }
858 return;
859 }
860
861
862 /*
863 * tell_sac - use sacadm to tell the sac to tell a port monitor to read
864 * its _pmtab. Return TRUE on success, FALSE on failure.
865 *
866 * args: tag - tag of port monitor to be notified
867 */
868
869
870 int
tell_sac(char * tag)871 tell_sac(char *tag)
872 {
873 pid_t pid; /* returned pid from fork */
874 int status; /* return status from sacadm child */
875
876 if ((pid = fork()) < 0) {
877 (void) fprintf(stderr, "warning - fork failed - could not notify <%s> about modified table\n", tag);
878 (void) fprintf(stderr, "try executing the command \"sacadm -x -p %s\"\n", tag);
879 Saferrno = E_SYSERR;
880 return(FALSE);
881 }
882 else if (pid) {
883 /* parent */
884 (void) wait(&status);
885 if (status) {
886 if (((status >> 8) & 0xff) == E_PMNOTRUN) {
887 (void) fprintf(stderr, "warning - port monitor, %s is not running\n", tag);
888 return (FALSE);
889 }
890 if (((status >> 8) & 0xff) == E_SACNOTRUN) {
891 Saferrno = E_SACNOTRUN;
892 } else {
893 Saferrno = E_SYSERR;
894 }
895 (void) fprintf(stderr,
896 "warning - could not notify <%s> about modified"
897 " table\n", tag);
898 (void) fprintf(stderr, "try executing the command"
899 " \"sacadm -x -p %s\"\n", tag);
900 return(FALSE);
901 }
902 else {
903 return(TRUE);
904 }
905 }
906 else {
907 /* set IFS for security */
908 (void) putenv("IFS=\" \"");
909 /* muffle sacadm warning messages */
910 (void) fclose(stderr);
911 (void) fopen("/dev/null", "w");
912 (void) execl("/usr/sbin/sacadm", "sacadm", "-x", "-p", tag, 0);
913
914 /*
915 * if we got here, it didn't work, exit status will clue in parent to
916 * put out the warning
917 */
918
919 exit(1);
920 }
921 /* NOTREACHED */
922 }
923
924
925 /*
926 * list_svcs - list information about services
927 *
928 * args: pmtag - tag of port monitor responsible for the service
929 * (may be null)
930 * type - type of port monitor responsible for the service
931 * (may be null)
932 * svctag - tag of service to be listed (may be null)
933 * oflag - true if output should be easily parseable
934 */
935
936 void
list_svcs(char * pmtag,char * type,char * svctag,int oflag)937 list_svcs(char *pmtag, char *type, char *svctag, int oflag)
938 {
939 FILE *fp; /* scratch file pointer */
940 register struct taglist *tp; /* pointer to PM list */
941 int nprint = 0; /* count # of svcs printed */
942 struct pmtab pmtab; /* place to hold parsed info */
943 register struct pmtab *pp = &pmtab; /* and a pointer to it */
944 register char *p; /* working pointer */
945 char buf[SIZE]; /* scratch buffer */
946 char fname[SIZE]; /* scratch buffer for building names */
947
948 fp = fopen(SACTAB, "r");
949 if (fp == NULL) {
950 Saferrno = E_SYSERR;
951 error("Could not open _sactab");
952 }
953 if (pmtag && !find_pm(fp, pmtag)) {
954 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
955 Saferrno = E_NOEXIST;
956 error(buf);
957 }
958 rewind(fp);
959 if (type) {
960 tp = find_type(fp, type);
961 if (tp == NULL) {
962 (void) sprintf(buf, "Invalid request, %s does not exist", type);
963 Saferrno = E_NOEXIST;
964 error(buf);
965 }
966 }
967 else
968 tp = find_type(fp, NULL);
969 (void) fclose(fp);
970
971 while (tp) {
972 if (pmtag && strcmp(tp->t_tag, pmtag)) {
973 /* not interested in this port monitor */
974 tp = tp->t_next;
975 continue;
976 }
977 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag);
978 fp = fopen(fname, "r");
979 if (fp == NULL) {
980 (void) sprintf(buf, "Could not open %s", fname);
981 Saferrno = E_SYSERR;
982 error(buf);
983 }
984 while (fgets(buf, SIZE, fp)) {
985 p = trim(buf);
986 if (*p == '\0')
987 continue;
988 parseline(p, pp, tp->t_tag);
989 if (!svctag || !strcmp(pp->p_tag, svctag)) {
990 if (oflag) {
991 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s#%s\n",
992 tp->t_tag, tp->t_type, pp->p_tag,
993 pflags(pp->p_flags, FALSE),
994 pp->p_id, pp->p_res1, pp->p_res2,
995 pp->p_res3,pp->p_pmspec, Comment);
996 }
997 else {
998 if (nprint == 0) {
999 (void) printf("PMTAG PMTYPE SVCTAG FLGS ID <PMSPECIFIC>\n");
1000 }
1001 (void) printf("%-14s %-14s %-14s %-4s %-8s %s #%s\n", tp->t_tag, tp->t_type, pp->p_tag,
1002 pflags(pp->p_flags, TRUE), pp->p_id, pspec(pp->p_pmspec), Comment);
1003 }
1004 nprint++;
1005 }
1006 }
1007 if (!feof(fp)) {
1008 (void) sprintf(buf, "error reading %s", fname);
1009 Saferrno = E_SYSERR;
1010 error(buf);
1011 }
1012 else {
1013 (void) fclose(fp);
1014 tp = tp->t_next;
1015 }
1016 }
1017 /* if we didn't find any valid ones, indicate an error */
1018 if (nprint == 0) {
1019 if (svctag)
1020 (void) fprintf(stderr, "Service <%s> does not exist\n", svctag);
1021 else
1022 (void) fprintf(stderr, "No services defined\n");
1023 Saferrno = E_NOEXIST;
1024 }
1025 return;
1026 }
1027
1028
1029 /*
1030 * find_svc - find an entry in _pmtab for a particular service tag
1031 *
1032 * args: fp - file pointer for _pmtab
1033 * tag - port monitor tag (for error reporting)
1034 * svctag - tag of service we're looking for
1035 */
1036
1037 int
find_svc(FILE * fp,char * tag,char * svctag)1038 find_svc(FILE *fp, char *tag, char *svctag)
1039 {
1040 register char *p; /* working pointer */
1041 int line = 0; /* line number we found entry on */
1042 struct pmtab pmtab; /* place to hold parsed info */
1043 static char buf[SIZE]; /* scratch buffer */
1044
1045 while (fgets(buf, SIZE, fp)) {
1046 line++;
1047 p = trim(buf);
1048 if (*p == '\0')
1049 continue;
1050 parseline(p, &pmtab, tag);
1051 if (!(strcmp(pmtab.p_tag, svctag)))
1052 return(line);
1053 }
1054 if (!feof(fp)) {
1055 (void) sprintf(buf, "error reading %s/%s/_pmtab", HOME, tag);
1056 Saferrno = E_SYSERR;
1057 error(buf);
1058 /* NOTREACHED */
1059 return (0);
1060 } else
1061 return (0);
1062 }
1063
1064
1065 /*
1066 * parseline - parse a line from _pmtab. This routine will return if the
1067 * parse wa successful, otherwise it will output an error and
1068 * exit.
1069 *
1070 * args: p - pointer to the data read from the file (note - this is
1071 * a static data region, so we can point into it)
1072 * pp - pointer to a structure in which the separated fields
1073 * are placed
1074 * tag - port monitor tag (for error reporting)
1075 *
1076 * A line in the file has the following format:
1077 *
1078 * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment
1079 */
1080
1081
1082 void
parseline(p,pp,tag)1083 parseline(p, pp, tag)
1084 register char *p;
1085 register struct pmtab *pp;
1086 char *tag;
1087 {
1088 char buf[SIZE]; /* scratch buffer */
1089
1090 /*
1091 * get the service tag
1092 */
1093
1094 p = nexttok(p, DELIM, FALSE);
1095 if (p == NULL) {
1096 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1097 Saferrno = E_SAFERR;
1098 error(buf);
1099 }
1100 if (strlen(p) > PMTAGSIZE) {
1101 p[PMTAGSIZE] = '\0';
1102 (void) fprintf(stderr, "tag too long, truncated to <%s>", p);
1103 }
1104 pp->p_tag = p;
1105
1106 /*
1107 * get the flags
1108 */
1109
1110 p = nexttok(NULL, DELIM, FALSE);
1111 if (p == NULL) {
1112 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1113 Saferrno = E_SAFERR;
1114 error(buf);
1115 }
1116 pp->p_flags = 0;
1117 while (*p) {
1118 switch (*p++) {
1119 case 'u':
1120 pp->p_flags |= U_FLAG;
1121 break;
1122 case 'x':
1123 pp->p_flags |= X_FLAG;
1124 break;
1125 default:
1126 (void) sprintf(buf, "Unrecognized flag <%c>", *(p - 1));
1127 Saferrno = E_SAFERR;
1128 error(buf);
1129 break;
1130 }
1131 }
1132
1133 /*
1134 * get the identity
1135 */
1136
1137 p = nexttok(NULL, DELIM, FALSE);
1138 if (p == NULL) {
1139 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1140 Saferrno = E_SAFERR;
1141 error(buf);
1142 }
1143 pp->p_id = p;
1144
1145 /*
1146 * get the first reserved field
1147 */
1148
1149 p = nexttok(NULL, DELIM, FALSE);
1150 if (p == NULL) {
1151 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1152 Saferrno = E_SAFERR;
1153 error(buf);
1154 }
1155 pp->p_res1 = p;
1156
1157 /*
1158 * get the second reserved field
1159 */
1160
1161 p = nexttok(NULL, DELIM, FALSE);
1162 if (p == NULL) {
1163 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1164 Saferrno = E_SAFERR;
1165 error(buf);
1166 }
1167 pp->p_res2 = p;
1168
1169 /*
1170 * get the third reserved field
1171 */
1172
1173 p = nexttok(NULL, DELIM, FALSE);
1174 if (p == NULL) {
1175 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1176 Saferrno = E_SAFERR;
1177 error(buf);
1178 }
1179 pp->p_res3 = p;
1180
1181 /*
1182 * the rest is the port monitor specific info
1183 */
1184
1185 p = nexttok(NULL, DELIM, TRUE);
1186 if (p == NULL) {
1187 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag);
1188 Saferrno = E_SAFERR;
1189 error(buf);
1190 }
1191 pp->p_pmspec = p;
1192 return;
1193 }
1194
1195
1196 /*
1197 * pspec - format port monitor specific information
1198 *
1199 * args: spec - port monitor specific info, separated by
1200 * field separater character (may be escaped by \)
1201 */
1202
1203 char *
pspec(spec)1204 pspec(spec)
1205 char *spec;
1206 {
1207 static char buf[SIZE]; /* returned string */
1208 register char *from; /* working pointer */
1209 register char *to; /* working pointer */
1210 int newflag; /* flag indicating new field */
1211
1212 to = buf;
1213 from = spec;
1214 newflag = 1;
1215 while (*from) {
1216 switch (*from) {
1217 case ':':
1218 if (newflag) {
1219 *to++ = '-';
1220 }
1221 *to++ = ' ';
1222 from++;
1223 newflag = 1;
1224 break;
1225 case '\\':
1226 if (*(from + 1) == ':') {
1227 *to++ = ':';
1228 /* skip over \: */
1229 from += 2;
1230 }
1231 else
1232 *to++ = *from++;
1233 newflag = 0;
1234 break;
1235 default:
1236 newflag = 0;
1237 *to++ = *from++;
1238 }
1239 }
1240 *to = '\0';
1241 return(buf);
1242 }
1243
1244
1245 /*
1246 * pflags - put service flags into intelligible form for output
1247 *
1248 * args: flags - binary representation of flags
1249 * dflag - true if a "-" should be returned if no flags
1250 */
1251
1252 char *
pflags(flags,dflag)1253 pflags(flags, dflag)
1254 long flags;
1255 int dflag;
1256 {
1257 register int i; /* scratch counter */
1258 static char buf[SIZE]; /* formatted flags */
1259
1260 if (flags == 0) {
1261 if (dflag)
1262 return("-");
1263 else
1264 return("");
1265 }
1266 i = 0;
1267 if (flags & U_FLAG) {
1268 buf[i++] = 'u';
1269 flags &= ~U_FLAG;
1270 }
1271 if (flags & X_FLAG) {
1272 buf[i++] = 'x';
1273 flags &= ~X_FLAG;
1274 }
1275 if (flags) {
1276 Saferrno = E_SAFERR;
1277 error("Internal error in pflags");
1278 }
1279 buf[i] = '\0';
1280 return(buf);
1281 }
1282
1283
1284 /*
1285 * find_type - find entries in _sactab for a particular port monitor type
1286 *
1287 * args: fp - file pointer for _sactab
1288 * type - type of port monitor we're looking for (if type is
1289 * null, it means find all PMs)
1290 */
1291
1292 struct taglist *
find_type(fp,type)1293 find_type(fp, type)
1294 FILE *fp;
1295 char *type;
1296 {
1297 register char *p; /* working pointer */
1298 struct sactab stab; /* place to hold parsed info */
1299 register struct sactab *sp = &stab; /* and a pointer to it */
1300 char buf[SIZE]; /* scratch buffer */
1301 struct taglist *thead; /* linked list of tags */
1302 register struct taglist *temp; /* scratch pointer */
1303
1304 thead = NULL;
1305 while (fgets(buf, SIZE, fp)) {
1306 p = trim(buf);
1307 if (*p == '\0')
1308 continue;
1309 parse(p, sp);
1310 if ((type == NULL) || !(strcmp(sp->sc_type, type))) {
1311 temp = (struct taglist *) malloc(sizeof(struct taglist));
1312 if (temp == NULL) {
1313 Saferrno = E_SYSERR;
1314 error("malloc failed");
1315 }
1316 temp->t_next = thead;
1317 (void) strcpy(temp->t_tag, sp->sc_tag);
1318 (void) strcpy(temp->t_type, sp->sc_type);
1319 thead = temp;
1320 }
1321 }
1322 if (!feof(fp)) {
1323 Saferrno = E_SYSERR;
1324 error("error reading _sactab");
1325 /* NOTREACHED */
1326 return (0);
1327 } else
1328 return (thead ? thead : NULL);
1329 }
1330