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
ib_get_var_type(char * str)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
ib_lex(char * val,char ** errmsg)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
ib_find_eol()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
ib_get_string(char ** llptr,char * tchar)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
ib_service_record_add(char * service,ib_service_type_t type)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
ib_get_services(char ** errmsg)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
ib_cmp_service()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
ib_free_service_recs(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
ib_cleanup_file(int rval)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
ib_init_file(char ** errmsg)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
ib_add_service(char ** errmsg)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
ib_delete_service(char ** errmsg)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
ib_list_services(struct cfga_msg * msgp,char ** errmsg)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
ib_conf_control_ioctl(char * svc,uint_t cmd)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
ib_service_record_valid(char * sname)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