xref: /titanic_41/usr/src/cmd/datadm/datadm.c (revision 1cfa752f4e24c34133009b0f6c139127a5c461de)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23   */
24  
25  #include <unistd.h>
26  #include <sys/types.h>
27  #include <sys/socket.h>
28  #include <sys/sockio.h>
29  #include <sys/stat.h>
30  #include <netinet/in.h>
31  #include <arpa/inet.h>
32  #include <net/if.h>
33  #include <stdio.h>
34  #include <stdlib.h>
35  #include <strings.h>
36  #include <ctype.h>
37  #include <errno.h>
38  #include <libintl.h>
39  #include <locale.h>
40  #include <fcntl.h>
41  #include <libdlpi.h>
42  #include <libdladm.h>
43  #include <libdlib.h>
44  #include <libdllink.h>
45  #include <sys/ib/ibnex/ibnex_devctl.h>
46  
47  #define	DATADM_OP_VIEW		0x0000
48  #define	DATADM_OP_UPDATE	0x0001
49  #define	DATADM_OP_ADD		0x0002
50  #define	DATADM_OP_REMOVE	0x0003
51  #define	DATADM_NUM_OPS		0x0004
52  #define	DATADM_DAT_CONF		"/etc/dat/dat.conf"
53  #define	DATADM_LINESZ		1024
54  #define	DATADM_NUM_SP_TOKENS	7
55  #define	DATADM_NUM_DAT_TOKENS	8
56  #define	DATADM_DRV_NAME		"driver_name"
57  #define	DATADM_MAX_TOKENS	16
58  
59  /*
60   * generic entry
61   * placed at the top of all entry types
62   */
63  typedef struct datadm_entry {
64  	struct datadm_entry	*de_next;
65  } datadm_entry_t;
66  
67  /*
68   * list structure
69   * can be manipulated using datadm_walk_list or
70   * datadm_enqueue_entry
71   */
72  typedef struct datadm_list {
73  	datadm_entry_t		*dl_head;
74  	datadm_entry_t		*dl_tail;
75  	uint_t			dl_count;
76  } datadm_list_t;
77  
78  /*
79   * internal representation of the version string in
80   * dat.conf or service_provider.conf. the format is
81   * <dv_name><dv_major>.<dv_minor>
82   */
83  typedef struct datadm_version {
84  	char	*dv_name;
85  	uint_t	dv_major;
86  	uint_t	dv_minor;
87  } datadm_version_t;
88  
89  /*
90   * each sp_entry corresponds to an entry in dat.conf or
91   * service_provider.conf. an sp_entry is processed by the
92   * function datadm_process_sp_entry.
93   */
94  typedef struct datadm_sp_entry {
95  	datadm_entry_t		spe_header;
96  	char			*spe_devname;
97  	datadm_version_t	spe_api_version;
98  	int			spe_threadsafe;
99  	int			spe_default;
100  	char			*spe_libpath;
101  	datadm_version_t	spe_sp_version;
102  	char			*spe_sp_data;
103  	int			spe_invalid;
104  } datadm_sp_entry_t;
105  
106  /*
107   * an hca_entry is created whenever a new hca device is
108   * encountered during sp_entry processing. this structure
109   * contains two lists. the sp_list holds sp entries that
110   * are added when sp entry processing occurs. duplicate
111   * sp entries are not added to this list. the ia_list may
112   * be built statically using the information in dat.conf or
113   * dynamically. similar to the sp_list,
114   * the ia_list contains only unique entries.
115   */
116  typedef struct datadm_hca_entry {
117  	datadm_entry_t		he_header;
118  	char			*he_name;
119  	datadm_list_t		he_sp_list;
120  	datadm_list_t		he_ia_list;
121  } datadm_hca_entry_t;
122  
123  /*
124   * an ia_entry is created when a new ia name is encountered
125   * during sp_entry processing or when a new ia name is
126   * discovered by datadm_build_ia_lists. ia_entry holds the ia
127   * device's instance number.
128   */
129  typedef struct datadm_ia_entry {
130  	datadm_entry_t		iae_header;
131  	char			iae_name[MAXLINKNAMELEN];
132  } datadm_ia_entry_t;
133  
134  /*
135   * a comment entry represents one of the comment lines at the
136   * top of dat.conf. a list of these lines are saved during the
137   * parsing of dat.conf. these lines are written back to dat.conf
138   * when dat.conf gets regenerated.
139   */
140  typedef struct datadm_cmnt_entry {
141  	datadm_entry_t		cmnt_header;
142  	char			*cmnt_line;
143  } datadm_cmnt_entry_t;
144  
145  typedef struct datadm_hca_find_by_name {
146  	char			*hf_name;
147  	datadm_hca_entry_t	*hf_hca_entry;
148  } datadm_hca_find_by_name_t;
149  
150  /*
151   * 2nd argument to datadm_hca_entry_find.
152   * hf_hca_entry is filled in if an hca_entry with
153   * a matching he_name is found.
154   */
155  typedef struct datadm_hca_find {
156  	datadm_sp_entry_t	*hf_sp_entry;
157  	datadm_hca_entry_t	*hf_hca_entry;
158  } datadm_hca_find_t;
159  
160  /*
161   * 2nd argument to datadm_ia_entry_find.
162   * if_ia_entry is filled in if an ia_entry with
163   * a matching ia_name is found.
164   */
165  typedef struct datadm_ia_find {
166  	char			*if_ia_name;
167  	datadm_ia_entry_t	*if_ia_entry;
168  } datadm_ia_find_t;
169  
170  /*
171   * this gets passed to datadm_add_plink.
172   */
173  typedef struct datadm_fill_ia_list {
174  	datadm_list_t		*ia_hca_list;
175  	dladm_handle_t		ia_dlh;
176  	int			ia_ibnex_fd;
177  	int			ia_sock_fd_v4;
178  	int			ia_sock_fd_v6;
179  } datadm_fill_ia_list_t;
180  
181  /*
182   * this defines the commandline parameters specified
183   * by the user.
184   */
185  typedef struct datadm_args {
186  	char			*da_sp_conf;
187  	char			*da_dat_conf;
188  	int			da_op_type;
189  } datadm_args_t;
190  
191  static datadm_args_t		datadm_args;
192  static datadm_list_t		datadm_conf_header;
193  static char			*datadm_conf_header_default =
194  	"#\n"
195  	"# Copyright (c) 2003, 2010, Oracle and/or its affiliates. "
196  	"All rights reserved.\n"
197  	"#\n"
198  	"# DAT configuration file.\n"
199  	"#\n"
200  	"# This file is updated using the datadm(1) command.\n"
201  	"# Do not hand edit this file.\n"
202  	"# See datadm(1) man page for more details.\n"
203  	"#\n"
204  	"# The fields in this file are -\n"
205  	"#\n"
206  	"# IAname version threadsafe default library-path provider-version \\\n"
207  	"# instance-data platform-information\n"
208  	"#\n";
209  
210  /*
211   * common parsing functions.
212   */
213  typedef int (*datadm_parse_func_t)(char *, void *);
214  static int datadm_parse_line(char *, char *[], int *);
215  static int datadm_parse_generic_str(char *, char **);
216  static int datadm_parse_nonnull_str(char *, char **);
217  static int datadm_parse_version(char *, datadm_version_t *);
218  static int datadm_parse_devname(char *, datadm_sp_entry_t *);
219  static int datadm_parse_api_version(char *, datadm_sp_entry_t *);
220  static int datadm_parse_threadsafe(char *, datadm_sp_entry_t *);
221  static int datadm_parse_default(char *, datadm_sp_entry_t *);
222  static int datadm_parse_libpath(char *, datadm_sp_entry_t *);
223  static int datadm_parse_sp_version(char *, datadm_sp_entry_t *);
224  static int datadm_parse_sp_data(char *, datadm_sp_entry_t *);
225  static int datadm_parse_ia_name(char *, char *);
226  
227  /*
228   * utility functions
229   */
230  static void datadm_enqueue_entry(datadm_list_t *, datadm_entry_t *);
231  static int datadm_walk_list(datadm_list_t *,
232      int (*)(datadm_entry_t *, void *), void *);
233  static int datadm_str_match(char *, char *);
234  static int datadm_version_match(datadm_version_t *, datadm_version_t *);
235  static int datadm_sp_entry_match(datadm_sp_entry_t *, datadm_sp_entry_t *);
236  
237  /*
238   * entry allocation/deallocation
239   */
240  static datadm_sp_entry_t *datadm_alloc_sp_entry(void);
241  static datadm_ia_entry_t *datadm_alloc_ia_entry(void);
242  static datadm_hca_entry_t *datadm_alloc_hca_entry(void);
243  static datadm_cmnt_entry_t *datadm_alloc_cmnt_entry(void);
244  static void datadm_free_sp_entry(datadm_sp_entry_t *);
245  static void datadm_free_ia_entry(datadm_ia_entry_t *);
246  static void datadm_free_hca_entry(datadm_hca_entry_t *);
247  static void datadm_free_cmnt_entry(datadm_cmnt_entry_t *);
248  
249  
250  /*
251   * high level parsing functions
252   */
253  static int datadm_parse_sp_conf(datadm_list_t *);
254  static int datadm_parse_dat_conf(datadm_list_t *);
255  static int datadm_process_sp_entry(datadm_list_t *, datadm_sp_entry_t *,
256      char *);
257  
258  /*
259   * ia devices discovery
260   */
261  static int datadm_build_ia_lists(datadm_list_t *);
262  
263  /*
264   * helper function for OP_REMOVE
265   */
266  static void datadm_invalidate_common_sp_entries(datadm_list_t *,
267      datadm_list_t *);
268  
269  /*
270   * output generation
271   */
272  static int datadm_generate_dat_conf(datadm_list_t *);
273  static int datadm_generate_conf_header(FILE *);
274  static int datadm_generate_conf_entry(FILE *, datadm_ia_entry_t *,
275      datadm_sp_entry_t *);
276  
277  /*
278   * datadm operations
279   */
280  static int datadm_view(void);
281  static int datadm_update(void);
282  static int datadm_add(void);
283  static int datadm_remove(void);
284  
285  /*
286   * usage
287   */
288  static void datadm_usage(void);
289  
290  
291  /*
292   * parse function tables
293   */
294  static datadm_parse_func_t datadm_sp_parse_funcs[DATADM_NUM_SP_TOKENS] = {
295  	(datadm_parse_func_t)datadm_parse_devname,
296  	(datadm_parse_func_t)datadm_parse_api_version,
297  	(datadm_parse_func_t)datadm_parse_threadsafe,
298  	(datadm_parse_func_t)datadm_parse_default,
299  	(datadm_parse_func_t)datadm_parse_libpath,
300  	(datadm_parse_func_t)datadm_parse_sp_version,
301  	(datadm_parse_func_t)datadm_parse_sp_data
302  };
303  
304  static datadm_parse_func_t datadm_dat_parse_funcs[DATADM_NUM_DAT_TOKENS] = {
305  	(datadm_parse_func_t)datadm_parse_ia_name,
306  	(datadm_parse_func_t)datadm_parse_api_version,
307  	(datadm_parse_func_t)datadm_parse_threadsafe,
308  	(datadm_parse_func_t)datadm_parse_default,
309  	(datadm_parse_func_t)datadm_parse_libpath,
310  	(datadm_parse_func_t)datadm_parse_sp_version,
311  	(datadm_parse_func_t)datadm_parse_sp_data,
312  	(datadm_parse_func_t)datadm_parse_devname
313  };
314  
315  /*
316   * operation table
317   */
318  static int (*datadm_ops[DATADM_NUM_OPS])(void) = {
319  	datadm_view,
320  	datadm_update,
321  	datadm_add,
322  	datadm_remove
323  };
324  
325  static void
datadm_usage(void)326  datadm_usage(void)
327  {
328  	(void) fprintf(stderr, gettext(
329  	    "usage: datadm -v\n"
330  	    "              -u\n"
331  	    "              -a <service_provider.conf>\n"
332  	    "              -r <service_provider.conf>\n"));
333  }
334  
335  static int
datadm_parse_generic_str(char * str,char ** strptr)336  datadm_parse_generic_str(char *str, char **strptr)
337  {
338  	int	len;
339  
340  	len = strlen(str);
341  	*strptr = (char *)malloc(len + 1);
342  	if (*strptr == NULL) {
343  		return (-1);
344  	}
345  	(void) strcpy(*strptr, str);
346  	return (0);
347  }
348  
349  /*
350   * this function strips off leading and trailing
351   * whitespaces and returns an error for null or
352   * empty strings.
353   */
354  static int
datadm_parse_nonnull_str(char * str,char ** strptr)355  datadm_parse_nonnull_str(char *str, char **strptr)
356  {
357  	int	len, i;
358  	char	*start;
359  
360  	if (str[0] == '\0') {
361  		return (-1);
362  	}
363  	start = str;
364  	for (i = 0; str[i] != '\0'; i++) {
365  		if (!isspace(str[i])) {
366  			start = &str[i];
367  			break;
368  		}
369  	}
370  	for (; str[i] != '\0'; i++) {
371  		if (isspace(str[i])) {
372  			str[i] = '\0';
373  		}
374  	}
375  	len = strlen(start);
376  	*strptr = (char *)malloc(len + 1);
377  	if (*strptr == NULL) {
378  		return (-1);
379  	}
380  	(void) strcpy(*strptr, start);
381  	return (0);
382  }
383  
384  /*
385   * parses the api_version and sp_version fields in
386   * dat.conf and service_provider.conf
387   */
388  static int
datadm_parse_version(char * str,datadm_version_t * version)389  datadm_parse_version(char *str, datadm_version_t *version)
390  {
391  	int	i = 0, len;
392  	int	major_idx, minor_idx;
393  
394  	len = strlen(str);
395  
396  	for (i = 0; i < len; i++) {
397  		if (isdigit(str[i])) break;
398  	}
399  	if (i == len) {
400  		return (-1);
401  	}
402  	if (i > 0) {
403  		version->dv_name = (char *)malloc(i + 1);
404  		bcopy(str, version->dv_name, i);
405  		version->dv_name[i] = '\0';
406  	} else {
407  		version->dv_name = NULL;
408  	}
409  	major_idx = i;
410  
411  	for (; i < len; i++) {
412  		if (!isdigit(str[i])) break;
413  	}
414  	if (i == len) {
415  		return (-1);
416  	}
417  	if (str[i] != '.') {
418  		return (-1);
419  	}
420  	minor_idx = ++i;
421  	if (i == len) {
422  		return (-1);
423  	}
424  	for (; i < len; i++) {
425  		if (!isdigit(str[i])) break;
426  	}
427  	if (i != len) {
428  		return (-1);
429  	}
430  	version->dv_major = atoi(str + major_idx);
431  	version->dv_minor = atoi(str + minor_idx);
432  	return (0);
433  }
434  
435  /*
436   * parses the ia_name field in dat.conf
437   */
438  static int
datadm_parse_ia_name(char * str,char * ia_name)439  datadm_parse_ia_name(char *str, char *ia_name)
440  {
441  	if (strlen(str) >= MAXLINKNAMELEN)
442  		return (-1);
443  	(void) strlcpy(ia_name, str, MAXLINKNAMELEN);
444  	return (0);
445  }
446  
447  /*
448   * parses the device name, strips leading and trailing spaces.
449   * the format should be "driver_name=<dev_name>"
450   */
451  static int
datadm_parse_devname(char * str,datadm_sp_entry_t * sp_entry)452  datadm_parse_devname(char *str, datadm_sp_entry_t *sp_entry)
453  {
454  	int	len, dlen, i, j = 0;
455  	char	*drv_name = DATADM_DRV_NAME;
456  
457  	len = strlen(str);
458  	dlen = strlen(drv_name);
459  
460  	/*
461  	 * strip out leading spaces and try to match
462  	 * the expected string
463  	 */
464  	for (i = 0; i < len; i++) {
465  		if (isspace(str[i]) && j == 0) {
466  			continue;
467  		} else {
468  			if (str[i] == drv_name[j]) {
469  				j++;
470  				if (j == dlen) {
471  					break;
472  				} else {
473  					continue;
474  				}
475  			} else {
476  				break;
477  			}
478  		}
479  	}
480  
481  	/*
482  	 * j must be dlen if the matching string is found
483  	 */
484  	if (j != dlen) {
485  		return (-1);
486  	}
487  
488  	/*
489  	 * skip past the last char of drv_name
490  	 */
491  	i++;
492  
493  	/*
494  	 * strip the spaces before the '='
495  	 */
496  	for (; i < len; i++) {
497  		if (!isspace(str[i])) {
498  			break;
499  		}
500  	}
501  
502  	/*
503  	 * return if the string is too long or if
504  	 * the '=' isn't found
505  	 */
506  	if (i >= len || str[i] != '=') {
507  		return (-1);
508  	}
509  	i++;
510  	if (i >= len) {
511  		/*
512  		 * no string after the equal
513  		 */
514  		return (-1);
515  	}
516  	return (datadm_parse_nonnull_str(str + i, &sp_entry->spe_devname));
517  }
518  
519  static int
datadm_parse_api_version(char * str,datadm_sp_entry_t * sp_entry)520  datadm_parse_api_version(char *str, datadm_sp_entry_t *sp_entry)
521  {
522  	return (datadm_parse_version(str, &sp_entry->spe_api_version));
523  }
524  
525  static int
datadm_parse_threadsafe(char * str,datadm_sp_entry_t * sp_entry)526  datadm_parse_threadsafe(char *str, datadm_sp_entry_t *sp_entry)
527  {
528  	int retval = 0;
529  
530  	if (strcmp(str, "threadsafe") == 0) {
531  		sp_entry->spe_threadsafe = 1;
532  	} else if (strcmp(str, "nonthreadsafe") == 0) {
533  		sp_entry->spe_threadsafe = 0;
534  	} else {
535  		retval = -1;
536  	}
537  	return (retval);
538  }
539  
540  static int
datadm_parse_default(char * str,datadm_sp_entry_t * sp_entry)541  datadm_parse_default(char *str, datadm_sp_entry_t *sp_entry)
542  {
543  	int retval = 0;
544  
545  	if (strcmp(str, "default") == 0) {
546  		sp_entry->spe_default = 1;
547  	} else if (strcmp(str, "nondefault") == 0) {
548  		sp_entry->spe_default = 0;
549  	} else {
550  		retval = -1;
551  	}
552  	return (retval);
553  }
554  
555  static int
datadm_parse_libpath(char * str,datadm_sp_entry_t * sp_entry)556  datadm_parse_libpath(char *str, datadm_sp_entry_t *sp_entry)
557  {
558  	return (datadm_parse_nonnull_str(str, &sp_entry->spe_libpath));
559  }
560  
561  static int
datadm_parse_sp_version(char * str,datadm_sp_entry_t * sp_entry)562  datadm_parse_sp_version(char *str, datadm_sp_entry_t *sp_entry)
563  {
564  	return (datadm_parse_version(str, &sp_entry->spe_sp_version));
565  }
566  
567  static int
datadm_parse_sp_data(char * str,datadm_sp_entry_t * sp_entry)568  datadm_parse_sp_data(char *str, datadm_sp_entry_t *sp_entry)
569  {
570  	return (datadm_parse_generic_str(str, &sp_entry->spe_sp_data));
571  }
572  
573  static void
datadm_enqueue_entry(datadm_list_t * list,datadm_entry_t * entry)574  datadm_enqueue_entry(datadm_list_t *list, datadm_entry_t *entry)
575  {
576  	if (list->dl_head == NULL) {
577  		list->dl_head = entry;
578  		list->dl_tail = entry;
579  		list->dl_count = 1;
580  	} else {
581  		list->dl_tail->de_next = entry;
582  		list->dl_tail = entry;
583  		list->dl_count++;
584  	}
585  }
586  
587  /*
588   * iterates through the list applying func on each element.
589   * break and return if func returns non-zero.
590   */
591  static int
datadm_walk_list(datadm_list_t * list,int (* func)(datadm_entry_t *,void *),void * arg)592  datadm_walk_list(datadm_list_t *list, int (*func)(datadm_entry_t *, void *),
593  	void *arg)
594  {
595  	datadm_entry_t	*entry;
596  	int		retval = 0;
597  
598  	entry = list->dl_head;
599  	while (entry != NULL) {
600  		retval = (*func)(entry, arg);
601  		if (retval != 0) break;
602  		entry = entry->de_next;
603  	}
604  	return (retval);
605  }
606  
607  /*
608   * iterates through the list applying free_func to each element.
609   * list becomes empty when the function returns.
610   */
611  static void
datadm_free_list(datadm_list_t * list,void (* free_func)(datadm_entry_t *))612  datadm_free_list(datadm_list_t *list, void (*free_func)(datadm_entry_t *))
613  {
614  	while (list->dl_head != NULL) {
615  		datadm_entry_t	*entry;
616  
617  		entry = list->dl_head;
618  		list->dl_head = entry->de_next;
619  		(*free_func)(entry);
620  	}
621  	list->dl_count = 0;
622  	list->dl_tail = NULL;
623  }
624  
625  static datadm_sp_entry_t *
datadm_alloc_sp_entry(void)626  datadm_alloc_sp_entry(void)
627  {
628  	datadm_sp_entry_t	*sp_entry;
629  
630  	sp_entry = (datadm_sp_entry_t *)malloc(sizeof (*sp_entry));
631  	if (sp_entry == NULL) {
632  		return (NULL);
633  	}
634  	bzero(sp_entry, sizeof (*sp_entry));
635  	return (sp_entry);
636  }
637  
638  static void
datadm_free_sp_entry(datadm_sp_entry_t * sp_entry)639  datadm_free_sp_entry(datadm_sp_entry_t *sp_entry)
640  {
641  	if (sp_entry->spe_devname != NULL) {
642  		free(sp_entry->spe_devname);
643  		sp_entry->spe_devname = NULL;
644  	}
645  	if (sp_entry->spe_api_version.dv_name != NULL) {
646  		free(sp_entry->spe_api_version.dv_name);
647  		sp_entry->spe_api_version.dv_name = NULL;
648  	}
649  	sp_entry->spe_api_version.dv_major = 0;
650  	sp_entry->spe_api_version.dv_minor = 0;
651  	sp_entry->spe_threadsafe = 0;
652  	sp_entry->spe_default = 0;
653  	if (sp_entry->spe_libpath != NULL) {
654  		free(sp_entry->spe_libpath);
655  		sp_entry->spe_libpath = NULL;
656  	}
657  	if (sp_entry->spe_sp_version.dv_name != NULL) {
658  		free(sp_entry->spe_sp_version.dv_name);
659  		sp_entry->spe_sp_version.dv_name = NULL;
660  	}
661  	sp_entry->spe_sp_version.dv_major = 0;
662  	sp_entry->spe_sp_version.dv_minor = 0;
663  	if (sp_entry->spe_sp_data != NULL) {
664  		free(sp_entry->spe_sp_data);
665  		sp_entry->spe_sp_data = NULL;
666  	}
667  	free(sp_entry);
668  }
669  
670  static int
datadm_str_match(char * s1,char * s2)671  datadm_str_match(char *s1, char *s2)
672  {
673  	if (s1 == NULL || s2 == NULL) {
674  		if (s1 != s2) {
675  			return (0);
676  		}
677  	} else {
678  		if (strcmp(s1, s2) != 0) {
679  			return (0);
680  		}
681  	}
682  	return (1);
683  }
684  
685  static int
datadm_version_match(datadm_version_t * v1,datadm_version_t * v2)686  datadm_version_match(datadm_version_t *v1, datadm_version_t *v2)
687  {
688  	if (!datadm_str_match(v1->dv_name, v2->dv_name)) {
689  		return (0);
690  	}
691  	if (v1->dv_major != v2->dv_major) {
692  		return (0);
693  	}
694  	if (v1->dv_minor != v2->dv_minor) {
695  		return (0);
696  	}
697  	return (1);
698  }
699  
700  static int
datadm_sp_entry_match(datadm_sp_entry_t * sp1,datadm_sp_entry_t * sp2)701  datadm_sp_entry_match(datadm_sp_entry_t *sp1, datadm_sp_entry_t *sp2)
702  {
703  	if (!datadm_str_match(sp1->spe_devname, sp2->spe_devname)) {
704  		return (0);
705  	}
706  	if (!datadm_version_match(&sp1->spe_api_version,
707  	    &sp2->spe_api_version)) {
708  		return (0);
709  	}
710  	if (sp1->spe_threadsafe != sp2->spe_threadsafe) {
711  		return (0);
712  	}
713  	if (sp2->spe_default != sp2->spe_default) {
714  		return (0);
715  	}
716  	if (!datadm_str_match(sp1->spe_libpath, sp2->spe_libpath)) {
717  		return (0);
718  	}
719  	if (!datadm_version_match(&sp1->spe_sp_version,
720  	    &sp2->spe_sp_version)) {
721  		return (0);
722  	}
723  	if (!datadm_str_match(sp1->spe_sp_data, sp2->spe_sp_data)) {
724  		return (0);
725  	}
726  	return (1);
727  }
728  
729  static datadm_ia_entry_t *
datadm_alloc_ia_entry(void)730  datadm_alloc_ia_entry(void)
731  {
732  	datadm_ia_entry_t	*ia_entry;
733  
734  	ia_entry = (datadm_ia_entry_t *)malloc(sizeof (*ia_entry));
735  	if (ia_entry == NULL) {
736  		return (NULL);
737  	}
738  	bzero(ia_entry, sizeof (*ia_entry));
739  	return (ia_entry);
740  }
741  
742  static void
datadm_free_ia_entry(datadm_ia_entry_t * ia_entry)743  datadm_free_ia_entry(datadm_ia_entry_t *ia_entry)
744  {
745  	free(ia_entry);
746  }
747  
748  static datadm_hca_entry_t *
datadm_alloc_hca_entry(void)749  datadm_alloc_hca_entry(void)
750  {
751  	datadm_hca_entry_t	*hca_entry;
752  
753  	hca_entry = (datadm_hca_entry_t *)malloc(sizeof (*hca_entry));
754  	if (hca_entry == NULL) {
755  		return (NULL);
756  	}
757  	bzero(hca_entry, sizeof (*hca_entry));
758  	return (hca_entry);
759  }
760  
761  static void
datadm_free_hca_entry(datadm_hca_entry_t * hca_entry)762  datadm_free_hca_entry(datadm_hca_entry_t *hca_entry)
763  {
764  	if (hca_entry->he_name != NULL) {
765  		free(hca_entry->he_name);
766  		hca_entry->he_name = NULL;
767  	}
768  	datadm_free_list(&hca_entry->he_sp_list,
769  	    (void (*)(datadm_entry_t *))datadm_free_sp_entry);
770  	datadm_free_list(&hca_entry->he_ia_list,
771  	    (void (*)(datadm_entry_t *))datadm_free_ia_entry);
772  	free(hca_entry);
773  }
774  
775  static int
datadm_hca_entry_match(datadm_hca_entry_t * h1,datadm_hca_entry_t * h2)776  datadm_hca_entry_match(datadm_hca_entry_t *h1, datadm_hca_entry_t *h2)
777  {
778  	if (!datadm_str_match(h1->he_name, h2->he_name)) {
779  		return (0);
780  	}
781  	return (1);
782  }
783  
784  static int
datadm_hca_entry_find(datadm_hca_entry_t * h1,datadm_hca_find_t * hf)785  datadm_hca_entry_find(datadm_hca_entry_t *h1, datadm_hca_find_t *hf)
786  {
787  	if (datadm_str_match(h1->he_name, hf->hf_sp_entry->spe_devname)) {
788  		hf->hf_hca_entry = h1;
789  		return (1);
790  	}
791  	return (0);
792  }
793  
794  static int
datadm_ia_entry_find(datadm_ia_entry_t * i1,datadm_ia_find_t * iaf)795  datadm_ia_entry_find(datadm_ia_entry_t *i1, datadm_ia_find_t *iaf)
796  {
797  	if (strcmp(i1->iae_name, iaf->if_ia_name) == 0) {
798  		iaf->if_ia_entry = i1;
799  		return (1);
800  	}
801  	return (0);
802  }
803  
804  static datadm_cmnt_entry_t *
datadm_alloc_cmnt_entry(void)805  datadm_alloc_cmnt_entry(void)
806  {
807  	datadm_cmnt_entry_t	*cmnt_entry;
808  
809  	cmnt_entry = (datadm_cmnt_entry_t *)malloc(sizeof (*cmnt_entry));
810  	if (cmnt_entry == NULL) {
811  		return (NULL);
812  	}
813  	bzero(cmnt_entry, sizeof (*cmnt_entry));
814  	return (cmnt_entry);
815  }
816  
817  static void
datadm_free_cmnt_entry(datadm_cmnt_entry_t * cmnt_entry)818  datadm_free_cmnt_entry(datadm_cmnt_entry_t *cmnt_entry)
819  {
820  	if (cmnt_entry->cmnt_line != NULL) {
821  		free(cmnt_entry->cmnt_line);
822  		cmnt_entry->cmnt_line = NULL;
823  	}
824  	free(cmnt_entry);
825  }
826  
827  /*
828   * tokenizes a line and strips off the quotes from quoted strings
829   */
830  static int
datadm_parse_line(char * line_buf,char * tokens[],int * token_count)831  datadm_parse_line(char *line_buf, char *tokens[], int *token_count)
832  {
833  	int			len, i;
834  	int			count = 0;
835  	char			*start = NULL;
836  
837  	/* the line must not be longer than DATADM_LINESZ */
838  	len = strlen(line_buf);
839  	if (line_buf[len - 1] != '\n') {
840  		return (-1);
841  	}
842  	/* discard blank lines and comments */
843  	if (len == 1) {
844  		*token_count = 0;
845  		return (0);
846  	}
847  	if (len >= 2 && line_buf[0] == '#') {
848  		*token_count = 0;
849  		return (0);
850  	}
851  	/* removes the new line */
852  	line_buf[len - 1] = '\0';
853  	len--;
854  
855  	for (i = 0; i < len; i++) {
856  		if (start != NULL) {
857  			/*
858  			 * start points to the start of
859  			 * a new token. if start is '"',
860  			 * we should expect a quoted
861  			 * string.
862  			 */
863  			if (*start == '\"') {
864  				/*
865  				 * keep scanning until we
866  				 * hit the end quote.
867  				 */
868  				if (line_buf[i] != '\"') {
869  					continue;
870  				}
871  				/*
872  				 * skip past the start quote
873  				 */
874  				start++;
875  			} else {
876  				/*
877  				 * our token is not a quoted
878  				 * string. our token ends only
879  				 * when we hit a whitespace.
880  				 */
881  				if (!isspace(line_buf[i])) {
882  					continue;
883  				}
884  			}
885  			/*
886  			 * nullify the end quote (if any)
887  			 * and update the tokens array.
888  			 */
889  			line_buf[i] = '\0';
890  			tokens[count] = start;
891  			start = NULL;
892  			count++;
893  		} else {
894  			/*
895  			 * skip whitespaces
896  			 */
897  			if (isspace(line_buf[i])) {
898  				continue;
899  			} else {
900  				start = &line_buf[i];
901  			}
902  		}
903  		if (count == DATADM_MAX_TOKENS) {
904  			start = NULL;
905  			break;
906  		}
907  	}
908  	if (start != NULL) {
909  		tokens[count] = start;
910  		start = NULL;
911  		count++;
912  	}
913  	*token_count = count;
914  	return (0);
915  }
916  
917  /*
918   * attempts to save sp_entry into hca_list.
919   * becomes no-op if sp entry already exists.
920   * new hca entries and ia entries are created as needed.
921   */
922  static int
datadm_process_sp_entry(datadm_list_t * hca_list,datadm_sp_entry_t * sp_entry,char * ia_name)923  datadm_process_sp_entry(datadm_list_t *hca_list, datadm_sp_entry_t *sp_entry,
924  	char *ia_name)
925  {
926  	datadm_hca_find_t	hca_find;
927  	datadm_ia_find_t	ia_find;
928  	datadm_hca_entry_t	*hca_entry;
929  
930  	hca_find.hf_sp_entry = sp_entry;
931  	hca_find.hf_hca_entry = NULL;
932  	(void) datadm_walk_list(hca_list, (int (*)(datadm_entry_t *, void *))
933  	    datadm_hca_entry_find, (void *)&hca_find);
934  
935  	if (hca_find.hf_hca_entry == NULL) {
936  		int	dlen;
937  
938  		/*
939  		 * hca_entry not found, need to create
940  		 * and insert one.
941  		 */
942  		hca_entry = datadm_alloc_hca_entry();
943  		if (hca_entry == NULL) {
944  			return (-1);
945  		}
946  		dlen = strlen(sp_entry->spe_devname);
947  		hca_entry->he_name = (char *)malloc(dlen + 1);
948  		if (hca_entry->he_name == NULL) {
949  			datadm_free_hca_entry(hca_entry);
950  			return (-1);
951  		}
952  		(void) strcpy(hca_entry->he_name, sp_entry->spe_devname);
953  		datadm_enqueue_entry(hca_list, (datadm_entry_t *)hca_entry);
954  	} else {
955  		hca_entry = hca_find.hf_hca_entry;
956  	}
957  	if (ia_name == NULL) {
958  		goto put_sp_entry;
959  	}
960  	ia_find.if_ia_name = ia_name;
961  	ia_find.if_ia_entry = NULL;
962  	(void) datadm_walk_list(&hca_entry->he_ia_list,
963  	    (int (*)(datadm_entry_t *, void *))datadm_ia_entry_find, &ia_find);
964  
965  	if (ia_find.if_ia_entry == NULL) {
966  		datadm_ia_entry_t	*ia_entry;
967  
968  		/*
969  		 * ia_entry not found, need to create
970  		 * and insert one.
971  		 */
972  		ia_entry = datadm_alloc_ia_entry();
973  		if (ia_entry == NULL) {
974  			return (-1);
975  		}
976  		(void) strlcpy(ia_entry->iae_name, ia_name, MAXLINKNAMELEN);
977  		datadm_enqueue_entry(&hca_entry->he_ia_list,
978  		    (datadm_entry_t *)ia_entry);
979  	}
980  
981  put_sp_entry:;
982  
983  	if (datadm_walk_list(&hca_entry->he_sp_list,
984  	    (int (*)(datadm_entry_t *, void *))datadm_sp_entry_match,
985  	    (void *)sp_entry)) {
986  		return (1);
987  	} else {
988  		/*
989  		 * only insert sp_entry if it is not found.
990  		 */
991  		datadm_enqueue_entry(&hca_entry->he_sp_list,
992  		    (datadm_entry_t *)sp_entry);
993  	}
994  	return (0);
995  }
996  
997  /*
998   * parses service_provider.conf
999   */
1000  static int
datadm_parse_sp_conf(datadm_list_t * hca_list)1001  datadm_parse_sp_conf(datadm_list_t *hca_list)
1002  {
1003  	datadm_sp_entry_t	*sp_entry;
1004  	FILE			*sp_file;
1005  	char			*sp_conf = datadm_args.da_sp_conf;
1006  	char			*tokens[DATADM_MAX_TOKENS];
1007  	char			line_buf[DATADM_LINESZ];
1008  	int			retval = 0;
1009  	int			token_count = 0;
1010  	int			line_count = 0;
1011  
1012  	sp_file = fopen(sp_conf, "r");
1013  	if (sp_file == NULL) {
1014  		(void) fprintf(stderr,
1015  		    gettext("datadm: cannot open %s\n"), sp_conf);
1016  		return (-1);
1017  	}
1018  
1019  	for (;;) {
1020  		bzero(line_buf, DATADM_LINESZ);
1021  		if (fgets(line_buf, DATADM_LINESZ, sp_file) == NULL) {
1022  			break;
1023  		}
1024  		token_count = 0;
1025  		line_count++;
1026  		retval = datadm_parse_line(line_buf, tokens, &token_count);
1027  		if (retval != 0) {
1028  			(void) fprintf(stderr, gettext(
1029  			    "datadm: %s: line %d exceeded max length %d\n"),
1030  			    sp_conf, line_count, DATADM_LINESZ);
1031  			break;
1032  		}
1033  		if (token_count == 0) continue;
1034  		if (token_count == DATADM_NUM_SP_TOKENS) {
1035  			int i = 0;
1036  
1037  			sp_entry = datadm_alloc_sp_entry();
1038  			if (sp_entry == NULL) {
1039  				retval = -1;
1040  				break;
1041  			}
1042  
1043  			/*
1044  			 * sp_entry gets filled incrementally by
1045  			 * each parsing function
1046  			 */
1047  			for (i = 0; i < DATADM_NUM_SP_TOKENS &&
1048  			    retval == 0; i++) {
1049  				retval = (*datadm_sp_parse_funcs[i])
1050  				    (tokens[i], (void *)sp_entry);
1051  			}
1052  			if (retval != 0) {
1053  				(void) fprintf(stderr, gettext(
1054  				    "datadm: parse error: %s, "
1055  				    "line %d, token: %s\n"),
1056  				    sp_conf, line_count, tokens[i - 1]);
1057  				datadm_free_sp_entry(sp_entry);
1058  				sp_entry = NULL;
1059  				break;
1060  			}
1061  
1062  			retval = datadm_process_sp_entry(hca_list,
1063  			    sp_entry, NULL);
1064  			if (retval != 0) {
1065  				datadm_free_sp_entry(sp_entry);
1066  				if (retval == 1) {
1067  					retval = 0;
1068  				} else {
1069  					break;
1070  				}
1071  			}
1072  		} else {
1073  			(void) fprintf(stderr, gettext(
1074  			    "datadm: parse error: %s, line %d, "
1075  			    "# of tokens: %d, expected %d\n"), sp_conf,
1076  			    line_count, token_count, DATADM_NUM_SP_TOKENS);
1077  			retval = -1;
1078  			break;
1079  		}
1080  	}
1081  	if (retval != 0) {
1082  		datadm_free_list(hca_list,
1083  		    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1084  	}
1085  	(void) fclose(sp_file);
1086  	return (retval);
1087  }
1088  
1089  /*
1090   * parses dat.conf
1091   */
1092  static int
datadm_parse_dat_conf(datadm_list_t * hca_list)1093  datadm_parse_dat_conf(datadm_list_t *hca_list)
1094  {
1095  	boolean_t		save_header = B_TRUE;
1096  	datadm_sp_entry_t	*sp_entry;
1097  	FILE			*dat_file;
1098  	char			*dat_conf = datadm_args.da_dat_conf;
1099  	char			*tokens[DATADM_MAX_TOKENS];
1100  	char			line_buf[DATADM_LINESZ];
1101  	int			retval = 0;
1102  	int			token_count = 0;
1103  	int			line_count = 0;
1104  
1105  	dat_file = fopen(dat_conf, "r");
1106  	if (dat_file == NULL) {
1107  		/* dat.conf not existing is not an error for OP_ADD */
1108  		if (datadm_args.da_op_type == DATADM_OP_ADD) {
1109  			return (0);
1110  		}
1111  		(void) fprintf(stderr, gettext("datadm: cannot open %s\n"),
1112  		    dat_conf);
1113  		return (-1);
1114  	}
1115  
1116  	for (;;) {
1117  		bzero(line_buf, DATADM_LINESZ);
1118  		if (fgets(line_buf, DATADM_LINESZ, dat_file) == NULL) {
1119  			break;
1120  		}
1121  		token_count = 0;
1122  		line_count++;
1123  		retval = datadm_parse_line(line_buf, tokens, &token_count);
1124  		if (retval != 0) {
1125  			(void) fprintf(stderr, gettext(
1126  			    "datadm: %s: line %d exceeded max length %d\n"),
1127  			    dat_conf, line_count, DATADM_LINESZ);
1128  			break;
1129  		}
1130  		if (token_count == 0) {
1131  			datadm_cmnt_entry_t	*cmnt_entry;
1132  			int			cmnt_len;
1133  
1134  			/*
1135  			 * comments are saved only if they are
1136  			 * at the top of dat.conf.
1137  			 */
1138  			if (!save_header) continue;
1139  			cmnt_entry = datadm_alloc_cmnt_entry();
1140  			if (cmnt_entry == NULL) {
1141  				perror("datadm: malloc");
1142  				retval = -1;
1143  				break;
1144  			}
1145  			cmnt_len = strlen(line_buf);
1146  			cmnt_entry->cmnt_line = (char *)malloc(cmnt_len + 1);
1147  			if (cmnt_entry->cmnt_line == NULL) {
1148  				perror("datadm: malloc");
1149  				datadm_free_cmnt_entry(cmnt_entry);
1150  				retval = -1;
1151  				break;
1152  			}
1153  			(void) strncpy(cmnt_entry->cmnt_line,
1154  			    line_buf, cmnt_len);
1155  			cmnt_entry->cmnt_line[cmnt_len] = '\0';
1156  			datadm_enqueue_entry(&datadm_conf_header,
1157  			    (datadm_entry_t *)cmnt_entry);
1158  			continue;
1159  		}
1160  		if (token_count == DATADM_NUM_DAT_TOKENS) {
1161  			int i = 0;
1162  			char ia_name[MAXLINKNAMELEN];
1163  
1164  			/*
1165  			 * we stop saving comment lines once
1166  			 * we see the first valid line.
1167  			 */
1168  			save_header = B_FALSE;
1169  			sp_entry = datadm_alloc_sp_entry();
1170  			if (sp_entry == NULL) {
1171  				retval = -1;
1172  				break;
1173  			}
1174  
1175  			/*
1176  			 * sp_entry gets filled incrementally by
1177  			 * each parsing function
1178  			 */
1179  			for (i = 0; i < DATADM_NUM_DAT_TOKENS &&
1180  			    retval == 0; i++) {
1181  				void	*arg;
1182  
1183  				if (i == 0) {
1184  					/*
1185  					 * the first token (ia name)
1186  					 * does not belong to an
1187  					 * sp_entry
1188  					 */
1189  					arg = (void *)ia_name;
1190  				} else {
1191  					arg = (void *)sp_entry;
1192  				}
1193  				retval = (*datadm_dat_parse_funcs[i])
1194  				    (tokens[i], arg);
1195  			}
1196  			if (retval != 0) {
1197  				(void) fprintf(stderr, gettext(
1198  				    "datadm: parse error: %s, "
1199  				    "line %d, token: %s\n"), dat_conf,
1200  				    line_count, tokens[i - 1]);
1201  				datadm_free_sp_entry(sp_entry);
1202  				sp_entry = NULL;
1203  				break;
1204  			}
1205  
1206  			/*
1207  			 * we ignore the ibds in dat.conf if we are
1208  			 * doing update
1209  			 */
1210  			if (datadm_args.da_op_type == DATADM_OP_UPDATE) {
1211  				retval = datadm_process_sp_entry(hca_list,
1212  				    sp_entry, NULL);
1213  			} else {
1214  				retval = datadm_process_sp_entry(hca_list,
1215  				    sp_entry, ia_name);
1216  			}
1217  			if (retval != 0) {
1218  				datadm_free_sp_entry(sp_entry);
1219  				if (retval == 1) {
1220  					retval = 0;
1221  				} else {
1222  					break;
1223  				}
1224  			}
1225  		} else {
1226  			(void) fprintf(stderr, gettext(
1227  			    "datadm: parse error: %s, line %d, "
1228  			    "# of tokens: %d, expected %d\n"), dat_conf,
1229  			    line_count, token_count, DATADM_NUM_DAT_TOKENS);
1230  			retval = -1;
1231  			break;
1232  		}
1233  	}
1234  	if (retval != 0) {
1235  		datadm_free_list(&datadm_conf_header,
1236  		    (void (*)(datadm_entry_t *))datadm_free_cmnt_entry);
1237  		datadm_free_list(hca_list,
1238  		    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1239  	}
1240  	(void) fclose(dat_file);
1241  	return (retval);
1242  }
1243  
1244  /*
1245   * used by OP_REMOVE to invalidate common sp entries between hl1 and hl2.
1246   * invalid sp entries will be ignored by datadm_generate_dat_conf.
1247   */
1248  static void
datadm_invalidate_common_sp_entries(datadm_list_t * hl1,datadm_list_t * hl2)1249  datadm_invalidate_common_sp_entries(datadm_list_t *hl1, datadm_list_t *hl2)
1250  {
1251  	datadm_entry_t	*he1, *he2;
1252  
1253  	he1 = hl1->dl_head;
1254  	while (he1 != NULL) {
1255  		he2 = hl2->dl_head;
1256  		while (he2 != NULL) {
1257  			datadm_entry_t	*se1, *se2;
1258  
1259  			if (!datadm_hca_entry_match(
1260  			    (datadm_hca_entry_t *)he1,
1261  			    (datadm_hca_entry_t *)he2)) {
1262  				he2 = he2->de_next;
1263  				continue;
1264  			}
1265  			se1 = ((datadm_hca_entry_t *)he1)->he_sp_list.dl_head;
1266  			while (se1 != NULL) {
1267  				se2 = ((datadm_hca_entry_t *)he2)->
1268  				    he_sp_list.dl_head;
1269  				while (se2 != NULL) {
1270  					if (!datadm_sp_entry_match(
1271  					    (datadm_sp_entry_t *)se1,
1272  					    (datadm_sp_entry_t *)se2)) {
1273  						se2 = se2->de_next;
1274  						continue;
1275  					}
1276  					((datadm_sp_entry_t *)se1)->
1277  					    spe_invalid = 1;
1278  					break;
1279  				}
1280  				se1 = se1->de_next;
1281  			}
1282  			break;
1283  		}
1284  		he1 = he1->de_next;
1285  	}
1286  }
1287  
1288  static int
datadm_hca_entry_find_by_name(datadm_hca_entry_t * h1,datadm_hca_find_by_name_t * hf)1289  datadm_hca_entry_find_by_name(datadm_hca_entry_t *h1,
1290      datadm_hca_find_by_name_t *hf)
1291  {
1292  	if (datadm_str_match(h1->he_name, hf->hf_name)) {
1293  		hf->hf_hca_entry = h1;
1294  		return (1);
1295  	}
1296  	return (0);
1297  }
1298  
1299  datadm_hca_entry_t *
datadm_hca_lookup_by_name(datadm_list_t * hca_list,char * hca_driver_name)1300  datadm_hca_lookup_by_name(datadm_list_t *hca_list, char *hca_driver_name)
1301  {
1302  	datadm_hca_find_by_name_t	hf;
1303  
1304  	hf.hf_name = hca_driver_name;
1305  	hf.hf_hca_entry = NULL;
1306  	(void) datadm_walk_list(hca_list,
1307  	    (int (*)(datadm_entry_t *, void *))datadm_hca_entry_find_by_name,
1308  	    &hf);
1309  	return (hf.hf_hca_entry);
1310  }
1311  
1312  static boolean_t
datadm_add_plink(char * linkname,datadm_fill_ia_list_t * ia_args)1313  datadm_add_plink(char *linkname, datadm_fill_ia_list_t *ia_args)
1314  {
1315  	datalink_class_t	class;
1316  	datalink_id_t		linkid;
1317  	dladm_ib_attr_t		ib_attr;
1318  	ibnex_ctl_query_hca_t	query_hca;
1319  	datadm_hca_entry_t	*hca;
1320  	struct lifreq		req;
1321  	datadm_ia_find_t	ia_find;
1322  	datadm_ia_entry_t	*ia_entry;
1323  
1324  	if ((dladm_name2info(ia_args->ia_dlh, linkname, &linkid, NULL, &class,
1325  	    NULL) != DLADM_STATUS_OK) ||
1326  	    (class != DATALINK_CLASS_PART) ||
1327  	    (dladm_part_info(ia_args->ia_dlh, linkid, &ib_attr,
1328  	    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK)) {
1329  		return (B_FALSE);
1330  	}
1331  
1332  	(void) strlcpy(req.lifr_name, linkname, sizeof (req.lifr_name));
1333  	/*
1334  	 * we don't really need to know the ip address.
1335  	 * we just want to check if the device is plumbed
1336  	 * or not.
1337  	 */
1338  	if (ioctl(ia_args->ia_sock_fd_v4, SIOCGLIFADDR, (caddr_t)&req) != 0) {
1339  		/*
1340  		 * we try v6 if the v4 address isn't found.
1341  		 */
1342  		if (ioctl(ia_args->ia_sock_fd_v6, SIOCGLIFADDR,
1343  		    (caddr_t)&req) != 0)
1344  			return (B_FALSE);
1345  	}
1346  
1347  	bzero(&query_hca, sizeof (query_hca));
1348  	query_hca.hca_guid = ib_attr.dia_hca_guid;
1349  	if (ioctl(ia_args->ia_ibnex_fd, IBNEX_CTL_QUERY_HCA, &query_hca) == -1)
1350  		return (B_FALSE);
1351  
1352  	if ((hca = datadm_hca_lookup_by_name(ia_args->ia_hca_list,
1353  	    query_hca.hca_info.hca_driver_name)) == NULL)
1354  		return (B_FALSE);
1355  
1356  	ia_find.if_ia_name = linkname;
1357  	ia_find.if_ia_entry = NULL;
1358  	(void) datadm_walk_list(&hca->he_ia_list,
1359  	    (int (*)(datadm_entry_t *, void *))
1360  	    datadm_ia_entry_find, &ia_find);
1361  
1362  	if (ia_find.if_ia_entry == NULL) {
1363  		/*
1364  		 * we insert an ia entry only if
1365  		 * it is unique.
1366  		 */
1367  		ia_entry = datadm_alloc_ia_entry();
1368  		if (ia_entry != NULL) {
1369  			(void) strlcpy(ia_entry->iae_name, linkname,
1370  			    MAXLINKNAMELEN);
1371  			datadm_enqueue_entry(&hca->he_ia_list,
1372  			    (datadm_entry_t *)ia_entry);
1373  		}
1374  	}
1375  
1376  	return (B_FALSE);
1377  }
1378  
1379  /*
1380   * build ia lists for each hca_list element
1381   */
1382  static int
datadm_build_ia_lists(datadm_list_t * hca_list)1383  datadm_build_ia_lists(datadm_list_t *hca_list)
1384  {
1385  	dladm_handle_t		dlh;
1386  	datadm_fill_ia_list_t	ia_args;
1387  	int			rv = -1;
1388  	int			fd = -1;
1389  	int			sv4 = -1;
1390  	int			sv6 = -1;
1391  
1392  	if (dladm_open(&dlh) != DLADM_STATUS_OK)
1393  		return (-1);
1394  
1395  	if ((fd = open(IBNEX_DEVCTL_DEV, O_RDONLY)) < 0)
1396  		goto out;
1397  
1398  	if ((sv4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1399  		perror("datadm: socket");
1400  		goto out;
1401  	}
1402  
1403  	if ((sv6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1404  		perror("datadm: socket");
1405  		goto out;
1406  	}
1407  
1408  	ia_args.ia_hca_list = hca_list;
1409  	ia_args.ia_dlh = dlh;
1410  	ia_args.ia_ibnex_fd = fd;
1411  	ia_args.ia_sock_fd_v4 = sv4;
1412  	ia_args.ia_sock_fd_v6 = sv6;
1413  
1414  	dlpi_walk((boolean_t (*) (const char *, void *))datadm_add_plink,
1415  	    &ia_args, 0);
1416  	rv = 0;
1417  
1418  out:
1419  	if (sv4 != -1)
1420  		(void) close(sv4);
1421  	if (sv6 != -1)
1422  		(void) close(sv6);
1423  	if (fd != -1)
1424  		(void) close(fd);
1425  
1426  	dladm_close(dlh);
1427  	return (rv);
1428  }
1429  
1430  static int
datadm_generate_conf_entry(FILE * outfile,datadm_ia_entry_t * ia_entry,datadm_sp_entry_t * sp_entry)1431  datadm_generate_conf_entry(FILE *outfile, datadm_ia_entry_t *ia_entry,
1432  	datadm_sp_entry_t *sp_entry)
1433  {
1434  	int	retval;
1435  
1436  	retval = fprintf(outfile,
1437  	    "%s  %s%d.%d  %s  %s  %s  %s%d.%d  \"%s\"  \"%s%s%s\"\n",
1438  	    ia_entry->iae_name,
1439  	    (sp_entry->spe_api_version.dv_name ?
1440  	    sp_entry->spe_api_version.dv_name : ""),
1441  	    sp_entry->spe_api_version.dv_major,
1442  	    sp_entry->spe_api_version.dv_minor,
1443  	    (sp_entry->spe_threadsafe ? "threadsafe" : "nonthreadsafe"),
1444  	    (sp_entry->spe_default ? "default" : "nondefault"),
1445  	    sp_entry->spe_libpath,
1446  	    (sp_entry->spe_sp_version.dv_name ?
1447  	    sp_entry->spe_sp_version.dv_name : ""),
1448  	    sp_entry->spe_sp_version.dv_major,
1449  	    sp_entry->spe_sp_version.dv_minor,
1450  	    sp_entry->spe_sp_data,
1451  	    DATADM_DRV_NAME, "=", sp_entry->spe_devname);
1452  
1453  	if (retval < 0) {
1454  		return (-1);
1455  	}
1456  	return (0);
1457  }
1458  
1459  /*
1460   * generate dat.conf header
1461   */
1462  static int
datadm_generate_conf_header(FILE * outfile)1463  datadm_generate_conf_header(FILE *outfile)
1464  {
1465  	datadm_entry_t		*cep;
1466  	datadm_cmnt_entry_t	*cmnt;
1467  	int			retval = 0;
1468  
1469  	cep = datadm_conf_header.dl_head;
1470  	if (cep == NULL) {
1471  		/*
1472  		 * if dat.conf doesn't have a header, we prepend a
1473  		 * default one.
1474  		 */
1475  		retval = fprintf(outfile, "%s", datadm_conf_header_default);
1476  		goto done;
1477  	}
1478  	while (cep != NULL) {
1479  		cmnt = (datadm_cmnt_entry_t *)cep;
1480  		if (cmnt->cmnt_line != NULL) {
1481  			int		len;
1482  
1483  			retval = fprintf(outfile, "%s", cmnt->cmnt_line);
1484  			if (retval < 0) {
1485  				break;
1486  			}
1487  
1488  			/*
1489  			 * append a newline if the comment line doesn't
1490  			 * have one.
1491  			 */
1492  			len = strlen(cmnt->cmnt_line);
1493  			if (cmnt->cmnt_line[len - 1] != '\n') {
1494  				retval = fprintf(outfile, "\n");
1495  				if (retval < 0) {
1496  					break;
1497  				}
1498  			}
1499  		}
1500  		cep = cep->de_next;
1501  	}
1502  done:;
1503  	if (retval < 0) {
1504  		return (-1);
1505  	}
1506  	return (0);
1507  }
1508  
1509  /*
1510   * outputs dat.conf to stdout or to basedir/etc/dat/dat.conf
1511   */
1512  static int
datadm_generate_dat_conf(datadm_list_t * hca_list)1513  datadm_generate_dat_conf(datadm_list_t *hca_list)
1514  {
1515  	FILE			*outfile = NULL;
1516  	char			*dat_conf = datadm_args.da_dat_conf;
1517  	datadm_entry_t		*hep;
1518  	int			retval = 0;
1519  
1520  	if (datadm_args.da_op_type == DATADM_OP_VIEW) {
1521  		outfile = stdout;
1522  	} else {
1523  		outfile = fopen(dat_conf, "w+");
1524  		if (outfile == NULL) {
1525  			(void) fprintf(stderr, gettext(
1526  			    "datadm: cannot open %s: %s\n"),
1527  			    dat_conf, strerror(errno));
1528  			return (-1);
1529  		}
1530  	}
1531  	if (outfile != stdout) {
1532  		/*
1533  		 * do not generate the header if we are
1534  		 * printing to the screen
1535  		 */
1536  		retval = datadm_generate_conf_header(outfile);
1537  		if (retval != 0) {
1538  			goto done;
1539  		}
1540  	}
1541  	hep = hca_list->dl_head;
1542  	while (hep != NULL) {
1543  		datadm_entry_t	*iep;
1544  
1545  		iep = ((datadm_hca_entry_t *)hep)->he_ia_list.dl_head;
1546  		while (iep != NULL) {
1547  			datadm_entry_t	*sep;
1548  
1549  			sep = ((datadm_hca_entry_t *)hep)->he_sp_list.dl_head;
1550  			while (sep != NULL) {
1551  				if (((datadm_sp_entry_t *)sep)->spe_invalid) {
1552  					sep = sep->de_next;
1553  					continue;
1554  				}
1555  				retval = datadm_generate_conf_entry(outfile,
1556  				    (datadm_ia_entry_t *)iep,
1557  				    (datadm_sp_entry_t *)sep);
1558  				if (retval != 0) {
1559  					goto done;
1560  				}
1561  				sep = sep->de_next;
1562  			}
1563  			iep = iep->de_next;
1564  		}
1565  		hep = hep->de_next;
1566  	}
1567  	retval = fflush(outfile);
1568  done:;
1569  	if (outfile != stdout) {
1570  		(void) fclose(outfile);
1571  	}
1572  	if (retval < 0) {
1573  		perror("datadm: fprintf");
1574  	}
1575  	return (retval);
1576  }
1577  
1578  static int
datadm_view(void)1579  datadm_view(void)
1580  {
1581  	int			retval = 0;
1582  	datadm_list_t		hca_list;
1583  
1584  	bzero(&hca_list, sizeof (hca_list));
1585  
1586  	retval = datadm_parse_dat_conf(&hca_list);
1587  	if (retval != 0) {
1588  		goto cleanup;
1589  	}
1590  	retval = datadm_generate_dat_conf(&hca_list);
1591  	if (retval != 0) {
1592  		goto cleanup;
1593  	}
1594  
1595  cleanup:;
1596  	datadm_free_list(&datadm_conf_header,
1597  	    (void (*)(datadm_entry_t *))datadm_free_cmnt_entry);
1598  	datadm_free_list(&hca_list,
1599  	    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1600  	return (retval);
1601  }
1602  
1603  static int
datadm_update(void)1604  datadm_update(void)
1605  {
1606  	int			retval = 0;
1607  	datadm_list_t		hca_list;
1608  
1609  	bzero(&hca_list, sizeof (hca_list));
1610  
1611  	retval = datadm_parse_dat_conf(&hca_list);
1612  	if (retval != 0) {
1613  		goto cleanup;
1614  	}
1615  	retval = datadm_build_ia_lists(&hca_list);
1616  	if (retval != 0) {
1617  		goto cleanup;
1618  	}
1619  	retval = datadm_generate_dat_conf(&hca_list);
1620  	if (retval != 0) {
1621  		goto cleanup;
1622  	}
1623  
1624  cleanup:;
1625  	datadm_free_list(&datadm_conf_header,
1626  	    (void (*)(datadm_entry_t *))datadm_free_cmnt_entry);
1627  	datadm_free_list(&hca_list,
1628  	    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1629  	return (retval);
1630  }
1631  
1632  static int
datadm_add(void)1633  datadm_add(void)
1634  {
1635  	int			retval = 0;
1636  	datadm_list_t		hca_list;
1637  
1638  	bzero(&hca_list, sizeof (hca_list));
1639  
1640  	retval = datadm_parse_dat_conf(&hca_list);
1641  	if (retval != 0) {
1642  		goto cleanup;
1643  	}
1644  	retval = datadm_parse_sp_conf(&hca_list);
1645  	if (retval != 0) {
1646  		goto cleanup;
1647  	}
1648  	retval = datadm_build_ia_lists(&hca_list);
1649  	if (retval != 0) {
1650  		goto cleanup;
1651  	}
1652  	retval = datadm_generate_dat_conf(&hca_list);
1653  	if (retval != 0) {
1654  		goto cleanup;
1655  	}
1656  
1657  cleanup:;
1658  	datadm_free_list(&datadm_conf_header,
1659  	    (void (*)(datadm_entry_t *))datadm_free_cmnt_entry);
1660  	datadm_free_list(&hca_list,
1661  	    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1662  	return (retval);
1663  }
1664  
1665  static int
datadm_remove(void)1666  datadm_remove(void)
1667  {
1668  	int			retval = 0;
1669  	datadm_list_t		hca_list;
1670  	datadm_list_t		hca_list2;
1671  
1672  	bzero(&hca_list, sizeof (hca_list));
1673  	bzero(&hca_list2, sizeof (hca_list2));
1674  
1675  	retval = datadm_parse_dat_conf(&hca_list);
1676  	if (retval != 0) {
1677  		goto cleanup;
1678  	}
1679  	retval = datadm_parse_sp_conf(&hca_list2);
1680  	if (retval != 0) {
1681  		goto cleanup;
1682  	}
1683  	datadm_invalidate_common_sp_entries(&hca_list, &hca_list2);
1684  
1685  	retval = datadm_generate_dat_conf(&hca_list);
1686  	if (retval != 0) {
1687  		goto cleanup;
1688  	}
1689  
1690  cleanup:;
1691  	datadm_free_list(&datadm_conf_header,
1692  	    (void (*)(datadm_entry_t *))datadm_free_cmnt_entry);
1693  	datadm_free_list(&hca_list,
1694  	    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1695  	datadm_free_list(&hca_list2,
1696  	    (void (*)(datadm_entry_t *))datadm_free_hca_entry);
1697  	return (retval);
1698  }
1699  
1700  static int
datadm_locate_dat_conf(char * basedir)1701  datadm_locate_dat_conf(char *basedir)
1702  {
1703  	char		*dat_conf;
1704  
1705  	if (basedir == NULL) {
1706  		datadm_args.da_dat_conf = DATADM_DAT_CONF;
1707  		return (0);
1708  	}
1709  	dat_conf = (char *)malloc(strlen(basedir) +
1710  	    strlen(DATADM_DAT_CONF) + 1);
1711  	if (dat_conf == NULL) {
1712  		return (-1);
1713  	}
1714  	dat_conf[0] = '\0';
1715  	(void) strcat(dat_conf, basedir);
1716  	(void) strcat(dat_conf, DATADM_DAT_CONF);
1717  	datadm_args.da_dat_conf = dat_conf;
1718  	return (0);
1719  }
1720  
1721  int
main(int argc,char ** argv)1722  main(int argc, char **argv)
1723  {
1724  	extern char	*optarg;
1725  	extern int	optind;
1726  	char		*basedir = NULL;
1727  	int		c, retval;
1728  	int		op_type = -1, errflg = 0;
1729  
1730  	bzero(&datadm_args, sizeof (datadm_args));
1731  	bzero(&datadm_conf_header, sizeof (datadm_conf_header));
1732  
1733  	(void) setlocale(LC_ALL, "");
1734  #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1735  #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1736  #endif
1737  	(void) textdomain(TEXT_DOMAIN);
1738  
1739  	while ((c = getopt(argc, argv, "vua:r:b:")) != EOF) {
1740  		switch (c) {
1741  		case 'v':
1742  			if (op_type != -1) errflg = 1;
1743  			op_type = DATADM_OP_VIEW;
1744  			break;
1745  		case 'u':
1746  			if (op_type != -1) errflg = 1;
1747  			op_type = DATADM_OP_UPDATE;
1748  			break;
1749  		case 'a':
1750  			if (op_type != -1) errflg = 1;
1751  			op_type = DATADM_OP_ADD;
1752  			datadm_args.da_sp_conf = optarg;
1753  			break;
1754  		case 'r':
1755  			if (op_type != -1) errflg = 1;
1756  			op_type = DATADM_OP_REMOVE;
1757  			datadm_args.da_sp_conf = optarg;
1758  			break;
1759  		case 'b':
1760  			basedir = optarg;
1761  			break;
1762  		default:
1763  			errflg = 1;
1764  			break;
1765  		}
1766  		if (errflg != 0) {
1767  			break;
1768  		}
1769  	}
1770  	if (errflg != 0 || op_type == -1 || optind < argc) {
1771  		datadm_usage();
1772  		return (1);
1773  	}
1774  	datadm_args.da_op_type = op_type;
1775  	if (datadm_locate_dat_conf(basedir)) {
1776  		return (1);
1777  	}
1778  
1779  	retval = (*datadm_ops[op_type])();
1780  	return (retval);
1781  }
1782