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