xref: /illumos-gate/usr/src/lib/cfgadm_plugins/ib/common/cfga_conf.c (revision 27954b0d964ffcb749cf19296906e7fecdf3da1b)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "cfga_ib.h"
27 #include "cfga_conf.h"
28 #include <sys/stat.h>
29 
30 /*
31  * cfga_conf.c
32  *
33  *	This file supports adding/deleting/listing services from IBCONF_FILE.
34  */
35 
36 /*
37  * function prototypes:
38  */
39 static ib_service_type_t	ib_get_var_type(char *);
40 static ib_token_t		ib_lex(char *, char **);
41 static void			ib_find_eol();
42 static int			ib_get_string(char **, char *);
43 static int			ib_service_record_add(char *,
44 				    ib_service_type_t);
45 static ib_token_t		ib_get_services(char **);
46 static boolean_t		ib_cmp_service();
47 static void			ib_free_service_recs(void);
48 static int			ib_cleanup_file(int);
49 static int			ib_init_file(char **);
50 int				ib_add_service(char **);
51 int				ib_delete_service(char **);
52 int				ib_list_services(struct cfga_msg *, char **);
53 static cfga_ib_ret_t		ib_conf_control_ioctl(char *, uint_t);
54 static int			ib_service_record_valid(char *);
55 
56 extern void			cfga_msg(struct cfga_msg *, const char *);
57 
58 
59 /* Global variables */
60 
61 /*
62  * supported "name=value" pairs from IBCONF_FILE
63  */
64 static ibcfg_var_t ibcfg_varlist[] = {
65 	{ "name",		IB_NAME },
66 	{ "class",		IB_CLASS },
67 	{ "port-svc-list",	IB_PORT_SERVICE },
68 	{ "vppa-svc-list",	IB_VPPA_SERVICE },
69 	{ "hca-svc-list",	IB_HCASVC_SERVICE },
70 	{ NULL,			IB_NONE }
71 };
72 
73 static char		ibconf_file[] = IBCONF_FILE;	/* file being read */
74 static int		ibcfg_linenum = 1;		/* track line#s */
75 static int		ibcfg_cntr = 0;			/* current char read */
76 static int		ibcfg_brec = 0;			/* beginning of rec */
77 static int		bvpparec = 0;			/* begin of vppa rec */
78 static int		bportrec = 0;			/* begin of port rec */
79 static int		bhcarec = 0;			/* begin of HCA rec */
80 static int		ibcfg_btoken = 0;		/* begin of new token */
81 static mutex_t		ibcfg_lock = DEFAULTMUTEX;	/* lock for the file */
82 static int		ibcfg_fd = -1;			/* file descriptor */
83 static int		ibcfg_tmpfd = 0;		/* tmp file "fd" */
84 static char		*file_buf = (char *)NULL;	/* read file into buf */
85 static char		*tmpnamef = (char *)NULL;	/* tmp file name */
86 static boolean_t	wrote_tmp = B_FALSE;		/* tmp file write in */
87 							/* progress indicator */
88 static struct stat	ibcfg_st;			/* file stat struct */
89 
90 static int		ibcfg_nport_services;		/* # of PORT services */
91 static int		ibcfg_nvppa_services;		/* # of VPPA services */
92 static int		ibcfg_nhca_services;		/* # of HCA services */
93 static ib_svc_rec_t	*ibcfg_vppa_head;		/* VPPA service recs */
94 static ib_svc_rec_t	*ibcfg_port_head;		/* PORT service recs */
95 static ib_svc_rec_t	*ibcfg_hca_head;		/* HCA service recs */
96 
97 extern char		*service_name;			/* service name */
98 extern ib_service_type_t service_type;			/* service type */
99 
100 
101 /*
102  * Function:
103  *	ib_get_var_type
104  * Input:
105  *	str	-	A parsed string from IBCONF_FILE
106  * Output:
107  *	NONE
108  * Returns:
109  *	Service type
110  * Description:
111  *	Returns the field from the token
112  */
113 static ib_service_type_t
114 ib_get_var_type(char *str)
115 {
116 	register ibcfg_var_t    *cfgvar;
117 
118 	cfgvar = &ibcfg_varlist[0];
119 	while (cfgvar->type != IB_NONE) {
120 		if (strcasecmp(cfgvar->name, str) == NULL)
121 			break;
122 		else
123 			cfgvar++;
124 	}
125 	return (cfgvar->type);
126 }
127 
128 
129 /*
130  * Function:
131  *	ib_lex
132  * Input:
133  *	NONE
134  * Output:
135  *	val	-	value just read
136  *	errmsg	-	pointer to error message string, if there are any errors
137  * Returns:
138  *	valid IB token
139  * Description:
140  *	Read tokens from the IBCONF_FILE and parse them
141  */
142 /* ARGSUSED */
143 static ib_token_t
144 ib_lex(char *val, char **errmsg)
145 {
146 	int		ch, oval, badquote;
147 	char		*cp = val;
148 	ib_token_t	token;
149 
150 	while ((ch = GETC(file_buf, ibcfg_cntr)) == ' ' || ch == '\t')
151 		;
152 
153 	/* make a note of the beginning of token */
154 	ibcfg_btoken = ibcfg_cntr - 1;
155 
156 	*cp++ = (char)ch;
157 	switch (ch) {
158 	case '=':
159 		token = EQUALS;
160 		break;
161 	case '&':
162 		token = AMPERSAND;
163 		break;
164 	case '|':
165 		token = BIT_OR;
166 		break;
167 	case '*':
168 		token = STAR;
169 		break;
170 	case '#':
171 		token = POUND;
172 		break;
173 	case ':':
174 		token = COLON;
175 		break;
176 	case ';':
177 		token = SEMICOLON;
178 		break;
179 	case ',':
180 		token = COMMA;
181 		break;
182 	case '/':
183 		token = SLASH;
184 		break;
185 	case ' ':
186 	case '\t':
187 	case '\f':
188 		while ((ch  = GETC(file_buf, ibcfg_cntr)) == ' ' ||
189 		    ch == '\t' || ch == '\f')
190 			*cp++ = (char)ch;
191 		(void) UNGETC(ibcfg_cntr);
192 		token = WHITE_SPACE;
193 		break;
194 	case '\n':
195 	case '\r':
196 		token = NEWLINE;
197 		break;
198 	case '"':
199 		cp--;
200 		badquote = 0;
201 		while (!badquote && (ch  = GETC(file_buf, ibcfg_cntr)) != '"') {
202 			switch (ch) {
203 			case '\n':
204 			case -1:
205 				(void) snprintf(*errmsg, MAXPATHLEN,
206 				    "Missing \"");
207 				cp = val;
208 				*cp++ = '\n';
209 				badquote = 1;
210 				/* since we consumed the newline/EOF */
211 				(void) UNGETC(ibcfg_cntr);
212 				break;
213 
214 			case '\\':
215 				ch = (char)GETC(file_buf, ibcfg_cntr);
216 				if (!isdigit(ch)) {
217 					/* escape the character */
218 					*cp++ = (char)ch;
219 					break;
220 				}
221 				oval = 0;
222 				while (ch >= '0' && ch <= '7') {
223 					ch -= '0';
224 					oval = (oval << 3) + ch;
225 					ch = (char)GETC(file_buf, ibcfg_cntr);
226 				}
227 				(void) UNGETC(ibcfg_cntr);
228 				/* check for character overflow? */
229 				if (oval > 127) {
230 					(void) snprintf(*errmsg, MAXPATHLEN,
231 					    "Character overflow detected.\n");
232 				}
233 				*cp++ = (char)oval;
234 				break;
235 			default:
236 				*cp++ = (char)ch;
237 				break;
238 			}
239 		}
240 		token = STRING;
241 		break;
242 	default:
243 		if (ch == -1) {
244 			token = EOF;
245 			break;
246 		}
247 		/*
248 		 * detect a lone '-' (including at the end of a line), and
249 		 * identify it as a 'name'
250 		 */
251 		if (ch == '-') {
252 			*cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr));
253 			if (iswhite(ch) || (ch == '\n')) {
254 				(void) UNGETC(ibcfg_cntr);
255 				cp--;
256 				token = NAME;
257 				break;
258 			}
259 		} else if (isunary(ch)) {
260 			*cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr));
261 		}
262 
263 		if (isdigit(ch)) {
264 			if (ch == '0') {
265 				if ((ch = GETC(file_buf, ibcfg_cntr)) == 'x') {
266 					*cp++ = (char)ch;
267 					ch = GETC(file_buf, ibcfg_cntr);
268 					while (isxdigit(ch)) {
269 						*cp++ = (char)ch;
270 						ch = GETC(file_buf, ibcfg_cntr);
271 					}
272 					(void) UNGETC(ibcfg_cntr);
273 					token = HEXVAL;
274 				} else {
275 					goto digit;
276 				}
277 			} else {
278 				ch = GETC(file_buf, ibcfg_cntr);
279 digit:
280 				while (isdigit(ch)) {
281 					*cp++ = (char)ch;
282 					ch = GETC(file_buf, ibcfg_cntr);
283 				}
284 				(void) UNGETC(ibcfg_cntr);
285 				token = DECVAL;
286 			}
287 		} else if (isalpha(ch) || ch == '\\') {
288 			if (ch != '\\') {
289 				ch = GETC(file_buf, ibcfg_cntr);
290 			} else {
291 				/*
292 				 * if the character was a backslash,
293 				 * back up so we can overwrite it with
294 				 * the next (i.e. escaped) character.
295 				 */
296 				cp--;
297 			}
298 
299 			while (isnamechar(ch) || ch == '\\') {
300 				if (ch == '\\')
301 					ch = GETC(file_buf, ibcfg_cntr);
302 				*cp++ = (char)ch;
303 				ch = GETC(file_buf, ibcfg_cntr);
304 			}
305 			(void) UNGETC(ibcfg_cntr);
306 			token = NAME;
307 		} else
308 			return (-1);
309 		break;
310 	}
311 	*cp = '\0';
312 	return (token);
313 }
314 
315 
316 /*
317  * Function:
318  *	ib_find_eol
319  * Input:
320  *	NONE
321  * Output:
322  *	NONE
323  * Returns:
324  *	NONE
325  * Description:
326  *	Leave NEWLINE as the next character.
327  */
328 static void
329 ib_find_eol()
330 {
331 	int ch;
332 
333 	while ((ch = GETC(file_buf, ibcfg_cntr)) != -1) {
334 		if (isnewline(ch))  {
335 			(void) UNGETC(ibcfg_cntr);
336 			break;
337 		}
338 	}
339 }
340 
341 
342 /*
343  * Function:
344  *	ib_get_string
345  * Input:
346  *	tchar		- name of the string
347  * Output:
348  *	llptr		- Valid string
349  * Returns:
350  *	1 for success, NULL for errors.
351  * Description:
352  *	The next item on the line is a string value. Allocate memory for
353  *	it and copy the string. Return 1, and set arg ptr to newly allocated
354  *	and initialized buffer, or NULL if an error occurs.
355  */
356 static int
357 ib_get_string(char **llptr, char *tchar)
358 {
359 	int	tlen = strlen(tchar);
360 	char	*cp;
361 	char	*start = (char *)0;
362 
363 	start = tchar;
364 	/* copy string */
365 	if ((cp = (char *)calloc(tlen + 1, sizeof (char))) == (char *)NULL) {
366 		*llptr = NULL;
367 		return (0);
368 	}
369 	bzero(cp, tlen + 1);
370 
371 	*llptr = cp;
372 	for (; tlen > 0; tlen--) {
373 		/* convert some common escape sequences */
374 		if (*start == '\\') {
375 			switch (*(start + 1)) {
376 			case 't':
377 				/* tab */
378 				*cp++ = '\t';
379 				tlen--;
380 				start += 2;
381 				break;
382 			case 'n':
383 				/* new line */
384 				*cp++ = '\n';
385 				tlen--;
386 				start += 2;
387 				break;
388 			case 'b':
389 				/* back space */
390 				*cp++ = '\b';
391 				tlen--;
392 				start += 2;
393 				break;
394 			default:
395 				/* simply copy it */
396 				*cp++ = *start++;
397 				break;
398 			}
399 		} else {
400 			*cp++ = *start++;
401 		}
402 	}
403 	*cp = '\0';
404 	return (1);
405 }
406 
407 
408 /*
409  * Function:
410  *	ib_service_record_add
411  * Input:
412  *	service		- name of the service
413  *	type		- type of the service
414  * Output:
415  *	rec		- one valid service record
416  * Returns:
417  *	CFGA_IB_OK on success or an appropriate error
418  * Description:
419  *	Add one record to internal data structures
420  */
421 static int
422 ib_service_record_add(char *service, ib_service_type_t type)
423 {
424 	ib_svc_rec_t	*tmp, *recp;
425 
426 	DPRINTF("ib_service_record_add: (%x, %s) "
427 	    "(#port = %d #vppa = %d #hca = %d)\n", type, service,
428 	    ibcfg_nport_services, ibcfg_nvppa_services,
429 	    ibcfg_nhca_services);
430 	recp = (ib_svc_rec_t *)calloc(1, sizeof (ib_svc_rec_t));
431 	if (recp == NULL)
432 		return (CFGA_IB_ALLOC_FAIL);
433 
434 	recp->type = type;
435 	recp->name = strdup((char *)service);
436 	if (type == IB_PORT_SERVICE) {
437 		if (ibcfg_port_head) {
438 			for (tmp = ibcfg_port_head; tmp->next != NULL; )
439 				tmp = tmp->next;
440 			tmp->next = recp;
441 		} else
442 			ibcfg_port_head = recp;
443 		ibcfg_nport_services++;
444 	} else if (type == IB_VPPA_SERVICE) {
445 		if (ibcfg_vppa_head) {
446 			for (tmp = ibcfg_vppa_head; tmp->next != NULL; )
447 				tmp = tmp->next;
448 			tmp->next = recp;
449 		} else
450 			ibcfg_vppa_head = recp;
451 		ibcfg_nvppa_services++;
452 	} else if (type == IB_HCASVC_SERVICE) {
453 		if (ibcfg_hca_head) {
454 			for (tmp = ibcfg_hca_head; tmp->next != NULL; )
455 				tmp = tmp->next;
456 			tmp->next = recp;
457 		} else
458 			ibcfg_hca_head = recp;
459 		ibcfg_nhca_services++;
460 	}
461 
462 	return (CFGA_IB_OK);
463 }
464 
465 
466 /*
467  * Function:
468  *	ib_get_services
469  * Input:
470  *	errmsg		- Error message filled in case of a failure
471  * Output:
472  *	rec		- one valid service record
473  * Returns:
474  *	CFGA_IB_OK on success or an appropriate error
475  * Description:
476  *	Fetch one record from the IBCONF_FILE
477  */
478 static ib_token_t
479 ib_get_services(char **errmsg)
480 {
481 	char			tokval[MAXLINESIZE];
482 	char			*llptr;
483 	boolean_t		sor = B_TRUE;
484 	ib_token_t		token;
485 	ib_service_type_t	cfgvar;
486 	ib_parse_state_t	parse_state = IB_NEWVAR;
487 
488 	token = ib_lex(tokval, errmsg);
489 	while ((token != EOF) && (token != SEMICOLON)) {
490 		if (token == STAR || token == POUND) {
491 			/* skip comments */
492 			ib_find_eol();
493 		} else if (token == NEWLINE) {
494 			ibcfg_linenum++;
495 		} else if (token == NAME || token == STRING) {
496 			if (parse_state == IB_NEWVAR) {
497 				cfgvar = ib_get_var_type(tokval);
498 				if (cfgvar == IB_NONE) {
499 					parse_state = IB_ERROR;
500 					(void) snprintf(*errmsg, MAXPATHLEN,
501 					    "Syntax Error: Invalid type %s",
502 					    tokval);
503 				} else {
504 					/* Note the beginning of the entry */
505 					if (sor) {
506 						ibcfg_brec = ibcfg_btoken;
507 						sor = B_FALSE;
508 					}
509 					parse_state = IB_CONFIG_VAR;
510 					if (cfgvar == IB_PORT_SERVICE)
511 						bportrec = ibcfg_cntr + 1;
512 					else if (cfgvar == IB_VPPA_SERVICE)
513 						bvpparec = ibcfg_cntr + 1;
514 					else if (cfgvar == IB_HCASVC_SERVICE)
515 						bhcarec = ibcfg_cntr + 1;
516 				}
517 
518 			} else if (parse_state == IB_VAR_VALUE) {
519 				llptr = NULL;
520 				if (ib_get_string(&llptr, tokval)) {
521 					if ((cfgvar == IB_PORT_SERVICE) ||
522 					    (cfgvar == IB_VPPA_SERVICE) ||
523 					    (cfgvar == IB_HCASVC_SERVICE)) {
524 						if (ib_service_record_valid(
525 						    llptr) &&
526 						    ib_service_record_add(
527 						    (char *)llptr, cfgvar) !=
528 						    CFGA_IB_OK) {
529 							return (E_O_F);
530 						} else {
531 							parse_state =
532 							    IB_CONFIG_VAR;
533 						}
534 					} else if ((cfgvar == IB_NAME) ||
535 					    (cfgvar == IB_CLASS)) {
536 						free((char *)llptr);
537 						parse_state = IB_NEWVAR;
538 					} else {
539 						free((char *)llptr);
540 						parse_state = IB_ERROR;
541 					}
542 				} else {
543 					parse_state = IB_ERROR;
544 					(void) snprintf(*errmsg, MAXPATHLEN,
545 					    "Syntax Error: Invalid value %s "
546 					    "for type: %s\n", tokval,
547 					    ibcfg_varlist[cfgvar].name);
548 				}
549 			} else if (parse_state == IB_ERROR) {
550 				/* just skip */
551 				DPRINTF("ib_get_services: ERROR\n");
552 			} else {
553 				parse_state = IB_ERROR;
554 				(void) snprintf(*errmsg, MAXPATHLEN,
555 				    "Syntax Error: at %s", tokval);
556 			}
557 		} else if (token == COMMA || token == EQUALS) {
558 			if (parse_state == IB_CONFIG_VAR) {
559 				if (cfgvar == IB_NONE) {
560 					parse_state = IB_ERROR;
561 					(void) snprintf(*errmsg, MAXPATHLEN,
562 					    "Syntax Error: unexpected '='");
563 				} else {
564 					parse_state = IB_VAR_VALUE;
565 				}
566 			} else if (parse_state != IB_ERROR) {
567 				(void) snprintf(*errmsg, MAXPATHLEN,
568 				    "Syntax Error: unexpected '='");
569 				parse_state = IB_ERROR;
570 			}
571 		} else {
572 			(void) snprintf(*errmsg, MAXPATHLEN,
573 			    "Syntax Error: at: %s", tokval);
574 			parse_state = IB_ERROR;
575 		}
576 		token = ib_lex(tokval, errmsg);
577 		if (ib_get_var_type(tokval) != IB_NONE)
578 			parse_state = IB_NEWVAR;
579 	}
580 	return (token);
581 }
582 
583 /*
584  * Function:
585  *	ib_cmp_service
586  * Input:
587  *	NONE
588  * Output:
589  *	NONE
590  * Returns:
591  *	B_TRUE if this service is already seen. B_FALSE if not.
592  * Description:
593  *	Compare the service just read from the services already seen.
594  *	Check if this service was already seen or not.
595  */
596 static boolean_t
597 ib_cmp_service()
598 {
599 	ib_svc_rec_t	*recp;
600 
601 	DPRINTF("ib_cmp_service: (%x, %s) "
602 	    "(#port = %d #vppa = %d #hca = %d)\n", service_type,
603 	    service_name, ibcfg_nport_services, ibcfg_nvppa_services,
604 	    ibcfg_nhca_services);
605 
606 	for (recp = ibcfg_port_head; recp != NULL; recp = recp->next) {
607 		DPRINTF("ib_cmp_service:P usvc = %s, usvc_name = %s\n",
608 		    service_name, recp->name ? recp->name : "NONE");
609 		if (recp->name && strcmp(recp->name, service_name) == 0)
610 			return (B_TRUE);
611 	}
612 	for (recp = ibcfg_vppa_head; recp != NULL; recp = recp->next) {
613 		DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n",
614 		    recp->type, recp->name ? recp->name : "NONE");
615 		if (recp->name && strcmp(recp->name, service_name) == 0)
616 			return (B_TRUE);
617 	}
618 	for (recp = ibcfg_hca_head; recp != NULL; recp = recp->next) {
619 		DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n",
620 		    recp->type, recp->name ? recp->name : "NONE");
621 		if (recp->name && strcmp(recp->name, service_name) == 0)
622 			return (B_TRUE);
623 	}
624 
625 	return (B_FALSE);
626 }
627 
628 
629 /*
630  * Function:
631  *	ib_free_service_recs
632  * Input:
633  *	NONE
634  * Output:
635  *	NONE
636  * Returns:
637  *	CFGA_IB_OK on success or an appropriate error
638  * Description:
639  *	Free the service records allocated in ib_get_services
640  */
641 static void
642 ib_free_service_recs(void)
643 {
644 	ib_svc_rec_t	*tmp, *recp;
645 
646 	DPRINTF("ib_free_service_recs: "
647 	    "#port_services = %d, #vppa_services = %d, #hca_services = %d\n",
648 	    ibcfg_nport_services, ibcfg_nvppa_services, ibcfg_nhca_services);
649 
650 	for (recp = ibcfg_port_head; recp != NULL; ) {
651 		if (recp && strlen(recp->name))
652 			S_FREE(recp->name);
653 		tmp = recp;
654 		recp = recp->next;
655 		S_FREE(tmp);
656 	}
657 
658 	for (recp = ibcfg_vppa_head; recp != NULL; ) {
659 		if (recp && strlen(recp->name))
660 			S_FREE(recp->name);
661 		tmp = recp;
662 		recp = recp->next;
663 		S_FREE(tmp);
664 	}
665 
666 	for (recp = ibcfg_hca_head; recp != NULL; ) {
667 		if (recp && strlen(recp->name))
668 			S_FREE(recp->name);
669 		tmp = recp;
670 		recp = recp->next;
671 		S_FREE(tmp);
672 	}
673 }
674 
675 
676 /*
677  * Function:
678  *	ib_cleanup_file
679  * Input:
680  *	rval		- error return value
681  * Output:
682  *	NONE
683  * Returns:
684  *	CFGA_IB_OK on success or an appropriate error
685  * Description:
686  *	Cleanup  IBCONF_FILE etc.
687  */
688 static int
689 ib_cleanup_file(int rval)
690 {
691 	int	rv = rval;
692 
693 	ib_free_service_recs();
694 	if (lockf(ibcfg_fd, F_ULOCK, 0) == -1) {
695 		DPRINTF("ib_cleanup_file: unlock file %s failed\n",
696 		    ibconf_file);
697 		rv = CFGA_IB_UNLOCK_FILE_ERR;
698 	}
699 	S_FREE(file_buf);
700 	close(ibcfg_fd);
701 	ibcfg_fd = -1;
702 	if (ibcfg_tmpfd && wrote_tmp == B_TRUE) {
703 		DPRINTF("ib_cleanup_file: tmpfile %s being renamed to %s\n",
704 		    tmpnamef, IBCONF_FILE);
705 		close(ibcfg_tmpfd);
706 		rename((const char *)tmpnamef, (const char *)IBCONF_FILE);
707 		unlink(tmpnamef);
708 	}
709 	(void) mutex_unlock(&ibcfg_lock);
710 	return (rv);
711 }
712 
713 
714 /*
715  * Function:
716  *	ib_init_file
717  * Input:
718  *	NONE
719  * Output:
720  *	errmsg		- Error message filled in case of a failure
721  * Returns:
722  *	CFGA_IB_OK on success or an appropriate error
723  * Description:
724  *	Initialize IBCONF_FILE for reading
725  */
726 static int
727 ib_init_file(char **errmsg)
728 {
729 	(void) mutex_lock(&ibcfg_lock);
730 
731 	if (*errmsg == (char *)NULL) {
732 		if ((*errmsg = calloc(MAXPATHLEN, 1)) == (char *)NULL) {
733 			(void) mutex_unlock(&ibcfg_lock);
734 			DPRINTF("ib_init_file: calloc errmsg failed\n");
735 			return (CFGA_IB_CONFIG_FILE_ERR);
736 		}
737 	}
738 
739 	/* Open the .conf file */
740 	if ((ibcfg_fd = open(ibconf_file, O_RDWR, 0666)) == -1) {
741 		(void) snprintf(*errmsg, MAXPATHLEN,
742 		    "failed to open %s file\n", ibconf_file);
743 		(void) mutex_unlock(&ibcfg_lock);
744 		return (CFGA_IB_CONFIG_FILE_ERR);
745 	}
746 
747 	/* Lock the file so that another cfgadm instance doesn't modify it */
748 	if (lockf(ibcfg_fd, F_TLOCK, 0) == -1) {
749 		(void) snprintf(*errmsg, MAXPATHLEN,
750 		    "failed to lock %s file\n", ibconf_file);
751 		close(ibcfg_fd);
752 		ibcfg_fd = -1;
753 		(void) mutex_unlock(&ibcfg_lock);
754 		return (CFGA_IB_LOCK_FILE_ERR);
755 	}
756 
757 	if (fstat(ibcfg_fd, &ibcfg_st) != 0) {
758 		DPRINTF("ib_init_file: failed to fstat %s file\n", ibconf_file);
759 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
760 	}
761 
762 	/* Allocate a buffer for the file */
763 	if ((file_buf = (char *)malloc(ibcfg_st.st_size)) == NULL) {
764 		DPRINTF("ib_init_file: failed to fstat %s file\n",
765 		    ibconf_file);
766 		return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
767 	}
768 
769 	/* Check if size matches */
770 	if (ibcfg_st.st_size != read(ibcfg_fd, file_buf, ibcfg_st.st_size)) {
771 		DPRINTF("ib_init_file: failed to read %s file\n", ibconf_file);
772 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
773 	}
774 
775 	/*
776 	 * These variables need to be reinitialized here as they may
777 	 * have been modified by a previous thread that called this
778 	 * function
779 	 */
780 	ibcfg_linenum = 1;
781 	ibcfg_cntr = 0;
782 	ibcfg_brec = 0;
783 	ibcfg_btoken = 0;
784 
785 	ibcfg_nport_services = 0;
786 	ibcfg_nvppa_services = 0;
787 	ibcfg_nhca_services = 0;
788 	ibcfg_port_head = (ib_svc_rec_t *)NULL;
789 	ibcfg_vppa_head = (ib_svc_rec_t *)NULL;
790 	ibcfg_hca_head = (ib_svc_rec_t *)NULL;
791 	return (CFGA_IB_OK);
792 }
793 
794 
795 /*
796  * Function:
797  *	ib_add_service
798  * Input:
799  *	NONE
800  * Output:
801  *	errmsg		- Error message filled in case of a failure
802  * Returns:
803  *	CFGA_IB_OK on success or an appropriate error
804  * Description:
805  *	open IBCONF_FILE and add "service_name".
806  */
807 int
808 ib_add_service(char **errmsg)
809 {
810 	int		rval;
811 	char		*sbuf;
812 	boolean_t	found = B_FALSE;
813 	ib_token_t	token = NEWLINE;
814 
815 	DPRINTF("ib_add_service: type = %x, service_name=%s\n", service_type,
816 	    service_name);
817 	if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
818 		DPRINTF("ib_add_service: initializing file failed\n");
819 		return (rval);
820 	}
821 
822 	/* Start reading the file */
823 	while (token != EOF) {
824 		token = ib_get_services(errmsg);
825 		found = ib_cmp_service();
826 		if (found == B_TRUE) {
827 			DPRINTF("ib_add_service: token=%x, found=%x\n",
828 			    token, found);
829 			break;
830 		}
831 	}
832 
833 	/* Service shouldn't already exist while adding */
834 	if (found) {
835 		(void) snprintf(*errmsg, MAXPATHLEN, "service entry %s exists ",
836 		    service_name);
837 		DPRINTF("ib_add_service: invalid add operation\n");
838 		return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
839 	}
840 
841 	DPRINTF("!FOUND and adding\n");
842 	switch (service_type) {
843 		case IB_PORT_SERVICE :
844 			ibcfg_brec = bportrec;
845 			break;
846 		case IB_VPPA_SERVICE :
847 			ibcfg_brec = bvpparec;
848 			break;
849 		case IB_HCASVC_SERVICE :
850 			ibcfg_brec = bhcarec;
851 			break;
852 		default :
853 			DPRINTF("ib_add_service: invalid add operation\n");
854 			return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR));
855 	}
856 
857 
858 	if ((sbuf = (char *)calloc(12, sizeof (char))) == NULL) {
859 		DPRINTF("ib_add_service: failed to calloc sbuf %s file\n",
860 		    ibconf_file);
861 		return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
862 	}
863 	if (file_buf[ibcfg_brec] == '"' && file_buf[ibcfg_brec + 1] == '"') {
864 		(void) snprintf(sbuf, 9, "%s", service_name);
865 		ibcfg_brec += 1;
866 	} else
867 		(void) snprintf(sbuf, 9, "\"%s\", ", service_name);
868 
869 
870 	/* Seek to the beginning of the file */
871 	if (lseek(ibcfg_fd, ibcfg_brec, SEEK_SET) == -1) {
872 		DPRINTF("ib_add_service: lseek %s file failed\n", ibconf_file);
873 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
874 	}
875 
876 	/* Add service to w/ IBNEX  */
877 	if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_ADD)) {
878 		DPRINTF("ib_add_service: ioctl add failed %d\n", errno);
879 		(void) snprintf(*errmsg, MAXPATHLEN, "failed to add "
880 		    "%s service incore ", service_name);
881 		return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
882 	}
883 
884 	/* Write the modified file */
885 	if (write(ibcfg_fd, sbuf, strlen(sbuf)) == -1) {
886 		DPRINTF("ib_add_service: write %s file failed\n", ibconf_file);
887 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
888 	}
889 
890 	/* Write the rest of the file as it was */
891 	if (write(ibcfg_fd, file_buf + ibcfg_brec,
892 	    ibcfg_st.st_size - ibcfg_brec) == -1) {
893 		DPRINTF("ib_add_service: write %s file failed 2\n",
894 		    ibconf_file);
895 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
896 	}
897 
898 	return (ib_cleanup_file(rval));
899 }
900 
901 
902 /*
903  * Function:
904  *	ib_delete_service
905  * Input:
906  *	NONE
907  * Output:
908  *	errmsg		- Error message filled in case of a failure
909  * Returns:
910  *	CFGA_IB_OK on success or an appropriate error
911  * Description:
912  *	open ib.conf file and delete "service_name"
913  */
914 int
915 ib_delete_service(char **errmsg)
916 {
917 	int		rval;
918 	int		num_svcs;
919 	int		skip_len;
920 	int		sbuf_len;
921 	int		tot_len;
922 	char		tmp[12];
923 	char		*sbuf = (char *)NULL;
924 	boolean_t	found = B_FALSE;
925 	ib_token_t	token = NEWLINE;
926 	ib_svc_rec_t	*recp;
927 
928 	DPRINTF("ib_delete_service: type = %x, service_name=%s\n",
929 	    service_type, service_name);
930 	if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
931 		DPRINTF("ib_delete_service: initializing file failed\n");
932 		return (rval);
933 	}
934 
935 	/* Start reading the file */
936 	while (token != EOF) {
937 		token = ib_get_services(errmsg);
938 		found = ib_cmp_service();		/* search for a match */
939 		if (found == B_TRUE) {
940 			DPRINTF("ib_delete_service: token=%x, found=%x\n",
941 			    token, found);
942 			break;
943 		}
944 	}
945 
946 	/* No service found, return */
947 	if (!found) {
948 		DPRINTF("ib_delete_service: invalid delete operation\n");
949 		(void) snprintf(*errmsg, MAXPATHLEN, "service entry %s "
950 		    "does not exist ", service_name);
951 		return (ib_cleanup_file(CFGA_IB_SVC_NO_EXIST_ERR));
952 	}
953 
954 	DPRINTF("FOUND and deleting \n");
955 
956 	switch (service_type) {
957 		case IB_PORT_SERVICE :
958 			ibcfg_brec = bportrec;
959 			num_svcs = ibcfg_nport_services;
960 			break;
961 		case IB_VPPA_SERVICE :
962 			ibcfg_brec = bvpparec;
963 			num_svcs = ibcfg_nvppa_services;
964 			break;
965 		case IB_HCASVC_SERVICE :
966 			ibcfg_brec = bhcarec;
967 			num_svcs = ibcfg_nhca_services;
968 			break;
969 		default :
970 			DPRINTF("ib_delete_service: invalid delete "
971 			    "operation\n");
972 			return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR));
973 	}
974 
975 	if ((sbuf = (char *)calloc(num_svcs * 8, sizeof (char))) == NULL) {
976 		DPRINTF("ib_delete_service: sbuf alloc failed %s\n",
977 		    ibconf_file);
978 		return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
979 	}
980 
981 	if (num_svcs == 1) {
982 		(void) snprintf(sbuf, 9, "\"\"");
983 		sbuf_len = 2;
984 		skip_len = 0;
985 	} else {
986 		if (service_type == IB_PORT_SERVICE) {
987 			for (recp = ibcfg_port_head; recp; recp = recp->next) {
988 				if (strcmp(recp->name, service_name) == 0)
989 					continue;
990 				(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
991 				(void) strcat(sbuf, tmp);
992 			}
993 
994 		} else if (service_type == IB_VPPA_SERVICE) {
995 			for (recp = ibcfg_vppa_head; recp; recp = recp->next) {
996 				if (strcmp(recp->name, service_name) == 0)
997 					continue;
998 				(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
999 				(void) strcat(sbuf, tmp);
1000 			}
1001 		} else {
1002 			for (recp = ibcfg_hca_head; recp; recp = recp->next) {
1003 				if (strcmp(recp->name, service_name) == 0)
1004 					continue;
1005 				(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
1006 				(void) strcat(sbuf, tmp);
1007 			}
1008 		}
1009 		skip_len = 4;
1010 		sbuf_len = strlen(sbuf);
1011 		sbuf[sbuf_len - 2] = '\0';
1012 		sbuf_len -= 2;
1013 	}
1014 
1015 	tot_len = strlen(service_name) + skip_len;
1016 
1017 	tmpnamef = tmpnam(ibconf_file);
1018 	DPRINTF("ib_delete_service: tmpnamef = %s\n", tmpnamef);
1019 	if ((ibcfg_tmpfd = creat(tmpnamef, 0666)) == -1) {
1020 		(void) snprintf(*errmsg, MAXPATHLEN,
1021 		    "failed to creat %s file\n", ibconf_file);
1022 		DPRINTF("ib_delete_service: failed to creat tmpnamef\n");
1023 		return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
1024 	}
1025 
1026 	/* Delete service from IBNEX  */
1027 	if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_DEL)) {
1028 		DPRINTF("ib_delete_service: ioctl delete failed %d\n", errno);
1029 		(void) snprintf(*errmsg, MAXPATHLEN, "failed to delete "
1030 		    "in core %s entry ", service_name);
1031 		close(ibcfg_tmpfd);
1032 		unlink(tmpnamef);
1033 		return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
1034 	}
1035 
1036 	/* write till ibcfg_brec */
1037 	if (write(ibcfg_tmpfd, file_buf, ibcfg_brec) == -1) {
1038 		DPRINTF("ib_delete_service: write %s file failed 1\n",
1039 		    ibconf_file);
1040 		close(ibcfg_tmpfd);
1041 		unlink(tmpnamef);
1042 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
1043 	}
1044 
1045 	/* write modified buffer */
1046 	if (write(ibcfg_tmpfd, sbuf, sbuf_len) == -1) {
1047 		DPRINTF("ib_delete_service: write %s file failed 2\n",
1048 		    ibconf_file);
1049 		close(ibcfg_tmpfd);
1050 		unlink(tmpnamef);
1051 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
1052 	}
1053 
1054 	/* Write the rest of the file as it was */
1055 	if (write(ibcfg_tmpfd, file_buf + ibcfg_brec + sbuf_len + tot_len,
1056 	    ibcfg_st.st_size - ibcfg_brec - sbuf_len - tot_len) == -1) {
1057 		DPRINTF("ib_delete_service: write %s file failed 3\n",
1058 		    ibconf_file);
1059 		close(ibcfg_tmpfd);
1060 		unlink(tmpnamef);
1061 		return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
1062 	}
1063 	wrote_tmp = B_TRUE;
1064 
1065 	/* No error encountered */
1066 	return (ib_cleanup_file(rval));
1067 }
1068 
1069 
1070 /*
1071  * Function:
1072  *	ib_list_services
1073  * Input:
1074  *	msgp		- CFGADM message pointer
1075  * Output:
1076  *	errmsg		- Error message filled in case of a failure
1077  * Returns:
1078  *	CFGA_IB_OK on success or an appropriate error
1079  * Description:
1080  *	open IBCONF_FILE and list services.
1081  */
1082 int
1083 ib_list_services(struct cfga_msg *msgp, char **errmsg)
1084 {
1085 	int		rval = CFGA_IB_OK;
1086 	char		pbuf[IBCONF_SERVICE_HDR_LEN];
1087 	ib_token_t	token = NEWLINE;
1088 	ib_svc_rec_t	*recp;
1089 
1090 	DPRINTF("ib_list_services:\n");
1091 	if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
1092 		DPRINTF("ib_list_services: initializing file failed\n");
1093 		return (rval);
1094 	}
1095 
1096 	/* start reading the file */
1097 	while (token != EOF)
1098 		token = ib_get_services(errmsg);
1099 
1100 	DPRINTF("ib_list_services: #port_services = %d, #vppa_services = %d,"
1101 	    " #hca_services = %d\n", ibcfg_nport_services,
1102 	    ibcfg_nvppa_services, ibcfg_nhca_services);
1103 
1104 	bzero(pbuf, IBCONF_SERVICE_HDR_LEN);
1105 	if (ibcfg_nport_services) {
1106 		(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
1107 		    IBCONF_PORT_SERVICE_HDR);
1108 		cfga_msg(msgp, pbuf);
1109 		for (recp = ibcfg_port_head; recp; recp = recp->next) {
1110 			DPRINTF("ib_list_services: svc_name = %s\n",
1111 			    recp->name ? recp->name : "NONE");
1112 			(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
1113 			cfga_msg(msgp, pbuf);
1114 		}
1115 		(void) snprintf(pbuf, 2, "\n");
1116 		cfga_msg(msgp, pbuf);
1117 	}
1118 
1119 	if (ibcfg_nvppa_services) {
1120 		(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
1121 		    IBCONF_VPPA_SERVICE_HDR);
1122 		cfga_msg(msgp, pbuf);
1123 		for (recp = ibcfg_vppa_head; recp; recp = recp->next) {
1124 			DPRINTF("ib_list_services: svc_name = %s\n",
1125 			    strlen(recp->name) > 0 ? recp->name : "NONE");
1126 			(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
1127 			cfga_msg(msgp, pbuf);
1128 		}
1129 	}
1130 
1131 	if (ibcfg_nhca_services) {
1132 		(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
1133 		    IBCONF_HCA_SERVICE_HDR);
1134 		cfga_msg(msgp, pbuf);
1135 		for (recp = ibcfg_hca_head; recp; recp = recp->next) {
1136 			DPRINTF("ib_list_services: svc_name = %s\n",
1137 			    strlen(recp->name) > 0 ? recp->name : "NONE");
1138 			(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
1139 			cfga_msg(msgp, pbuf);
1140 		}
1141 	}
1142 	return (ib_cleanup_file(CFGA_IB_OK));
1143 }
1144 
1145 
1146 /*
1147  * Function:
1148  *	ib_conf_control_ioctl
1149  * Input:
1150  *	svc		- Service being added/deleted
1151  *	cmd		- Command to DEVCTL_AP_CONTROL devctl
1152  * Output:
1153  *	NONE
1154  * Returns:
1155  *	CFGA_IB_OK if it succeeds or an appropriate error.
1156  * Description:
1157  *	Issues DEVCTL_AP_CONTROL devctl with cmd
1158  */
1159 static cfga_ib_ret_t
1160 ib_conf_control_ioctl(char *svc, uint_t cmd)
1161 {
1162 	int			apid_fd = -1;
1163 	cfga_ib_ret_t		rv = CFGA_IB_OK;
1164 	struct ibnex_ioctl_data	ioctl_data;
1165 
1166 	DPRINTF("Service = %s len = %x, type = %x\n", svc,
1167 	    strlen(svc), service_type);
1168 
1169 	/* try to open the static IB ap_id */
1170 	if ((apid_fd = open(IB_STATIC_APID, O_RDONLY)) == -1) {
1171 		DPRINTF("ib_conf_control_ioctl: open failed: errno = %d\n",
1172 		    errno);
1173 		/* Provides a more useful error msg */
1174 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR;
1175 		return (rv);
1176 	}
1177 
1178 	ioctl_data.cmd = cmd;
1179 	ioctl_data.misc_arg = (uint_t)service_type;
1180 	ioctl_data.buf = (caddr_t)svc;
1181 	ioctl_data.bufsiz = strlen(svc);
1182 	ioctl_data.ap_id = (caddr_t)IB_STATIC_APID;
1183 	ioctl_data.ap_id_len = strlen(IB_STATIC_APID);
1184 
1185 	if (ioctl(apid_fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
1186 		DPRINTF("ib_conf_control_ioctl: size ioctl ERR, errno: %d\n",
1187 		    errno);
1188 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
1189 	}
1190 	(void) close(apid_fd);
1191 	return (rv);
1192 }
1193 
1194 /*
1195  * This functions checks if the service name is valid. Valid
1196  * service names have  :
1197  *		0 < strlen(name) <= 4
1198  *		Service name is unique
1199  * Returns: 	0 - Name is not valid, 1 - Name is valid
1200  */
1201 static int
1202 ib_service_record_valid(char *sname)
1203 {
1204 	int rc = 1, len;
1205 	char *tmp_service_name;
1206 
1207 	tmp_service_name = service_name;
1208 	service_name = strdup(sname);
1209 	len = strlen(sname);
1210 	if (len == 0 || len > 4) {
1211 		S_FREE(service_name);
1212 		service_name = tmp_service_name;
1213 		return (0);
1214 	}
1215 	if (ib_cmp_service() == B_TRUE)
1216 		rc = 0;
1217 	S_FREE(service_name);
1218 	service_name = tmp_service_name;
1219 	return (rc);
1220 }
1221