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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <sys/types.h>
35 #include <libdladm_impl.h>
36 #include <libdlflow_impl.h>
39 * XXX duplicate defines
41 #define DLADM_PROP_VAL_MAX 32
42 #define DLADM_MAX_PROPS 32
45 free_props(prop_db_info_t
*lip
)
47 prop_db_info_t
*lip_next
;
48 prop_val_t
*lvp
, *lvp_next
;
50 for (; lip
!= NULL
; lip
= lip_next
) {
51 lip_next
= lip
->li_nextprop
;
52 for (lvp
= lip
->li_val
; lvp
!= NULL
; lvp
= lvp_next
) {
53 lvp_next
= lvp
->lv_nextval
;
61 * Generate an entry in the property database.
62 * Each entry has this format:
63 * <name> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
66 generate_prop_line(const char *name
, char *buf
,
67 prop_db_info_t
*listp
, dladm_status_t
*statusp
)
69 char tmpbuf
[MAXLINELEN
];
70 char *ptr
, *lim
= tmpbuf
+ MAXLINELEN
;
71 prop_db_info_t
*lip
= listp
;
72 prop_val_t
*lvp
= NULL
;
75 * Delete line if there are no properties left.
78 (lip
->li_val
== NULL
&& lip
->li_nextprop
== NULL
)) {
83 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%s\t", name
);
84 for (; lip
!= NULL
; lip
= lip
->li_nextprop
) {
86 * Skip properties without values.
88 if (lip
->li_val
== NULL
)
91 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%s=", lip
->li_name
);
92 for (lvp
= lip
->li_val
; lvp
!= NULL
; lvp
= lvp
->lv_nextval
) {
93 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%s%c",
95 ((lvp
->lv_nextval
== NULL
) ? ';' : ','));
99 *statusp
= DLADM_STATUS_TOOSMALL
;
102 (void) snprintf(buf
, MAXLINELEN
, "%s\n", tmpbuf
);
106 * This function is used to update or create an entry in the persistent db.
107 * process_prop_db() will first scan the db for an entry matching the
108 * specified name. If a match is found, this function is invoked with the
109 * entry's contents (buf) and its linked-list representation (listp). lsp
110 * holds the name and values of the property to be added or updated; this
111 * information will be merged with listp. Subsequently, an updated entry
112 * will be written to buf, which will in turn be written to disk by
113 * process_prop_db(). If no entry matches the specified name, listp
114 * will be NULL; a new entry will be generated in this case and it will
115 * contain only the property information in lsp.
119 process_prop_set(dladm_handle_t handle
, prop_db_state_t
*lsp
, char *buf
,
120 prop_db_info_t
*listp
, dladm_status_t
*statusp
)
122 dladm_status_t status
;
123 prop_db_info_t
*lastp
= NULL
, *lip
= listp
, *nlip
= NULL
;
127 if (lsp
->ls_propname
== NULL
) {
133 * Find the prop we want to change.
135 for (; lip
!= NULL
; lip
= lip
->li_nextprop
) {
136 if (strcmp(lip
->li_name
, lsp
->ls_propname
) == 0)
144 * If the prop is not found, append it to the list.
146 if ((nlip
= malloc(sizeof (prop_db_info_t
))) == NULL
) {
147 status
= DLADM_STATUS_NOMEM
;
151 * nlip will need to be freed later if there is no list to
155 lastp
->li_nextprop
= nlip
;
156 nlip
->li_name
= lsp
->ls_propname
;
157 nlip
->li_nextprop
= NULL
;
159 lvpp
= &nlip
->li_val
;
161 prop_val_t
*lvp
, *lvp_next
;
164 * If the prop is found, delete the existing values from it.
166 for (lvp
= lip
->li_val
; lvp
!= NULL
; lvp
= lvp_next
) {
167 lvp_next
= lvp
->lv_nextval
;
175 * Fill our prop with the specified values.
177 for (i
= 0; i
< *lsp
->ls_valcntp
; i
++) {
178 if ((*lvpp
= malloc(sizeof (prop_val_t
))) == NULL
) {
179 status
= DLADM_STATUS_NOMEM
;
182 (*lvpp
)->lv_name
= lsp
->ls_propval
[i
];
183 (*lvpp
)->lv_nextval
= NULL
;
184 lvpp
= &(*lvpp
)->lv_nextval
;
188 generate_prop_line(lsp
->ls_name
, buf
, listp
, statusp
);
190 generate_prop_line(lsp
->ls_name
, buf
, nlip
, statusp
);
204 * This function is used for retrieving the values for a specific property.
205 * It gets called if an entry matching the specified name exists in the db.
206 * The entry is converted into a linked-list listp. This list is then scanned
207 * for the specified property name; if a matching property exists, its
208 * associated values are copied to the array lsp->ls_propval.
212 process_prop_get(dladm_handle_t handle
, prop_db_state_t
*lsp
, char *buf
,
213 prop_db_info_t
*listp
, dladm_status_t
*statusp
)
215 prop_db_info_t
*lip
= listp
;
220 * Find the prop we want to get.
222 for (; lip
!= NULL
; lip
= lip
->li_nextprop
) {
223 if (strcmp(lip
->li_name
, lsp
->ls_propname
) == 0)
227 *statusp
= DLADM_STATUS_NOTFOUND
;
231 for (lvp
= lip
->li_val
; lvp
!= NULL
; lvp
= lvp
->lv_nextval
) {
232 (void) strncpy(lsp
->ls_propval
[valcnt
], lvp
->lv_name
,
235 if (++valcnt
>= *lsp
->ls_valcntp
&& lvp
->lv_nextval
!= NULL
) {
236 *statusp
= DLADM_STATUS_TOOSMALL
;
241 * This function is meant to be called at most once for each call
242 * to process_prop_db(). For this reason, it's ok to overwrite
243 * the caller's valcnt array size with the actual number of values
246 *lsp
->ls_valcntp
= valcnt
;
251 * This is used for initializing properties.
252 * Unlike the other routines, this gets called for every entry in the
253 * database. lsp->ls_name is not user-specified but instead is set to
254 * the current name being processed.
258 process_prop_init(dladm_handle_t handle
, prop_db_state_t
*lsp
, char *buf
,
259 prop_db_info_t
*listp
, dladm_status_t
*statusp
)
261 dladm_status_t status
= DLADM_STATUS_OK
;
262 prop_db_info_t
*lip
= listp
;
267 for (; lip
!= NULL
; lip
= lip
->li_nextprop
) {
269 * Construct the propval array and fill it with
272 for (lvp
= lip
->li_val
, valcnt
= 0;
273 lvp
!= NULL
; lvp
= lvp
->lv_nextval
, valcnt
++) {
276 propval
= malloc(sizeof (char *) * valcnt
);
277 if (propval
== NULL
) {
278 *statusp
= DLADM_STATUS_NOMEM
;
282 for (i
= 0; i
< valcnt
; i
++, lvp
= lvp
->lv_nextval
)
283 propval
[i
] = (char *)lvp
->lv_name
;
285 status
= (*lsp
->ls_initop
)(handle
, lsp
->ls_name
, lip
->li_name
,
286 propval
, valcnt
, DLADM_OPT_ACTIVE
, NULL
);
289 * We continue with initializing other properties even
290 * after encountering an error. This error will be
291 * propagated to the caller via 'statusp'.
293 if (status
!= DLADM_STATUS_OK
)
302 parse_props(char *buf
, prop_db_info_t
**lipp
)
306 prop_db_info_t
*lip
= NULL
;
307 prop_db_info_t
**tailp
= lipp
;
308 prop_val_t
*lvp
= NULL
;
309 prop_val_t
**vtailp
= NULL
;
313 for (i
= 0; i
< len
; i
++) {
315 boolean_t match
= (c
== '=' || c
== ',' || c
== ';');
318 * Move to the next character if there is no match and
319 * if we have not reached the last character.
321 if (!match
&& i
!= len
- 1)
326 * Nul-terminate the string pointed to by 'curr'.
335 * We get here after we have processed the "<prop>="
336 * pattern. The pattern we are now interested in is
337 * "<val0>,<val1>,...,<valn>;". For each value we
338 * find, a prop_val_t will be allocated and
339 * added to the current 'lip'.
344 lvp
= malloc(sizeof (*lvp
));
349 lvp
->lv_nextval
= NULL
;
351 vtailp
= &lvp
->lv_nextval
;
354 tailp
= &lip
->li_nextprop
;
360 * lip == NULL indicates that 'curr' must be refering
361 * to a property name. We allocate a new prop_db_info_t
362 * append it to the list given by the caller.
367 lip
= malloc(sizeof (*lip
));
373 lip
->li_nextprop
= NULL
;
375 vtailp
= &lip
->li_val
;
380 * The list must be non-empty and the last character must be ';'.
382 if (*lipp
== NULL
|| lip
!= NULL
)
394 process_prop_line(dladm_handle_t handle
, prop_db_state_t
*lsp
, char *buf
,
395 dladm_status_t
*statusp
)
397 prop_db_info_t
*lip
= NULL
;
400 boolean_t cont
, noname
= B_FALSE
;
403 * Skip leading spaces, blank lines, and comments.
406 for (i
= 0; i
< len
; i
++) {
407 if (!isspace(buf
[i
]))
410 if (i
== len
|| buf
[i
] == '#')
414 if (lsp
->ls_name
!= NULL
) {
416 * Skip names we're not interested in.
417 * Note that strncmp() and isspace() are used here
418 * instead of strtok() and strcmp() because we don't
419 * want to modify buf in case it does not contain the
422 llen
= strlen(lsp
->ls_name
);
423 if (strncmp(str
, lsp
->ls_name
, llen
) != 0 ||
428 * If a name is not specified, find the name
429 * and assign it to lsp->ls_name.
431 if (strtok_r(str
, " \n\t", &lasts
) == NULL
)
439 if (str
>= buf
+ len
)
443 * Now find the list of properties.
445 if ((str
= strtok_r(str
, " \n\t", &lasts
)) == NULL
)
448 if (parse_props(str
, &lip
) < 0)
451 cont
= (*lsp
->ls_op
)(handle
, lsp
, buf
, lip
, statusp
);
463 * Delete corrupted line.
470 process_prop_db(dladm_handle_t handle
, void *arg
, FILE *fp
, FILE *nfp
)
472 prop_db_state_t
*lsp
= arg
;
473 dladm_status_t status
= DLADM_STATUS_OK
;
474 char buf
[MAXLINELEN
];
475 boolean_t cont
= B_TRUE
;
478 * This loop processes each line of the configuration file.
479 * buf can potentially be modified by process_prop_line().
480 * If this is a write operation and buf is not truncated, buf will
481 * be written to disk. process_prop_line() will no longer be
482 * called after it returns B_FALSE; at which point the remainder
483 * of the file will continue to be read and, if necessary, written
486 while (fgets(buf
, MAXLINELEN
, fp
) != NULL
) {
488 cont
= process_prop_line(handle
, lsp
, buf
, &status
);
490 if (nfp
!= NULL
&& buf
[0] != '\0' && fputs(buf
, nfp
) == EOF
) {
491 status
= dladm_errno2status(errno
);
496 if (status
!= DLADM_STATUS_OK
|| !cont
)
499 if (lsp
->ls_op
== process_prop_set
) {
501 * If the specified name is not found above, we add the
502 * name and its properties to the configuration file.
504 (void) (*lsp
->ls_op
)(handle
, lsp
, buf
, NULL
, &status
);
505 if (status
== DLADM_STATUS_OK
&& fputs(buf
, nfp
) == EOF
)
506 status
= dladm_errno2status(errno
);
509 if (lsp
->ls_op
== process_prop_get
)
510 status
= DLADM_STATUS_NOTFOUND
;
516 i_dladm_get_prop_temp(dladm_handle_t handle
, const char *name
, prop_type_t type
,
517 const char *prop_name
, char **prop_val
, uint_t
*val_cntp
,
518 prop_table_t
*prop_tbl
)
521 dladm_status_t status
;
525 if (name
== NULL
|| prop_name
== NULL
|| prop_val
== NULL
||
526 val_cntp
== NULL
|| *val_cntp
== 0)
527 return (DLADM_STATUS_BADARG
);
529 for (i
= 0; i
< prop_tbl
->pt_size
; i
++)
530 if (strcasecmp(prop_name
, prop_tbl
->pt_table
[i
].pd_name
) == 0)
533 if (i
== prop_tbl
->pt_size
)
534 return (DLADM_STATUS_NOTFOUND
);
536 pdp
= &prop_tbl
->pt_table
[i
];
537 status
= DLADM_STATUS_OK
;
540 case DLADM_PROP_VAL_CURRENT
:
541 status
= pdp
->pd_get(handle
, name
, prop_val
, val_cntp
);
543 case DLADM_PROP_VAL_DEFAULT
:
544 if (pdp
->pd_defval
.vd_name
== NULL
) {
545 status
= DLADM_STATUS_NOTSUP
;
548 (void) strcpy(*prop_val
, pdp
->pd_defval
.vd_name
);
552 case DLADM_PROP_VAL_MODIFIABLE
:
553 if (pdp
->pd_getmod
!= NULL
) {
554 status
= pdp
->pd_getmod(handle
, name
, prop_val
,
558 cnt
= pdp
->pd_nmodval
;
560 status
= DLADM_STATUS_NOTSUP
;
561 } else if (cnt
> *val_cntp
) {
562 status
= DLADM_STATUS_TOOSMALL
;
564 for (i
= 0; i
< cnt
; i
++) {
565 (void) strcpy(prop_val
[i
],
566 pdp
->pd_modval
[i
].vd_name
);
572 status
= DLADM_STATUS_BADARG
;
579 static dladm_status_t
580 i_dladm_set_one_prop_temp(dladm_handle_t handle
, const char *name
,
581 fprop_desc_t
*pdp
, char **prop_val
, uint_t val_cnt
, uint_t flags
)
583 dladm_status_t status
;
584 val_desc_t
*vdp
= NULL
;
587 if (pdp
->pd_temponly
&& (flags
& DLADM_OPT_PERSIST
) != 0)
588 return (DLADM_STATUS_TEMPONLY
);
590 if (pdp
->pd_set
== NULL
)
591 return (DLADM_STATUS_PROPRDONLY
);
593 if (prop_val
!= NULL
) {
594 if (pdp
->pd_check
!= NULL
)
595 status
= pdp
->pd_check(pdp
, prop_val
, val_cnt
, &vdp
);
597 status
= DLADM_STATUS_BADARG
;
599 if (status
!= DLADM_STATUS_OK
)
604 if (pdp
->pd_defval
.vd_name
== NULL
)
605 return (DLADM_STATUS_NOTSUP
);
607 if ((vdp
= malloc(sizeof (val_desc_t
))) == NULL
)
608 return (DLADM_STATUS_NOMEM
);
610 (void) memcpy(vdp
, &pdp
->pd_defval
, sizeof (val_desc_t
));
614 status
= pdp
->pd_set(handle
, name
, vdp
, cnt
);
621 i_dladm_set_prop_temp(dladm_handle_t handle
, const char *name
,
622 const char *prop_name
, char **prop_val
, uint_t val_cnt
, uint_t flags
,
623 char **errprop
, prop_table_t
*prop_tbl
)
626 dladm_status_t status
= DLADM_STATUS_OK
;
627 boolean_t found
= B_FALSE
;
629 for (i
= 0; i
< prop_tbl
->pt_size
; i
++) {
630 fprop_desc_t
*pdp
= &prop_tbl
->pt_table
[i
];
633 if (prop_name
!= NULL
&&
634 (strcasecmp(prop_name
, pdp
->pd_name
) != 0))
638 s
= i_dladm_set_one_prop_temp(handle
, name
, pdp
, prop_val
,
641 if (prop_name
!= NULL
) {
645 if (s
!= DLADM_STATUS_OK
&&
646 s
!= DLADM_STATUS_NOTSUP
) {
648 *errprop
= pdp
->pd_name
;
656 status
= DLADM_STATUS_NOTFOUND
;
662 i_dladm_is_prop_temponly(const char *prop_name
, char **errprop
,
663 prop_table_t
*prop_tbl
)
667 if (prop_name
== NULL
)
670 for (i
= 0; i
< prop_tbl
->pt_size
; i
++) {
671 fprop_desc_t
*pdp
= &prop_tbl
->pt_table
[i
];
673 if (strcasecmp(prop_name
, pdp
->pd_name
) != 0)
677 *errprop
= pdp
->pd_name
;
679 if (pdp
->pd_temponly
)
686 dladm_free_props(dladm_arg_list_t
*list
)
688 dladm_free_args(list
);
692 dladm_parse_props(char *str
, dladm_arg_list_t
**listp
, boolean_t novalues
)
694 if (dladm_parse_args(str
, listp
, novalues
) != DLADM_STATUS_OK
)
697 return (DLADM_STATUS_OK
);
700 dladm_free_args(*listp
);
701 return (DLADM_STATUS_PROP_PARSE_ERR
);