xref: /titanic_44/usr/src/cmd/bnu/sysfiles.c (revision 9dd0f810214fdc8e1af881a9a5c4b6927629ff9e)
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 1998 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 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include "uucp.h"
34 
35 #include <unistd.h>
36 #include "sysfiles.h"
37 #include <sys/stropts.h>
38 
39 /*
40  * manage systems files (Systems, Devices, and Dialcodes families).
41  *
42  * also manage new file Devconfig, allows per-device setup.
43  * present use is to specify what streams modules to push/pop for
44  * AT&T TLI/streams network.
45  *
46  * TODO:
47  *    call bsfix()?
48  *    combine the 3 versions of everything (sys, dev, and dial) into one.
49  *    allow arbitrary classes of service.
50  *    need verifysys() for uucheck.
51  *    nameserver interface?
52  *    pass sysname (or 0) to getsysline().  (might want reg. exp. or NS processing
53  */
54 
55 /* private variables */
56 static void tokenize(), nameparse(), setfile(), setioctl(),
57 	scansys(), scancfg(), setconfig();
58 static int namematch(), nextdialers(), nextdevices(), nextsystems(), getline();
59 
60 /* pointer arrays might be dynamically allocated */
61 static char *Systems[64] = {0};	/* list of Systems files */
62 static char *Devices[64] = {0};	/* list of Devices files */
63 static char *Dialers[64] = {0};	/* list of Dialers files */
64 static char *Pops[64] = {0};	/* list of STREAMS modules to be popped */
65 static char *Pushes[64] = {0};	/* list of STREAMS modules to be pushed */
66 
67 static int nsystems;		/* index into list of Systems files */
68 static int ndevices;		/* index into list of Devices files */
69 static int ndialers;		/* index into list of Dialers files */
70 static int npops;		/* index into list of STREAMS modules */
71 							/*to be popped */
72 static int npushes;		/* index into list of STREAMS modules */
73 							/*to be pushed */
74 
75 GLOBAL unsigned connecttime = CONNECTTIME;
76 GLOBAL unsigned expecttime = EXPECTTIME;
77 GLOBAL unsigned msgtime = MSGTIME;
78 
79 static FILE *fsystems;
80 static FILE *fdevices;
81 static FILE *fdialers;
82 
83 static char errformat[BUFSIZ];
84 
85 /* this might be dynamically allocated */
86 #define NTOKENS 16
87 static char *tokens[NTOKENS], **tokptr;
88 
89 /* export these */
90 EXTERN void sysreset(), devreset(), dialreset(), setdevcfg(), setservice();
91 EXTERN char *strsave();
92 
93 /* import these */
94 extern char *strcpy(), *strtok(), *strchr(), *strsave();
95 EXTERN int eaccess();
96 
97 /*
98  * setservice init's Systems, Devices, Dialers lists from Sysfiles
99  */
100 GLOBAL void
101 setservice(service)
102 char *service;
103 {
104 	char	*prev = _uu_setlocale(LC_ALL, "C");
105 
106 	setconfig();
107 	scansys(service);
108 	(void) _uu_resetlocale(LC_ALL, prev);
109 	return;
110 }
111 
112 /*
113  * setdevcfg init's Pops, Pushes lists from Devconfig
114  */
115 
116 GLOBAL void
117 setdevcfg(service, device)
118 char *service, *device;
119 {
120 	char	*prev = _uu_setlocale(LC_ALL, "C");
121 
122 	scancfg(service, device);
123 	(void) _uu_resetlocale(LC_ALL, prev);
124 	return;
125 }
126 
127 /*	administrative files access */
128 GLOBAL int
129 sysaccess(type)
130 int type;
131 {
132 	switch (type) {
133 
134 	case ACCESS_SYSTEMS:
135 		return(access(Systems[nsystems], R_OK));
136 	case ACCESS_DEVICES:
137 		return(access(Devices[ndevices], R_OK));
138 	case ACCESS_DIALERS:
139 		return(access(Dialers[ndialers], R_OK));
140 	case EACCESS_SYSTEMS:
141 		return(eaccess(Systems[nsystems], R_OK));
142 	case EACCESS_DEVICES:
143 		return(eaccess(Devices[ndevices], R_OK));
144 	case EACCESS_DIALERS:
145 		return(eaccess(Dialers[ndialers], R_OK));
146 	default:
147 		(void)sprintf(errformat, "bad access type %d", type);
148 		logent(errformat, "sysaccess");
149 		return(FAIL);
150 	}
151 }
152 
153 
154 /*
155  * read Sysfiles, set up lists of Systems/Devices/Dialers file names.
156  * allow multiple entries for a given service, allow a service
157  * type to describe resources more than once, e.g., systems=foo:baz systems=bar.
158  */
159 static void
160 scansys(service)
161 char *service;
162 {	FILE *f;
163 	char *tok, buf[BUFSIZ];
164 
165 	Systems[0] = Devices[0] = Dialers[0] = NULL;
166 	if ((f = fopen(SYSFILES, "r")) != 0) {
167 		while (getline(f, buf) > 0) {
168 			/* got a (logical) line from Sysfiles */
169 			/* strtok's of this buf continue in tokenize() */
170 			tok = strtok(buf, " \t");
171 			if (namematch("service=", tok, service)) {
172 				tokenize();
173 				nameparse();
174 			}
175 		}
176 		(void) fclose(f);
177 	}
178 
179 	/* if didn't find entries in Sysfiles, use defaults */
180 	if (Systems[0] == NULL) {
181 		Systems[0] = strsave(SYSTEMS);
182 		ASSERT(Systems[0] != NULL, Ct_ALLOCATE, "scansys: Systems", 0);
183 		Systems[1] = NULL;
184 	}
185 	if (Devices[0] == NULL) {
186 		Devices[0] = strsave(DEVICES);
187 		ASSERT(Devices[0] != NULL, Ct_ALLOCATE, "scansys: Devices", 0);
188 		Devices[1] = NULL;
189 	}
190 	if (Dialers[0] == NULL) {
191 		Dialers[0] = strsave(DIALERS);
192 		ASSERT(Dialers[0] != NULL, Ct_ALLOCATE, "scansys: Dialers", 0);
193 		Dialers[1] = NULL;
194 	}
195 	return;
196 }
197 
198 
199 /*
200  * read Devconfig.  allow multiple entries for a given service, allow a service
201  * type to describe resources more than once, e.g., push=foo:baz push=bar.
202  */
203 static void
204 scancfg(service, device)
205 char *service, *device;
206 {	FILE *f;
207 	char *tok, buf[BUFSIZ];
208 
209 	/* (re)initialize device-specific information */
210 
211 	npops = npushes = 0;
212 	Pops[0] = Pushes[0] = NULL;
213 	connecttime = CONNECTTIME;
214 	expecttime = EXPECTTIME;
215 	msgtime = MSGTIME;
216 
217 	if ((f = fopen(DEVCONFIG, "r")) != 0) {
218 		while (getline(f, buf) > 0) {
219 			/* got a (logical) line from Devconfig */
220 			/* strtok's of this buf continue in tokenize() */
221 			tok = strtok(buf, " \t");
222 			if (namematch("service=", tok, service)) {
223 				tok = strtok((char *)0, " \t");
224 				if ( namematch("device=", tok, device)) {
225 					tokenize();
226 					nameparse();
227 				}
228 			}
229 		}
230 		(void) fclose(f);
231 	}
232 
233 	return;
234 
235 }
236 
237 /*
238  *  given a file pointer and buffer, construct logical line in buffer
239  *  (i.e., concatenate lines ending in '\').  return length of line
240  *  ASSUMES that buffer is BUFSIZ long!
241  */
242 
243 static int
244 getline(f, line)
245 FILE *f;
246 char *line;
247 {	char *lptr, *lend;
248 
249 	lptr = line;
250 	while (fgets(lptr, (line + BUFSIZ) - lptr, f) != NULL) {
251 		lend = lptr + strlen(lptr);
252 		if (lend == lptr || lend[-1] != '\n')
253 			/* empty buf or line too long! */
254 			break;
255 		*--lend = '\0'; /* lop off ending '\n' */
256 		if ( lend == line ) /* empty line - ignore */
257 			continue;
258 		lptr = lend;
259 		if (lend[-1] != '\\')
260 			break;
261 		/* continuation */
262 		lend[-1] = ' ';
263 	}
264 	return(lptr - line);
265 }
266 
267 /*
268  * given a label (e.g., "service=", "device="), a name ("cu", "uucico"),
269  *  and a line:  if line begins with the label and if the name appears
270  * in a colon-separated list of names following the label, return true;
271  * else return false
272  */
273 static int
274 namematch(label, line, name)
275 char *label, *line, *name;
276 {	char *lend;
277 
278 	if (strncmp(label, line, strlen(label)) != SAME) {
279 		return(FALSE);	/* probably a comment line */
280 	}
281 	line += strlen(label);
282 	if (*line == '\0')
283 		return(FALSE);
284 	/*
285 	 * can't use strtok() in the following because scansys(),
286 	 * scancfg() do an initializing call to strtok() before
287 	 * coming here and then CONTINUE calling strtok() in tokenize(),
288 	 * after returning from namematch().
289 	 */
290 	while ((lend = strchr(line, ':')) != NULL) {
291 		*lend = '\0';
292 		if (strcmp(line, name) == SAME)
293 			return(TRUE);
294 		line = lend+1;
295 	}
296 	return(strcmp(line, name) == SAME);
297 }
298 
299 /*
300  * tokenize() continues pulling tokens out of a buffer -- the
301  * initializing call to strtok must have been made before calling
302  * tokenize() -- and starts stuffing 'em into tokptr.
303  */
304 static void
305 tokenize()
306 {	char *tok;
307 
308 	tokptr = tokens;
309 	while ((tok = strtok((char *) NULL, " \t")) != NULL) {
310 		*tokptr++ = tok;
311 		if (tokptr - tokens >= NTOKENS)
312 			break;
313 	}
314 	*tokptr = NULL;
315 	return;
316 }
317 
318 /*
319  * look at top token in array: should be line of the form
320  *	name=item1:item2:item3...
321  * if name is one we recognize, then call set[file|ioctl] to set up
322  * corresponding list.  otherwise, log bad name.
323  */
324 static void
325 nameparse()
326 {	char **line, *equals;
327 	int temp;
328 
329 #define setuint(a,b,c) a = ( ((temp = atoi(b)) <= 0) ? (c) : temp )
330 
331 	for (line = tokens; (line - tokens) < NTOKENS && *line; line++) {
332 		equals = strchr(*line, '=');
333 		if (equals == NULL)
334 			continue;	/* may be meaningful someday? */
335 		*equals = '\0';
336 		/* ignore entry with empty rhs */
337 		if (*++equals == '\0')
338 			continue;
339 		if (strcmp(*line, "systems") == SAME)
340 			setfile(Systems, equals);
341 		else if (strcmp(*line, "devices") == SAME)
342 			setfile(Devices, equals);
343 		else if (strcmp(*line, "dialers") == SAME)
344 			setfile(Dialers, equals);
345 		else if (strcmp(*line, "pop") == SAME)
346 			setioctl(Pops, equals);
347 		else if (strcmp(*line, "push") == SAME)
348 			setioctl(Pushes, equals);
349 		else if (strcmp(*line, "connecttime") == SAME)
350 			setuint(connecttime, equals, CONNECTTIME);
351 		else if (strcmp(*line, "expecttime") == SAME)
352 			setuint(expecttime, equals, EXPECTTIME);
353 		else if (strcmp(*line, "msgtime") == SAME)
354 			setuint(msgtime, equals, MSGTIME);
355 		else {
356 			(void)sprintf(errformat,"unrecognized label %s",*line);
357 			logent(errformat, "Sysfiles|Devconfig");
358 		}
359 	}
360 	return;
361 }
362 
363 /*
364  * given the list for a particular type (systems, devices,...)
365  * and a line of colon-separated files, add 'em to list
366  */
367 
368 static void
369 setfile(type, line)
370 char **type, *line;
371 {	char **tptr, *tok;
372 	char expandpath[BUFSIZ];
373 
374 	if (*line == 0)
375 		return;
376 	tptr = type;
377 	while (*tptr)		/* skip over existing entries to*/
378 		tptr++;		/* concatenate multiple entries */
379 
380 	for (tok = strtok(line, ":"); tok != NULL;
381 	tok = strtok((char *) NULL, ":")) {
382 		expandpath[0] = '\0';
383 		if ( *tok != '/' )
384 			/* by default, file names are relative to SYSDIR */
385 			sprintf(expandpath, "%s/", SYSDIR);
386 		strcat(expandpath, tok);
387 		if (eaccess(expandpath, R_OK) != 0)
388 			/* if we can't read it, no point in adding to list */
389 			continue;
390 		*tptr = strsave(expandpath);
391 		ASSERT(*tptr != NULL, Ct_ALLOCATE, "setfile: tptr", 0);
392 		tptr++;
393 	}
394 	return;
395 }
396 
397 /*
398  * given the list for a particular ioctl (push, pop)
399  * and a line of colon-separated modules, add 'em to list
400  */
401 
402 static void
403 setioctl(type, line)
404 char **type, *line;
405 {	char **tptr, *tok;
406 
407 	if (*line == 0)
408 		return;
409 	tptr = type;
410 	while (*tptr)		/* skip over existing entries to*/
411 		tptr++;		/* concatenate multiple entries */
412 	for (tok = strtok(line, ":"); tok != NULL;
413 	tok = strtok((char *) NULL, ":")) {
414 		*tptr = strsave(tok);
415 		ASSERT(*tptr != NULL, Ct_ALLOCATE, "setioctl: tptr", 0);
416 		tptr++;
417 	}
418 	return;
419 }
420 
421 /*
422  * reset Systems files
423  */
424 GLOBAL void
425 sysreset()
426 {
427 	if (fsystems)
428 		fclose(fsystems);
429 	fsystems = NULL;
430 	nsystems = 0;
431 	devreset();
432 	return;
433 }
434 
435 /*
436  * reset Devices files
437  */
438 GLOBAL void
439 devreset()
440 {
441 	if (fdevices)
442 		fclose(fdevices);
443 	fdevices = NULL;
444 	ndevices = 0;
445 	dialreset();
446 	return;
447 }
448 
449 /*
450  * reset Dialers files
451  */
452 GLOBAL void
453 dialreset()
454 {
455 	if (fdialers)
456 		fclose(fdialers);
457 	fdialers = NULL;
458 	ndialers = 0;
459 	return;
460 }
461 
462 /*
463  * get next line from Systems file
464  * return TRUE if successful, FALSE if not
465  */
466 GLOBAL int
467 getsysline(buf, len)
468 char *buf;
469 {
470 	char	*prev = _uu_setlocale(LC_ALL, "C");
471 
472 	if (Systems[0] == NULL)
473 		/* not initialized via setservice() - use default */
474 		setservice("uucico");
475 
476 	/* initialize devices and dialers whenever a new line is read */
477 	/* from systems */
478 	devreset();
479 	if (fsystems == NULL)
480 		if (nextsystems() == FALSE) {
481 			(void) _uu_resetlocale(LC_ALL, prev);
482 			return(FALSE);
483 		}
484 
485 	ASSERT(len >= BUFSIZ, "BUFFER TOO SMALL", "getsysline", 0);
486 	for(;;) {
487 		while (getline(fsystems, buf) != NULL)
488 		    if ((*buf != '#') && (*buf != ' ') &&
489 			(*buf != '\t') && (*buf != '\n')) {
490 			(void) _uu_resetlocale(LC_ALL, prev);
491 			return(TRUE);
492 		}
493 		if (nextsystems() == FALSE) {
494 			(void) _uu_resetlocale(LC_ALL, prev);
495 			return(FALSE);
496 		}
497 	}
498 }
499 
500 /*
501  * move to next systems file.  return TRUE if successful, FALSE if not
502  */
503 static int
504 nextsystems()
505 {
506 	devreset();
507 
508 	if (fsystems != NULL) {
509 		(void) fclose(fsystems);
510 		nsystems++;
511 	} else {
512 		nsystems = 0;
513 	}
514 	for ( ; Systems[nsystems] != NULL; nsystems++)
515 		if ((fsystems = fopen(Systems[nsystems], "r")) != NULL)
516 			return(TRUE);
517 	return(FALSE);
518 }
519 
520 /*
521  * get next line from Devices file
522  * return TRUE if successful, FALSE if not
523  */
524 GLOBAL int
525 getdevline(buf, len)
526 char *buf;
527 {
528 	char	*prev = _uu_setlocale(LC_ALL, "C");
529 
530 	if (Devices[0] == NULL)
531 		/* not initialized via setservice() - use default */
532 		setservice("uucico");
533 
534 	if (fdevices == NULL)
535 		if (nextdevices() == FALSE) {
536 			(void) _uu_resetlocale(LC_ALL, prev);
537 			return(FALSE);
538 		}
539 	for(;;) {
540 		if (fgets(buf, len, fdevices) != NULL) {
541 			(void) _uu_resetlocale(LC_ALL, prev);
542 			return(TRUE);
543 		}
544 		if (nextdevices() == FALSE) {
545 			(void) _uu_resetlocale(LC_ALL, prev);
546 			return(FALSE);
547 		}
548 	}
549 }
550 
551 /*
552  * move to next devices file.  return TRUE if successful, FALSE if not
553  */
554 static int
555 nextdevices()
556 {
557 	if (fdevices != NULL) {
558 		(void) fclose(fdevices);
559 		ndevices++;
560 	} else {
561 		ndevices = 0;
562 	}
563 	for ( ; Devices[ndevices] != NULL; ndevices++)
564 		if ((fdevices = fopen(Devices[ndevices], "r")) != NULL)
565 			return(TRUE);
566 	return(FALSE);
567 }
568 
569 
570 /*
571  * get next line from Dialers file
572  * return TRUE if successful, FALSE if not
573  */
574 
575 GLOBAL int
576 getdialline(buf, len)
577 char *buf;
578 {
579 	char	*prev = _uu_setlocale(LC_ALL, "C");
580 
581 	if (Dialers[0] == NULL)
582 		/* not initialized via setservice() - use default */
583 		setservice("uucico");
584 
585 	if (fdialers == NULL)
586 		if (nextdialers() == FALSE) {
587 			(void) _uu_resetlocale(LC_ALL, prev);
588 			return(FALSE);
589 		}
590 	for(;;) {
591 		if (fgets(buf, len, fdialers) != NULL) {
592 			(void) _uu_resetlocale(LC_ALL, prev);
593 			return(TRUE);
594 		}
595 		if (nextdialers() == FALSE) {
596 			(void) _uu_resetlocale(LC_ALL, prev);
597 			return(FALSE);
598 		}
599 	}
600 }
601 
602 /*
603  * move to next dialers file.  return TRUE if successful, FALSE if not
604  */
605 static int
606 nextdialers()
607 {
608 	if (fdialers) {
609 		(void) fclose(fdialers);
610 		ndialers++;
611 	} else {
612 		ndialers = 0;
613 	}
614 
615 	for ( ; Dialers[ndialers] != NULL; ndialers++)
616 		if ((fdialers = fopen(Dialers[ndialers], "r")) != NULL)
617 			return(TRUE);
618 	return(FALSE);
619 }
620 
621 /*
622  * get next module to be popped
623  * return TRUE if successful, FALSE if not
624  */
625 static int
626 getpop(buf, len, optional)
627 char *buf;
628 int len, *optional;
629 {
630 	int slen;
631 
632 	if ( Pops[0] == NULL || Pops[npops] == NULL )
633 		return(FALSE);
634 
635 	/*	if the module name is enclosed in parentheses,	*/
636 	/*	is optional. set flag & strip parens		*/
637 	slen = strlen(Pops[npops]) - 1;
638 	if ( Pops[npops][0] == '('  && Pops[npops][slen] == ')' ) {
639 		*optional = 1;
640 		len = ( slen < len ? slen : len );
641 		strncpy(buf, &(Pops[npops++][1]), len);
642 	} else {
643 		*optional = 0;
644 		strncpy(buf, Pops[npops++], len);
645 	}
646 	buf[len-1] = '\0';
647 	return(TRUE);
648 }
649 
650 /*
651  * get next module to be pushed
652  * return TRUE if successful, FALSE if not
653  */
654 static int
655 getpush(buf, len)
656 char *buf;
657 int len;
658 {
659 	if ( Pushes[0] == NULL || Pushes[npushes] == NULL )
660 		return(FALSE);
661 	strncpy(buf, Pushes[npushes++], len);
662 	return(TRUE);
663 }
664 
665 /*
666  * pop/push requested modules
667  * return TRUE if successful, FALSE if not
668  */
669 GLOBAL int
670 pop_push(fd)
671 int fd;
672 {
673     char	strmod[FMNAMESZ], onstream[FMNAMESZ];
674     int		optional;
675     char	*prev = _uu_setlocale(LC_ALL, "C");
676 
677     /*	check for streams modules to pop	*/
678     while ( getpop(strmod, sizeof(strmod), &optional) ) {
679 	DEBUG(5, (optional ? "pop_push: optionally POPing %s\n"
680 			   : "pop_push: POPing %s\n" ), strmod);
681 	if ( ioctl(fd, I_LOOK, onstream) == -1 ) {
682 	    DEBUG(5, "pop_push: I_LOOK on fd %d failed ", fd);
683 	    DEBUG(5, "errno %d\n", errno);
684 	    (void) _uu_resetlocale(LC_ALL, prev);
685 	    return(FALSE);
686 	}
687 	if ( strcmp(strmod, onstream) != SAME ) {
688 	    if ( optional )
689 		continue;
690 	    DEBUG(5, "pop_push: I_POP: %s not there\n", strmod);
691 	    (void) _uu_resetlocale(LC_ALL, prev);
692 	    return(FALSE);
693 	}
694 	if ( ioctl(fd, I_POP, 0) == -1 ) {
695 	    DEBUG(5, "pop_push: I_POP on fd %d failed ", fd);
696 	    DEBUG(5, "errno %d\n", errno);
697 	    (void) _uu_resetlocale(LC_ALL, prev);
698 	    return(FALSE);
699 	}
700     }
701 
702     /*	check for streams modules to push	*/
703     while ( getpush(strmod, sizeof(strmod)) ) {
704 	DEBUG(5, "pop_push: PUSHing %s\n", strmod);
705 	if ( ioctl(fd, I_PUSH, strmod) == -1 ) {
706 	    DEBUG(5, "pop_push: I_PUSH on fd %d failed ", fd);
707 	    DEBUG(5, "errno %d\n", errno);
708 	    (void) _uu_resetlocale(LC_ALL, prev);
709 	    return(FALSE);
710 	}
711     }
712     (void) _uu_resetlocale(LC_ALL, prev);
713     return(TRUE);
714 }
715 
716 /*
717  * 	return name of currently open Systems file
718  */
719 GLOBAL char *
720 currsys()
721 {
722 	return(Systems[nsystems]);
723 }
724 
725 /*
726  * 	return name of currently open Devices file
727  */
728 GLOBAL char *
729 currdev()
730 {
731 	return(Devices[ndevices]);
732 }
733 
734 /*
735  * 	return name of currently open Dialers file
736  */
737 GLOBAL char *
738 currdial()
739 {
740 	return(Dialers[ndialers]);
741 }
742 
743 /*
744  * set configuration parameters provided in Config file
745  */
746 static void
747 setconfig()
748 {
749     FILE *f;
750     char buf[BUFSIZ];
751     char *tok;
752     extern char _ProtoCfg[];
753 
754     if ((f = fopen(CONFIG, "r")) != 0) {
755 	while (getline(f, buf) > 0) {
756 	    /* got a (logical) line from Config file */
757 	    tok = strtok(buf, " \t");
758 	    if ( (tok != NULL) && (*tok != '#') ) {
759 		/* got a token */
760 
761 		/* this probably should be table driven when
762 		 * the list of configurable parameters grows.
763 		 */
764 		if (strncmp("Protocol=", tok, strlen("Protocol=")) == SAME) {
765 		    tok += strlen("Protocol=");
766 		    if ( *tok != '\0' ) {
767 			if ( _ProtoCfg[0] != '\0' ) {
768 			    DEBUG(7, "Protocol string %s ", tok);
769 			    DEBUG(7, "overrides %s\n", _ProtoCfg);
770 		        }
771 		        strcpy(_ProtoCfg, tok);
772 		    }
773 	        } else {
774 		    DEBUG(7, "Unknown configuration parameter %s\n", tok);
775 	        }
776 	    }
777 	}
778     }
779 }
780