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 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <pwd.h>
39 #include <grp.h>
40 #include <signal.h>
41 #include "ttymon.h"
42 #include "tmstruct.h"
43 #include "tmextern.h"
44
45 extern char *strsave();
46 extern void set_softcar();
47 extern int vml();
48 void purge();
49 static int get_flags();
50 static int get_ttyflags();
51 static int same_entry();
52 static int check_pmtab();
53 static void insert_pmtab();
54 static void free_pmtab();
55 static char *expand();
56
57 int check_identity();
58
59 int strcheck();
60
61 /*
62 * read_pmtab()
63 * - read and parse pmtab
64 * - store table in linked list pointed by global variable "PMtab"
65 * - exit if file does not exist or error detected.
66 */
67 void
read_pmtab()68 read_pmtab()
69 {
70 register struct pmtab *gptr;
71 register char *ptr, *wptr;
72 FILE *fp;
73 int input, state, size, rawc, field, linenum;
74 char oldc;
75 char line[BUFSIZ];
76 char wbuf[BUFSIZ];
77 static char *states[] = {
78 "","tag","flags","identity","reserved1","reserved2","reserved3",
79 "device","ttyflags","count","service", "timeout","ttylabel",
80 "modules","prompt","disable msg","terminal type","soft-carrier"
81 };
82
83 # ifdef DEBUG
84 debug("in read_pmtab");
85 # endif
86
87 if ((fp = fopen(PMTABFILE,"r")) == NULL) {
88 fatal("open pmtab (%s) failed", PMTABFILE);
89 }
90
91 Nentries = 0;
92 if (check_version(PMTAB_VERS, PMTABFILE) != 0)
93 fatal("check pmtab version failed");
94
95 for (gptr = PMtab; gptr; gptr = gptr->p_next) {
96 if ((gptr->p_status == SESSION) ||
97 (gptr->p_status == LOCKED) ||
98 (gptr->p_status == UNACCESS)) {
99 if (gptr->p_fd > 0) {
100 (void)close(gptr->p_fd);
101 gptr->p_fd = 0;
102 }
103 gptr->p_inservice = gptr->p_status;
104 }
105 gptr->p_status = NOTVALID;
106 }
107
108 wptr = wbuf;
109 input = ACTIVE;
110 linenum = 0;
111 do {
112 linenum++;
113 line[0] = '\0';
114 for (ptr= line,oldc = '\0'; ptr < &line[sizeof(line)-1] &&
115 (rawc=getc(fp))!= '\n' && rawc != EOF; ptr++,oldc=(char)rawc){
116 if ((rawc == '#') && (oldc != '\\'))
117 break;
118 *ptr = (char)rawc;
119 }
120 *ptr = '\0';
121
122 /* skip rest of the line */
123 if (rawc != EOF && rawc != '\n') {
124 if (rawc != '#')
125 log("Entry too long.\n");
126 while ((rawc = getc(fp)) != EOF && rawc != '\n')
127 ;
128 }
129
130 if (rawc == EOF) {
131 if (ptr == line) break;
132 else input = FINISHED;
133 }
134
135 /* if empty line, skip */
136 for (ptr=line; *ptr != '\0' && isspace(*ptr); ptr++)
137 ;
138 if (*ptr == '\0') continue;
139
140 #ifdef DEBUG
141 debug("**** Next Entry ****\n%s", line);
142 #endif
143 log("Processing pmtab line #%d", linenum);
144
145 /* Now we have the complete line */
146
147 if ((gptr = ALLOC_PMTAB) == PNULL)
148 fatal("memory allocation failed");
149
150 /* set hangup flag, this is the default */
151 gptr->p_ttyflags |= H_FLAG;
152
153 /*
154 * For compatibility reasons, we cannot rely on these
155 * having values assigned from pmtab.
156 */
157 gptr->p_termtype = "";
158 gptr->p_softcar = "";
159
160 for (state=P_TAG,ptr=line;state !=FAILURE && state !=SUCCESS;) {
161 switch(state) {
162 case P_TAG:
163 gptr->p_tag = strsave(getword(ptr,&size,0));
164 break;
165 case P_FLAGS:
166 (void)strcpy(wptr, getword(ptr,&size,0));
167 if ((get_flags(wptr, &gptr->p_flags)) != 0) {
168 field = state;
169 state = FAILURE;
170 }
171 break;
172 case P_IDENTITY:
173 gptr->p_identity=strsave(getword(ptr,&size,0));
174 break;
175 case P_RES1:
176 gptr->p_res1=strsave(getword(ptr,&size,0));
177 break;
178 case P_RES2:
179 gptr->p_res2=strsave(getword(ptr,&size,0));
180 break;
181 case P_RES3:
182 gptr->p_res3=strsave(getword(ptr,&size,0));
183 break;
184 case P_DEVICE:
185 gptr->p_device = strsave(getword(ptr,&size,0));
186 break;
187 case P_TTYFLAGS:
188 (void)strcpy(wptr, getword(ptr,&size,0));
189 if ((get_ttyflags(wptr,&gptr->p_ttyflags))!=0) {
190 field = state;
191 state = FAILURE;
192 }
193 break;
194 case P_COUNT:
195 (void)strcpy(wptr, getword(ptr,&size,0));
196 if (strcheck(wptr, NUM) != 0) {
197 log("wait_read count must be a positive number");
198 field = state;
199 state = FAILURE;
200 }
201 else
202 gptr->p_count = atoi(wptr);
203 break;
204 case P_SERVER:
205 gptr->p_server =
206 strsave(expand(getword(ptr,&size,1),
207 gptr->p_device));
208 break;
209 case P_TIMEOUT:
210 (void)strcpy(wptr, getword(ptr,&size,0));
211 if (strcheck(wptr, NUM) != 0) {
212 log("timeout value must be a positive number");
213 field = state;
214 state = FAILURE;
215 }
216 else
217 gptr->p_timeout = atoi(wptr);
218 break;
219 case P_TTYLABEL:
220 gptr->p_ttylabel=strsave(getword(ptr,&size,0));
221 break;
222 case P_MODULES:
223 gptr->p_modules = strsave(getword(ptr,&size,0));
224 if (vml(gptr->p_modules) != 0) {
225 field = state;
226 state = FAILURE;
227 }
228 break;
229 case P_PROMPT:
230 gptr->p_prompt = strsave(getword(ptr,&size,TRUE));
231 break;
232 case P_DMSG:
233 gptr->p_dmsg = strsave(getword(ptr,&size,TRUE));
234 break;
235
236 case P_TERMTYPE:
237 gptr->p_termtype = strsave(getword(ptr,&size,TRUE));
238 break;
239
240 case P_SOFTCAR:
241 gptr->p_softcar = strsave(getword(ptr,&size,TRUE));
242 break;
243
244 } /* end switch */
245 ptr += size;
246 if (state == FAILURE)
247 break;
248 if (*ptr == ':') {
249 ptr++; /* Skip the ':' */
250 state++ ;
251 } else if (*ptr != '\0') {
252 field = state;
253 state = FAILURE;
254 }
255 if (*ptr == '\0') {
256 /*
257 * Maintain compatibility with older ttymon
258 * pmtab files. If Sun-added fields are
259 * missing, this should not be an error.
260 */
261 if (state > P_DMSG) {
262 state = SUCCESS;
263 } else {
264 field = state;
265 state = FAILURE;
266 }
267 }
268 } /* end for loop */
269
270 if (state == SUCCESS) {
271 if (check_pmtab(gptr) == 0) {
272 if (Nentries < Maxfds)
273 insert_pmtab(gptr);
274 else {
275 log("can't add more entries to "
276 "pmtab, Maxfds = %d", Maxfds);
277 free_pmtab(gptr);
278 (void)fclose(fp);
279 return;
280 }
281 }
282 else {
283 log("Parsing failure for entry: \n%s", line);
284 log("-------------------------------------------");
285 free_pmtab(gptr);
286 }
287 } else {
288 *++ptr = '\0';
289 log("Parsing failure in the \"%s\" field,\n%s"
290 "<--error detected here", states[field], line);
291 log("-------------------------------------------");
292 free_pmtab(gptr);
293 }
294 } while (input == ACTIVE);
295
296 (void)fclose(fp);
297 return;
298 }
299
300 /*
301 * get_flags - scan flags field to set U_FLAG and X_FLAG
302 */
303 static int
get_flags(wptr,flags)304 get_flags(wptr, flags)
305 char *wptr; /* pointer to the input string */
306 long *flags; /* pointer to the flag to set */
307 {
308 register char *p;
309 for (p = wptr; *p; p++) {
310 switch (*p) {
311 case 'x':
312 *flags |= X_FLAG;
313 break;
314 case 'u':
315 *flags |= U_FLAG;
316 break;
317 default:
318 log("Invalid flag -- %c", *p);
319 return(-1);
320 }
321 }
322 return(0);
323 }
324
325 /*
326 * get_ttyflags - scan ttyflags field to set corresponding flags
327 */
328 static int
get_ttyflags(wptr,ttyflags)329 get_ttyflags(wptr, ttyflags)
330 char *wptr; /* pointer to the input string */
331 long *ttyflags; /* pointer to the flag to be set*/
332 {
333 register char *p;
334 for (p = wptr; *p; p++) {
335 switch (*p) {
336 case 'c':
337 *ttyflags |= C_FLAG;
338 break;
339 case 'h': /* h means don't hangup */
340 *ttyflags &= ~H_FLAG;
341 break;
342 case 'b':
343 *ttyflags |= B_FLAG;
344 break;
345 case 'r':
346 *ttyflags |= R_FLAG;
347 break;
348 case 'I':
349 *ttyflags |= I_FLAG;
350 break;
351 default:
352 log("Invalid ttyflag -- %c", *p);
353 return(-1);
354 }
355 }
356 return(0);
357 }
358
359 # ifdef DEBUG
360 /*
361 * pflags - put service flags into intelligible form for output
362 */
363
364 char *
pflags(flags)365 pflags(flags)
366 long flags; /* binary representation of the flags */
367 {
368 register int i; /* scratch counter */
369 static char buf[BUFSIZ]; /* formatted flags */
370
371 if (flags == 0)
372 return("-");
373 i = 0;
374 if (flags & U_FLAG) {
375 buf[i++] = 'u';
376 flags &= ~U_FLAG;
377 }
378 if (flags & X_FLAG) {
379 buf[i++] = 'x';
380 flags &= ~X_FLAG;
381 }
382 if (flags)
383 log("Internal error in pflags");
384 buf[i] = '\0';
385 return(buf);
386 }
387
388 /*
389 * pttyflags - put ttyflags into intelligible form for output
390 */
391
392 char *
pttyflags(flags)393 pttyflags(flags)
394 long flags; /* binary representation of ttyflags */
395 {
396 register int i; /* scratch counter */
397 static char buf[BUFSIZ]; /* formatted flags */
398
399 if (flags == 0)
400 return("h");
401 i = 0;
402 if (flags & C_FLAG) {
403 buf[i++] = 'c';
404 flags &= ~C_FLAG;
405 }
406 if (flags & H_FLAG)
407 flags &= ~H_FLAG;
408 else
409 buf[i++] = 'h';
410 if (flags & B_FLAG) {
411 buf[i++] = 'b';
412 flags &= ~B_FLAG;
413 }
414 if (flags & R_FLAG) {
415 buf[i++] = 'r';
416 flags &= ~B_FLAG;
417 }
418 if (flags & I_FLAG) {
419 buf[i++] = 'I';
420 flags &= ~I_FLAG;
421 }
422 if (flags)
423 log("Internal error in p_ttyflags");
424 buf[i] = '\0';
425 return(buf);
426 }
427
428 void
dump_pmtab()429 dump_pmtab()
430 {
431 struct pmtab *gptr;
432
433 debug("in dump_pmtab");
434 log("********** dumping pmtab **********");
435 log(" ");
436 for (gptr=PMtab; gptr; gptr = gptr->p_next) {
437 log("-------------------------------------------");
438 log("tag:\t\t%s", gptr->p_tag);
439 log("flags:\t\t%s",pflags(gptr->p_flags));
440 log("identity:\t%s", gptr->p_identity);
441 log("reserved1:\t%s", gptr->p_res1);
442 log("reserved2:\t%s", gptr->p_res2);
443 log("reserved3:\t%s", gptr->p_res3);
444 log("device:\t%s", gptr->p_device);
445 log("ttyflags:\t%s",pttyflags(gptr->p_ttyflags));
446 log("count:\t\t%d", gptr->p_count);
447 log("server:\t%s", gptr->p_server);
448 log("timeout:\t%d", gptr->p_timeout);
449 log("ttylabel:\t%s", gptr->p_ttylabel);
450 log("modules:\t%s", gptr->p_modules);
451 log("prompt:\t%s", gptr->p_prompt);
452 log("disable msg:\t%s", gptr->p_dmsg);
453 log("terminal type:\t%s", gptr->p_termtype);
454 log("soft-carrier:\t%s", gptr->p_softcar);
455 log("status:\t\t%d", gptr->p_status);
456 log("inservice:\t%d", gptr->p_inservice);
457 log("fd:\t\t%d", gptr->p_fd);
458 log("pid:\t\t%ld", gptr->p_pid);
459 log("uid:\t\t%ld", gptr->p_uid);
460 log("gid:\t\t%ld", gptr->p_gid);
461 log("dir:\t%s", gptr->p_dir);
462 log(" ");
463 }
464 log("********** end dumping pmtab **********");
465 }
466 # endif
467
468 /*
469 * same_entry(e1,e2) - compare 2 entries of pmtab
470 * if the fields are different, copy e2 to e1
471 * return 1 if same, return 0 if different
472 */
473 static int
same_entry(e1,e2)474 same_entry(e1,e2)
475 struct pmtab *e1,*e2;
476 {
477
478 if (strcmp(e1->p_identity, e2->p_identity) != 0)
479 return(0);
480 if (strcmp(e1->p_res1, e2->p_res1) != 0)
481 return(0);
482 if (strcmp(e1->p_res2, e2->p_res2) != 0)
483 return(0);
484 if (strcmp(e1->p_res3, e2->p_res3) != 0)
485 return(0);
486 if (strcmp(e1->p_device, e2->p_device) != 0)
487 return(0);
488 if (strcmp(e1->p_server, e2->p_server) != 0)
489 return(0);
490 if (strcmp(e1->p_ttylabel, e2->p_ttylabel) != 0)
491 return(0);
492 if (strcmp(e1->p_modules, e2->p_modules) != 0)
493 return(0);
494 if (strcmp(e1->p_prompt, e2->p_prompt) != 0)
495 return(0);
496 if (strcmp(e1->p_dmsg, e2->p_dmsg) != 0)
497 return(0);
498 if (strcmp(e1->p_termtype, e2->p_termtype) != 0)
499 return(0);
500 if (strcmp(e1->p_softcar, e2->p_softcar) != 0)
501 return(0);
502 if (e1->p_flags != e2->p_flags)
503 return(0);
504 /*
505 * compare lowest 4 bits only,
506 * because A_FLAG is not part of original ttyflags
507 */
508 if ((e1->p_ttyflags & ~A_FLAG) != (e2->p_ttyflags & ~A_FLAG))
509 return(0);
510 if (e1->p_count != e2->p_count)
511 return(0);
512 if (e1->p_timeout != e2->p_timeout)
513 return(0);
514 if (e1->p_uid != e2->p_uid)
515 return(0);
516 if (e1->p_gid != e2->p_gid)
517 return(0);
518 if (strcmp(e1->p_dir, e2->p_dir) != 0)
519 return(0);
520 return(1);
521 }
522
523
524 /*
525 * insert_pmtab - insert a pmtab entry into the linked list
526 */
527
528 static void
insert_pmtab(sp)529 insert_pmtab(sp)
530 register struct pmtab *sp; /* ptr to entry to be inserted */
531 {
532 register struct pmtab *tsp, *savtsp; /* scratch pointers */
533 int ret; /* strcmp return value */
534
535 # ifdef DEBUG
536 debug("in insert_pmtab");
537 # endif
538 savtsp = tsp = PMtab;
539
540 /*
541 * find the correct place to insert this element
542 */
543
544 while (tsp) {
545 ret = strcmp(sp->p_tag, tsp->p_tag);
546 if (ret > 0) {
547 /* keep on looking */
548 savtsp = tsp;
549 tsp = tsp->p_next;
550 continue;
551 }
552 else if (ret == 0) {
553 if (tsp->p_status) {
554 /* this is a duplicate entry, ignore it */
555 log("Ignoring duplicate entry for <%s>",
556 tsp->p_tag);
557 }
558 else {
559 if (same_entry(tsp,sp)) { /* same entry */
560 tsp->p_status = VALID;
561 }
562 else { /* entry changed */
563 if ((sp->p_flags & X_FLAG) &&
564 ((sp->p_dmsg == NULL) ||
565 (*(sp->p_dmsg) == '\0'))) {
566 /* disabled entry */
567 tsp->p_status = NOTVALID;
568 }
569 else {
570 # ifdef DEBUG
571 debug("replacing <%s>", sp->p_tag);
572 # endif
573 /* replace old entry */
574 sp->p_next = tsp->p_next;
575 if (tsp == PMtab) {
576 PMtab = sp;
577 }
578 else {
579 savtsp->p_next = sp;
580 }
581 sp->p_status = CHANGED;
582 sp->p_fd = tsp->p_fd;
583 sp->p_pid = tsp->p_pid;
584 sp->p_inservice =
585 tsp->p_inservice;
586 sp = tsp;
587 }
588 }
589 Nentries++;
590 }
591 free_pmtab(sp);
592 return;
593 }
594 else {
595 if ((sp->p_flags & X_FLAG) &&
596 ((sp->p_dmsg == NULL) ||
597 (*(sp->p_dmsg) == '\0'))) { /* disabled entry */
598 free_pmtab(sp);
599 return;
600 }
601 /*
602 * Set the state of soft-carrier.
603 * Since this is a one-time only operation,
604 * we do it when this service is added to
605 * the enabled list.
606 */
607 if (*sp->p_softcar != '\0')
608 set_softcar(sp);
609
610 /* insert it here */
611 if (tsp == PMtab) {
612 sp->p_next = PMtab;
613 PMtab = sp;
614 }
615 else {
616 sp->p_next = savtsp->p_next;
617 savtsp->p_next = sp;
618 }
619 # ifdef DEBUG
620 debug("adding <%s>", sp->p_tag);
621 # endif
622 Nentries++;
623 /* this entry is "current" */
624 sp->p_status = VALID;
625 return;
626 }
627 }
628
629 /*
630 * either an empty list or should put element at end of list
631 */
632
633 if ((sp->p_flags & X_FLAG) &&
634 ((sp->p_dmsg == NULL) ||
635 (*(sp->p_dmsg) == '\0'))) { /* disabled entry */
636 free_pmtab(sp); /* do not poll this entry */
637 return;
638 }
639 /*
640 * Set the state of soft-carrier.
641 * Since this is a one-time only operation,
642 * we do it when this service is added to
643 * the enabled list.
644 */
645 if (*sp->p_softcar != '\0')
646 set_softcar(sp);
647 sp->p_next = NULL;
648 if (PMtab == NULL)
649 PMtab = sp;
650 else
651 savtsp->p_next = sp;
652 # ifdef DEBUG
653 debug("adding <%s>", sp->p_tag);
654 # endif
655 ++Nentries;
656 /* this entry is "current" */
657 sp->p_status = VALID;
658 }
659
660
661 /*
662 * purge - purge linked list of "old" entries
663 */
664
665
666 void
purge()667 purge()
668 {
669 register struct pmtab *sp; /* working pointer */
670 register struct pmtab *savesp, *tsp; /* scratch pointers */
671
672 # ifdef DEBUG
673 debug("in purge");
674 # endif
675 sp = savesp = PMtab;
676 while (sp) {
677 if (sp->p_status) {
678 # ifdef DEBUG
679 debug("p_status not 0");
680 # endif
681 savesp = sp;
682 sp = sp->p_next;
683 }
684 else {
685 tsp = sp;
686 if (tsp == PMtab) {
687 PMtab = sp->p_next;
688 savesp = PMtab;
689 }
690 else
691 savesp->p_next = sp->p_next;
692 # ifdef DEBUG
693 debug("purging <%s>", sp->p_tag);
694 # endif
695 sp = sp->p_next;
696 free_pmtab(tsp);
697 }
698 }
699 }
700
701 /*
702 * free_pmtab - free one pmtab entry
703 */
704 static void
free_pmtab(p)705 free_pmtab(p)
706 struct pmtab *p;
707 {
708 #ifdef DEBUG
709 debug("in free_pmtab");
710 #endif
711 free(p->p_tag);
712 free(p->p_identity);
713 free(p->p_res1);
714 free(p->p_res2);
715 free(p->p_res3);
716 free(p->p_device);
717 free(p->p_server);
718 free(p->p_ttylabel);
719 free(p->p_modules);
720 free(p->p_prompt);
721 free(p->p_dmsg);
722 free(p->p_termtype);
723 free(p->p_softcar);
724 if (p->p_dir)
725 free(p->p_dir);
726 free(p);
727 }
728
729 /*
730 * check_pmtab - check the fields to make sure things are correct
731 * - return 0 if everything is ok
732 * - return -1 if something is wrong
733 */
734
735 static int
check_pmtab(p)736 check_pmtab(p)
737 struct pmtab *p;
738 {
739 if (p == NULL) {
740 log("pmtab ptr is NULL");
741 return(-1);
742 }
743
744 /* check service tag */
745 if ((p->p_tag == NULL) || (*(p->p_tag) == '\0')) {
746 log("port/service tag is missing");
747 return(-1);
748 }
749 if (strlen(p->p_tag) > (size_t)(MAXID - 1)) {
750 log("port/service tag <%s> is longer than %d", p->p_tag,
751 MAXID-1);
752 return(-1);
753 }
754 if (strcheck(p->p_tag, ALNUM) != 0) {
755 log("port/service tag <%s> is not alphanumeric", p->p_tag);
756 return(-1);
757 }
758 if (check_identity(p) != 0) {
759 return(-1);
760 }
761
762 if (check_device(p->p_device) != 0)
763 return(-1);
764
765 if (check_cmd(p->p_server) != 0)
766 return(-1);
767 return(0);
768 }
769
770 extern struct passwd *getpwnam();
771 extern void endpwent();
772 extern struct group *getgrgid();
773 extern void endgrent();
774
775 /*
776 * check_identity - check to see if the identity is a valid user
777 * - log name in the passwd file,
778 * - and if its group id is a valid one
779 * - return 0 if everything is ok. Otherwise, return -1
780 */
781
782 int
check_identity(p)783 check_identity(p)
784 struct pmtab *p;
785 {
786 register struct passwd *pwdp;
787
788 if ((p->p_identity == NULL) || (*(p->p_identity) == '\0')) {
789 log("identity field is missing");
790 return(-1);
791 }
792 if ((pwdp = getpwnam(p->p_identity)) == NULL) {
793 log("missing or bad passwd entry for <%s>", p->p_identity);
794 endpwent();
795 return(-1);
796 }
797 if (getgrgid(pwdp->pw_gid) == NULL) {
798 log("no group entry for %ld", pwdp->pw_gid);
799 endgrent();
800 endpwent();
801 return(-1);
802 }
803 p->p_uid = pwdp->pw_uid;
804 p->p_gid = pwdp->pw_gid;
805 p->p_dir = strsave(pwdp->pw_dir);
806 endgrent();
807 endpwent();
808 return(0);
809 }
810
811 /*
812 * expand(cmdp, devp) - expand %d to device name and %% to %,
813 * - any other characters are untouched.
814 * - return the expanded string
815 */
816 static char *
expand(cmdp,devp)817 expand(cmdp,devp)
818 char *cmdp; /* ptr to cmd string */
819 char *devp; /* ptr to device name */
820 {
821 register char *cp, *dp, *np;
822 static char buf[BUFSIZ];
823 cp = cmdp;
824 np = buf;
825 dp = devp;
826 while (*cp) {
827 if (*cp != '%') {
828 *np++ = *cp++;
829 continue;
830 }
831 switch (*++cp) {
832 case 'd':
833 while (*dp) {
834 *np++ = *dp++;
835 }
836 cp++;
837 break;
838 case '%':
839 *np++ = *cp++;
840 break;
841 default:
842 *np++ = *cp++;
843 break;
844 }
845 }
846 *np = '\0';
847 return(buf);
848 }
849
850