dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libvscan / common / libvscan.c
blobdfa116ff5b43cfbf74e518c1bd745dd84ca3b4b1
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <math.h>
32 #include <limits.h>
33 #include <libscf.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <door.h>
37 #include <pwd.h>
38 #include <auth_attr.h>
39 #include <secdb.h>
40 #include <sys/socket.h>
41 #include <arpa/inet.h>
42 #include <libintl.h>
43 #include <libvscan.h>
45 #define VS_DOOR_CALL_RETRIES 3
47 #define VS_INSTANCE_FMRI "svc:/system/filesystem/vscan:icap"
49 /* SMF property group and property names */
50 #define VS_PGNAME_GENERAL "vs_general"
51 #define VS_PGNAME_ENGINE_PREFIX "vs_engine_"
52 #define VS_PGNAME_ENGINE_LEN VS_SE_NAME_LEN + 16
54 #define VS_PNAME_MAXSIZE "maxsize"
55 #define VS_PNAME_MAXSIZE_ACTION "maxsize_action"
56 #define VS_PNAME_TYPES "types"
57 #define VS_PNAME_VLOG "viruslog"
59 #define VS_PNAME_SE_ENABLE "enable"
60 #define VS_PNAME_SE_HOST "host"
61 #define VS_PNAME_SE_PORT "port"
62 #define VS_PNAME_SE_MAXCONN "max_connect"
63 #define VS_PNAME_VAUTH "value_authorization"
66 /* types string processing */
67 #define VS_TYPES_SEP ','
68 #define VS_TYPES_ESCAPE '\\'
69 #define VS_TYPES_RULES "+-"
73 * The SCF context enapsulating the SCF objects used in the
74 * repository load and store routines vs_scf_values_get()
75 * and vs_scf_values_set().
77 * The context is always opened before a get or set, then
78 * closed when finished (or on error); the open does an
79 * initial setup, while inside the get and set functions,
80 * additional objects within the context may be selectively
81 * initialized for use, depending on the actions needed and
82 * the properties being operated on.
84 typedef struct vs_scfctx {
85 scf_handle_t *vscf_handle;
86 scf_instance_t *vscf_inst;
87 scf_propertygroup_t *vscf_pgroup;
88 scf_transaction_t *vscf_tx;
89 scf_iter_t *vscf_iter;
90 scf_property_t *vscf_prop[VS_NUM_PROPIDS];
91 scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS];
92 scf_value_t *vscf_val[VS_NUM_PROPIDS];
93 } vs_scfctx_t;
96 * The vscan property definition. Maps the property id with the name
97 * and type used to store the property in the repository.
98 * A table of these definitions is defined with a single entry per
99 * property.
101 typedef struct {
102 const char *vpd_name;
103 uint64_t vpd_id;
104 scf_type_t vpd_type;
105 } vs_propdef_t;
107 typedef enum {
108 VS_PTYPE_GEN,
109 VS_PTYPE_SE
110 } vs_prop_type_t;
112 typedef struct vs_prop_hd {
113 vs_prop_type_t vp_type;
114 uint64_t vp_ids;
115 uint64_t vp_all;
116 union {
117 vs_props_t vp_gen;
118 vs_props_se_t vp_se;
119 } vp_props;
120 } vs_prop_hd_t;
122 #define vp_gen vp_props.vp_gen
123 #define vp_se vp_props.vp_se
126 * Default values - these are used to return valid data
127 * to the caller in cases where invalid or unexpected values
128 * are found in the repository.
130 * Note: These values must be kept in sync with those defined
131 * in the service manifest.
133 static const boolean_t vs_dflt_allow = B_TRUE;
134 static const boolean_t vs_dflt_enable = B_TRUE;
135 static const char *vs_dflt_maxsize = "1GB";
136 static const char *vs_dflt_host = "";
137 static const uint16_t vs_dflt_port = 1344;
138 static const uint16_t vs_dflt_maxconn = 8;
139 static const char *vs_dflt_types = "+*";
140 static const char *vs_dflt_vlog = "";
142 /* Property definition table */
143 static const vs_propdef_t vs_propdefs[] = {
144 /* general properties */
145 { VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING },
146 { VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN },
147 { VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING },
148 { VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING },
149 /* scan engine properties */
150 { VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN },
151 { VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST },
152 { VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER },
153 { VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER },
154 { VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING }
157 static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
159 /* Local functions */
160 static const vs_propdef_t *vs_get_propdef(uint64_t);
161 static void vs_default_value(vs_prop_hd_t *, const uint64_t);
163 static int vs_scf_values_get(const char *, vs_prop_hd_t *);
164 static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
166 static int vs_scf_values_set(const char *, vs_prop_hd_t *);
167 static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
168 static int vs_scf_pg_create(const char *, vs_prop_hd_t *);
169 static int vs_scf_pg_delete(const char *);
171 static int vs_scf_ctx_open(vs_scfctx_t *);
172 static void vs_scf_ctx_close(vs_scfctx_t *);
174 static int vs_validate(const vs_prop_hd_t *, uint64_t);
175 static int vs_is_valid_types(const char *);
176 static int vs_is_valid_host(const char *);
177 static int vs_checkauth(char *);
178 static int vs_door_call(int, door_arg_t *);
180 static int vs_props_get_engines(char *[], int *);
181 static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
182 static int vs_scf_pg_count(void);
183 static int vs_strtoshift(const char *);
187 * vs_props_get_all
189 * Retrieves the general service properties and all properties
190 * for all scan engines from the repository.
192 * If invalid property values are found, the values are corrected to
193 * the default value.
195 * Return codes:
196 * VS_ERR_VS_ERR_NONE
197 * VS_ERR_SCF
198 * VS_ERR_SYS
201 vs_props_get_all(vs_props_all_t *va)
203 int i, rc, n;
204 char *engids[VS_SE_MAX];
206 (void) memset(va, 0, sizeof (vs_props_all_t));
207 if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
208 != VS_ERR_NONE)
209 return (rc);
211 n = VS_SE_MAX;
212 if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
213 return (rc);
215 for (i = 0; i < n; i++) {
216 if ((rc = vs_props_se_get(engids[i],
217 &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
218 break;
221 /* free engids allocated in vs_props_get_engines */
222 for (i = 0; i < VS_SE_MAX; i++) {
223 free(engids[i]);
226 return (rc);
231 * vs_props_get
233 * Retrieves values for the specified general service properties from
234 * the repository.
236 * If invalid property values are found, the values are corrected to
237 * the default value.
239 * Return codes:
240 * VS_ERR_VS_ERR_NONE
241 * VS_ERR_INVALID_PROPERTY
242 * VS_ERR_SCF
243 * VS_ERR_SYS
246 vs_props_get(vs_props_t *vp, uint64_t propids)
248 int rc;
249 vs_prop_hd_t prop_hd;
251 if ((propids & VS_PROPID_GEN_ALL) != propids)
252 return (VS_ERR_INVALID_PROPERTY);
254 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
255 prop_hd.vp_type = VS_PTYPE_GEN;
256 prop_hd.vp_ids = propids;
257 prop_hd.vp_all = VS_PROPID_GEN_ALL;
259 rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
261 *vp = prop_hd.vp_gen;
262 return (rc);
267 * vs_props_set
269 * Changes values for the specified general service properties
270 * in the repository.
272 * Return codes:
273 * VS_ERR_VS_ERR_NONE
274 * VS_ERR_INVALID_PROPERTY
275 * VS_ERR_INVALID_VALUE
276 * VS_ERR_SCF
277 * VS_ERR_SYS
280 vs_props_set(const vs_props_t *vp, uint64_t propids)
282 vs_prop_hd_t prop_hd;
284 if ((propids & VS_PROPID_GEN_ALL) != propids)
285 return (VS_ERR_INVALID_PROPERTY);
287 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
288 prop_hd.vp_type = VS_PTYPE_GEN;
289 prop_hd.vp_ids = propids;
290 prop_hd.vp_all = VS_PROPID_GEN_ALL;
291 prop_hd.vp_gen = *vp;
292 return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
297 * vs_props_se_get
299 * Retrieves values for the specified scan engine properties from the
300 * repository.
302 * If the enable property is set (true), the host property is
303 * checked for validity. If it is not valid, the requested values
304 * are returned with the enable propery set to off (false)
306 * Return codes:
307 * VS_ERR_VS_ERR_NONE
308 * VS_ERR_INVALID_PROPERTY
309 * VS_ERR_SCF
310 * VS_ERR_SYS
313 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
315 int rc;
316 char pgname[VS_PGNAME_ENGINE_LEN];
317 vs_prop_hd_t prop_hd;
319 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
320 if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
321 return (VS_ERR_INVALID_SE);
323 if ((propids & VS_PROPID_SE_ALL) != propids)
324 return (VS_ERR_INVALID_PROPERTY);
326 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
327 prop_hd.vp_type = VS_PTYPE_SE;
328 prop_hd.vp_ids = propids;
329 prop_hd.vp_all = VS_PROPID_SE_ALL;
330 (void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
332 /* If getting enable, get the host property too */
333 if ((propids & VS_PROPID_SE_ENABLE))
334 prop_hd.vp_ids |= VS_PROPID_SE_HOST;
336 /* Load values from the repository */
337 vs_engid_to_pgname(engid, pgname);
338 rc = vs_scf_values_get(pgname, &prop_hd);
339 if (rc != VS_ERR_NONE)
340 return (rc);
343 * If the host is invalid and the enable property is on,
344 * return enable property as off
346 if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
347 (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
348 prop_hd.vp_se.vep_enable = B_FALSE;
351 *sep = prop_hd.vp_se;
352 return (rc);
358 * vs_props_se_set
360 * Changes the values for the specified scan engine properties in the
361 * repository.
363 * If the enable property is being changed to true in this operation,
364 * a host property must also be specified, or already exist in the
365 * repository.
367 * Return codes:
368 * VS_ERR_NONE
369 * VS_ERR_INVALID_PROPERTY
370 * VS_ERR_INVALID_VALUE
371 * VS_ERR_SCF
372 * VS_ERR_SYS
375 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
377 int rc;
378 char pgname[VS_PGNAME_ENGINE_LEN];
379 vs_prop_hd_t prop_hd;
381 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
382 if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
383 return (VS_ERR_INVALID_SE);
385 if ((propids & VS_PROPID_SE_ALL) != propids)
386 return (VS_ERR_INVALID_PROPERTY);
388 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
389 prop_hd.vp_type = VS_PTYPE_SE;
390 prop_hd.vp_all = VS_PROPID_SE_ALL;
392 vs_engid_to_pgname(engid, pgname);
395 * if enabling a scan engine, ensure that a valid host
396 * is also being set, or already exists in the repository
398 if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
399 !(propids & VS_PROPID_SE_HOST)) {
401 prop_hd.vp_ids = VS_PROPID_SE_HOST;
402 if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
403 return (rc);
405 if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
406 return (VS_ERR_INVALID_HOST);
409 prop_hd.vp_ids = propids;
410 prop_hd.vp_se = *sep;
412 return (vs_scf_values_set(pgname, &prop_hd));
417 * vs_props_se_create
420 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
422 int n;
423 char pgname[VS_PGNAME_ENGINE_LEN];
424 vs_prop_hd_t prop_hd;
426 if ((propids & VS_PROPID_SE_ALL) != propids)
427 return (VS_ERR_INVALID_PROPERTY);
429 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
430 if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
431 return (VS_ERR_INVALID_SE);
433 if ((n = vs_scf_pg_count()) == -1)
434 return (VS_ERR_SCF);
436 if (n == VS_SE_MAX)
437 return (VS_ERR_MAX_SE);
439 vs_engid_to_pgname(engid, pgname);
441 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
442 prop_hd.vp_type = VS_PTYPE_SE;
443 prop_hd.vp_all = VS_PROPID_SE_ALL;
444 prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
445 prop_hd.vp_se = *sep;
447 /* if hostname not specified, default it to engid */
448 if ((propids & VS_PROPID_SE_HOST) == 0) {
449 (void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
450 prop_hd.vp_ids |= VS_PROPID_SE_HOST;
453 return (vs_scf_pg_create(pgname, &prop_hd));
458 * vs_props_se_delete
461 vs_props_se_delete(const char *engid)
463 char pgname[VS_PGNAME_ENGINE_LEN];
465 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
466 if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
467 return (VS_ERR_INVALID_SE);
469 vs_engid_to_pgname(engid, pgname);
471 return (vs_scf_pg_delete(pgname));
476 * vs_strerror
478 const char *
479 vs_strerror(int error)
481 switch (error) {
482 case VS_ERR_NONE:
483 return (gettext("no error"));
484 case VS_ERR_INVALID_PROPERTY:
485 return (gettext("invalid property id"));
486 case VS_ERR_INVALID_VALUE:
487 return (gettext("invalid property value"));
488 case VS_ERR_INVALID_HOST:
489 return (gettext("invalid host"));
490 case VS_ERR_INVALID_SE:
491 return (gettext("invalid scan engine"));
492 case VS_ERR_MAX_SE:
493 return (gettext("max scan engines exceeded"));
494 case VS_ERR_AUTH:
495 return (gettext("insufficient privileges for action"));
496 case VS_ERR_DAEMON_COMM:
497 return (gettext("unable to contact vscand"));
498 case VS_ERR_SCF:
499 return (scf_strerror(scf_error()));
500 case VS_ERR_SYS:
501 return (strerror(errno));
502 default:
503 return (gettext("unknown error"));
509 * vs_get_propdef
511 * Finds and returns a property definition by property id.
513 static const vs_propdef_t *
514 vs_get_propdef(uint64_t propid)
516 int i;
518 for (i = 0; i < vs_npropdefs; i++) {
519 if (propid == vs_propdefs[i].vpd_id)
520 return (&vs_propdefs[i]);
523 return (NULL);
528 * vs_default_value
530 * Sets a property value that contains invalid data to its default value.
532 * Note that this function does not alter any values in the repository
533 * This is only to enable the caller to get valid data.
535 static void
536 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
538 vs_props_t *vp = &prop_hd->vp_gen;
539 vs_props_se_t *vep = &prop_hd->vp_se;
541 switch (propid) {
542 case VS_PROPID_MAXSIZE:
543 (void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
544 sizeof (vp->vp_maxsize));
545 break;
546 case VS_PROPID_MAXSIZE_ACTION:
547 vp->vp_maxsize_action = vs_dflt_allow;
548 break;
549 case VS_PROPID_TYPES:
550 (void) strlcpy(vp->vp_types, vs_dflt_types,
551 sizeof (vp->vp_types));
552 break;
553 case VS_PROPID_VLOG:
554 (void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
555 sizeof (vp->vp_vlog));
556 break;
557 case VS_PROPID_SE_ENABLE:
558 vep->vep_enable = vs_dflt_enable;
559 break;
560 case VS_PROPID_SE_HOST:
561 (void) strlcpy(vep->vep_host, vs_dflt_host,
562 sizeof (vep->vep_host));
563 break;
564 case VS_PROPID_SE_PORT:
565 vep->vep_port = vs_dflt_port;
566 break;
567 case VS_PROPID_SE_MAXCONN:
568 vep->vep_maxconn = vs_dflt_maxconn;
569 break;
570 default:
571 break;
577 * vs_scf_values_get
579 * Gets property values for one or more properties from the repository.
580 * This is the single entry point for loading SMF values.
582 * While a transaction is not used for loading property values,
583 * the operation is parameterized by a property group. All properties
584 * retrieved in this function, then, must belong to the same property
585 * group.
588 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
590 vs_scfctx_t vsc;
591 int rc, np;
592 const vs_propdef_t *vpd;
593 uint64_t propid;
595 if ((vs_scf_ctx_open(&vsc)) != 0) {
596 vs_scf_ctx_close(&vsc);
597 return (VS_ERR_SCF);
600 if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
601 vs_scf_ctx_close(&vsc);
602 if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
603 rc = scf_error();
604 if ((rc == SCF_ERROR_NOT_FOUND) ||
605 (rc == SCF_ERROR_INVALID_ARGUMENT))
606 return (VS_ERR_INVALID_SE);
608 return (VS_ERR_SCF);
611 rc = VS_ERR_NONE;
612 np = 0;
613 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
614 if ((prop_hd->vp_ids & propid) == 0)
615 continue;
617 if ((vpd = vs_get_propdef(propid)) == NULL) {
618 rc = VS_ERR_INVALID_PROPERTY;
619 break;
622 vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
623 vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
625 if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
626 rc = VS_ERR_SCF;
627 break;
630 if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
631 vsc.vscf_prop[np]) == -1) {
632 if (scf_error() == SCF_ERROR_NOT_FOUND) {
633 vs_default_value(prop_hd, vpd->vpd_id);
634 continue;
636 rc = VS_ERR_SCF;
637 break;
640 if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
641 break;
643 ++np;
647 vs_scf_ctx_close(&vsc);
649 return (rc);
654 * vs_scf_get
656 * Loads a single values from the repository into the appropriate vscan
657 * property structure member.
659 static int
660 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
661 vs_scfctx_t *vsc, int idx)
663 int rc;
664 int64_t port;
665 uint8_t valbool;
666 vs_props_t *vp = &prop_hd->vp_gen;
667 vs_props_se_t *vep = &prop_hd->vp_se;
669 if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
670 vsc->vscf_val[idx])) == -1) {
671 if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
672 rc == SCF_ERROR_NOT_FOUND) {
673 vs_default_value(prop_hd, vpd->vpd_id);
674 return (VS_ERR_NONE);
676 return (VS_ERR_SCF);
679 rc = VS_ERR_NONE;
680 switch (vpd->vpd_id) {
681 case VS_PROPID_MAXSIZE:
682 if ((scf_value_get_astring(vsc->vscf_val[idx],
683 vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
684 return (VS_ERR_SCF);
686 break;
687 case VS_PROPID_MAXSIZE_ACTION:
688 if ((scf_value_get_boolean(vsc->vscf_val[idx],
689 &valbool)) == -1) {
690 return (VS_ERR_SCF);
692 vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
693 break;
694 case VS_PROPID_TYPES:
695 if ((scf_value_get_astring(vsc->vscf_val[idx],
696 vp->vp_types, sizeof (vp->vp_types))) == -1) {
697 return (VS_ERR_SCF);
699 break;
700 case VS_PROPID_VLOG:
701 if ((scf_value_get_astring(vsc->vscf_val[idx],
702 vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
703 return (VS_ERR_SCF);
705 break;
706 case VS_PROPID_SE_ENABLE:
707 if ((scf_value_get_boolean(vsc->vscf_val[idx],
708 &valbool)) == -1) {
709 return (VS_ERR_SCF);
711 vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
712 break;
713 case VS_PROPID_SE_HOST:
714 (void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
715 vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
716 break;
717 case VS_PROPID_SE_PORT:
718 if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
719 return (VS_ERR_SCF);
720 if (port <= 0 || port >= UINT16_MAX)
721 rc = VS_ERR_INVALID_VALUE;
722 else
723 vep->vep_port = (uint16_t)port;
724 break;
725 case VS_PROPID_SE_MAXCONN:
726 if ((scf_value_get_integer(vsc->vscf_val[idx],
727 (int64_t *)&vep->vep_maxconn)) == -1) {
728 return (VS_ERR_SCF);
730 break;
731 default:
732 break;
735 if ((rc != VS_ERR_NONE) ||
736 (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
737 vs_default_value(prop_hd, vpd->vpd_id);
740 return (VS_ERR_NONE);
745 * vs_scf_pg_create
747 static int
748 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
750 int rc;
751 uint64_t propid;
752 vs_scfctx_t vsc;
754 /* ensure that caller has authorization to refresh service */
755 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
756 return (rc);
758 if (vs_scf_ctx_open(&vsc) != 0) {
759 vs_scf_ctx_close(&vsc);
760 return (VS_ERR_SCF);
763 if (scf_instance_add_pg(vsc.vscf_inst, pgname,
764 SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
765 vs_scf_ctx_close(&vsc);
766 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
767 return (VS_ERR_INVALID_SE);
768 return (VS_ERR_SCF);
770 vs_scf_ctx_close(&vsc);
772 /* set default values for those not specified */
773 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
774 if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
775 vs_default_value(prop_hd, propid);
778 prop_hd->vp_ids = prop_hd->vp_all;
779 prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
781 rc = vs_scf_values_set(pgname, prop_hd);
782 if (rc != VS_ERR_NONE)
783 (void) vs_scf_pg_delete(pgname);
785 return (rc);
790 * vs_scf_pg_delete
792 static int
793 vs_scf_pg_delete(const char *pgname)
795 int rc;
796 vs_scfctx_t vsc;
798 /* ensure that caller has authorization to refresh service */
799 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
800 return (rc);
802 if (vs_scf_ctx_open(&vsc) != 0) {
803 vs_scf_ctx_close(&vsc);
804 return (VS_ERR_SCF);
807 if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
808 vs_scf_ctx_close(&vsc);
809 rc = scf_error();
810 if ((rc == SCF_ERROR_NOT_FOUND) ||
811 (rc == SCF_ERROR_INVALID_ARGUMENT))
812 return (VS_ERR_INVALID_SE);
813 else
814 return (VS_ERR_SCF);
817 if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
818 vs_scf_ctx_close(&vsc);
819 rc = scf_error();
820 if ((rc == SCF_ERROR_NOT_FOUND) ||
821 (rc == SCF_ERROR_INVALID_ARGUMENT))
822 return (VS_ERR_INVALID_SE);
824 return (VS_ERR_SCF);
827 vs_scf_ctx_close(&vsc);
829 /* Notify the daemon that things have changed */
830 if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
831 return (VS_ERR_SCF);
834 return (VS_ERR_NONE);
839 * vs_scf_values_set
841 * Sets property values in the repository. This is the single
842 * entry point for storing SMF values.
844 * Like loading values, this is an operation based on a single property
845 * group, so all property values changed in this function must belong
846 * to the same property group. Additionally, this operation is done in
847 * the context of a repository transaction; on any fatal error, the
848 * SCF context will be closed, destroying all SCF objects and aborting
849 * the transaction.
851 static int
852 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
854 int rc, np;
855 const vs_propdef_t *vpd;
856 uint64_t propid;
857 vs_scfctx_t vsc;
859 /* ensure that caller has authorization to refresh service */
860 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
861 return (rc);
863 if (vs_scf_ctx_open(&vsc) != 0) {
864 vs_scf_ctx_close(&vsc);
865 return (VS_ERR_SCF);
868 if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
869 vs_scf_ctx_close(&vsc);
870 rc = scf_error();
871 if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
872 if ((rc == SCF_ERROR_NOT_FOUND) ||
873 (rc == SCF_ERROR_INVALID_ARGUMENT))
874 return (VS_ERR_INVALID_SE);
876 return (VS_ERR_SCF);
879 if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
880 (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
881 vs_scf_ctx_close(&vsc);
882 return (VS_ERR_SCF);
885 /* Process the value change for each specified property */
886 rc = 0;
887 np = 0;
888 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
889 if ((prop_hd->vp_ids & propid) == 0)
890 continue;
892 if ((vpd = vs_get_propdef(propid)) == NULL) {
893 rc = VS_ERR_INVALID_PROPERTY;
894 break;
897 vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
898 vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
900 if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
901 rc = VS_ERR_SCF;
902 break;
905 if ((rc = scf_transaction_property_change(vsc.vscf_tx,
906 vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
907 rc = scf_transaction_property_new(vsc.vscf_tx,
908 vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
910 if (rc == -1) {
911 rc = VS_ERR_SCF;
912 break;
915 if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
916 break;
918 ++np;
921 if (rc != VS_ERR_NONE) {
922 vs_scf_ctx_close(&vsc);
923 return (rc);
926 /* Commit the transaction */
927 if (scf_transaction_commit(vsc.vscf_tx) == -1) {
928 vs_scf_ctx_close(&vsc);
929 return (VS_ERR_SCF);
931 vs_scf_ctx_close(&vsc);
933 /* Notify the daemon that things have changed */
934 if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
935 return (VS_ERR_SCF);
937 return (VS_ERR_NONE);
942 * vs_scf_set
944 * Stores a single value from the appropriate vscan property structure
945 * member into the repository.
947 * Values are set in the SCF value object, then the value object
948 * is added to the SCF property object.
950 static int
951 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
952 vs_scfctx_t *vsc, int idx)
954 int rc;
955 vs_props_t *vp = &prop_hd->vp_gen;
956 vs_props_se_t *vep = &prop_hd->vp_se;
958 if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
959 return (rc);
961 rc = VS_ERR_NONE;
962 switch (vpd->vpd_id) {
963 case VS_PROPID_MAXSIZE:
964 if ((scf_value_set_astring(vsc->vscf_val[idx],
965 vp->vp_maxsize)) == -1) {
966 rc = VS_ERR_SCF;
968 break;
969 case VS_PROPID_MAXSIZE_ACTION:
970 scf_value_set_boolean(vsc->vscf_val[idx],
971 (uint8_t)vp->vp_maxsize_action);
972 break;
973 case VS_PROPID_TYPES:
974 if ((scf_value_set_astring(vsc->vscf_val[idx],
975 vp->vp_types)) == -1) {
976 return (VS_ERR_SCF);
978 break;
979 case VS_PROPID_SE_ENABLE:
980 scf_value_set_boolean(vsc->vscf_val[idx],
981 (uint8_t)vep->vep_enable);
982 break;
983 case VS_PROPID_SE_HOST:
984 if ((scf_value_set_from_string(vsc->vscf_val[idx],
985 vpd->vpd_type, vep->vep_host)) == -1) {
986 rc = VS_ERR_SCF;
988 break;
989 case VS_PROPID_SE_PORT:
990 scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
991 break;
992 case VS_PROPID_SE_MAXCONN:
993 scf_value_set_integer(vsc->vscf_val[idx],
994 vep->vep_maxconn);
995 break;
996 case VS_PROPID_VALUE_AUTH:
997 if ((scf_value_set_astring(vsc->vscf_val[idx],
998 VS_VALUE_AUTH)) == -1) {
999 return (VS_ERR_SCF);
1001 break;
1002 default:
1003 break;
1006 if ((scf_entry_add_value(vsc->vscf_ent[idx],
1007 vsc->vscf_val[idx])) == -1) {
1008 return (VS_ERR_SCF);
1011 return (rc);
1016 * vs_scf_ctx_open
1018 * Opens an SCF context; creates the minumum SCF objects
1019 * for use in loading/storing from the SMF repository (meaning
1020 * vscf_property group data).
1022 * Other SCF objects in the context may be initialized elsewher
1023 * subsequent to open, but all initialized structures are destroyed
1024 * in vs_scf_ctx_close().
1026 static int
1027 vs_scf_ctx_open(vs_scfctx_t *vsc)
1029 (void) memset(vsc, 0, sizeof (vs_scfctx_t));
1031 if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
1032 return (VS_ERR_SCF);
1034 if (scf_handle_bind(vsc->vscf_handle) == -1)
1035 return (VS_ERR_SCF);
1037 if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
1038 return (VS_ERR_SCF);
1040 if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
1041 NULL, NULL, vsc->vscf_inst, NULL, NULL,
1042 SCF_DECODE_FMRI_EXACT) == -1) {
1043 return (VS_ERR_SCF);
1046 if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
1047 return (VS_ERR_SCF);
1049 return (VS_ERR_NONE);
1054 * vs_scf_ctx_close
1056 * Closes an SCF context; destroys all initialized SCF objects.
1058 static void
1059 vs_scf_ctx_close(vs_scfctx_t *vsc)
1061 int i;
1063 for (i = 0; i < VS_NUM_PROPIDS; i++) {
1064 if (vsc->vscf_val[i])
1065 scf_value_destroy(vsc->vscf_val[i]);
1066 if (vsc->vscf_ent[i])
1067 scf_entry_destroy(vsc->vscf_ent[i]);
1068 if (vsc->vscf_prop[i])
1069 scf_property_destroy(vsc->vscf_prop[i]);
1072 if (vsc->vscf_iter)
1073 scf_iter_destroy(vsc->vscf_iter);
1074 if (vsc->vscf_tx)
1075 scf_transaction_destroy(vsc->vscf_tx);
1076 if (vsc->vscf_pgroup)
1077 scf_pg_destroy(vsc->vscf_pgroup);
1078 if (vsc->vscf_inst)
1079 scf_instance_destroy(vsc->vscf_inst);
1080 if (vsc->vscf_handle)
1081 scf_handle_destroy(vsc->vscf_handle);
1086 * vs_validate
1088 * Validate property identified in propid.
1090 * Returns: VS_ERR_NONE
1091 * VS_ERR_INVALID_VALUE
1092 * VS_ERR_INVALID_PROPERTY
1094 static int
1095 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
1097 uint64_t num;
1098 const vs_props_t *vp = &prop_hd->vp_gen;
1099 const vs_props_se_t *vep = &prop_hd->vp_se;
1101 switch (propid) {
1102 case VS_PROPID_MAXSIZE:
1103 if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
1104 return (VS_ERR_INVALID_VALUE);
1105 break;
1106 case VS_PROPID_MAXSIZE_ACTION:
1107 break;
1108 case VS_PROPID_TYPES:
1109 if (!vs_is_valid_types(vp->vp_types))
1110 return (VS_ERR_INVALID_VALUE);
1111 break;
1112 case VS_PROPID_SE_ENABLE:
1113 break;
1114 case VS_PROPID_SE_PORT:
1115 if (vep->vep_port == 0)
1116 return (VS_ERR_INVALID_VALUE);
1117 break;
1118 case VS_PROPID_SE_HOST:
1119 if (!vs_is_valid_host(vep->vep_host))
1120 return (VS_ERR_INVALID_VALUE);
1121 break;
1122 case VS_PROPID_SE_MAXCONN:
1123 if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
1124 vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
1125 return (VS_ERR_INVALID_VALUE);
1126 break;
1127 case VS_PROPID_VALUE_AUTH:
1128 case VS_PROPID_VLOG:
1129 break;
1130 default:
1131 return (VS_ERR_INVALID_PROPERTY);
1134 return (VS_ERR_NONE);
1139 * vs_props_validate
1141 * Validate properties identified in propids.
1143 * Returns: VS_ERR_NONE
1144 * VS_ERR_INVALID_VALUE
1145 * VS_ERR_INVALID_PROPERTY
1148 vs_props_validate(const vs_props_t *props, uint64_t propids)
1150 uint64_t propid;
1151 vs_prop_hd_t prop_hd;
1153 if ((propids & VS_PROPID_GEN_ALL) != propids)
1154 return (VS_ERR_INVALID_PROPERTY);
1156 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1157 prop_hd.vp_gen = *props;
1158 prop_hd.vp_type = VS_PTYPE_GEN;
1159 prop_hd.vp_ids = propids;
1160 prop_hd.vp_all = VS_PROPID_GEN_ALL;
1162 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1163 if ((propids & propid) == 0)
1164 continue;
1166 if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1167 return (VS_ERR_INVALID_VALUE);
1170 return (VS_ERR_NONE);
1175 * vs_props_se_validate
1177 * Validate properties identified in propids.
1179 * Returns: VS_ERR_NONE
1180 * VS_ERR_INVALID_VALUE
1181 * VS_ERR_INVALID_PROPERTY
1184 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
1186 uint64_t propid;
1187 vs_prop_hd_t prop_hd;
1189 if ((propids & VS_PROPID_SE_ALL) != propids)
1190 return (VS_ERR_INVALID_PROPERTY);
1192 (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1193 prop_hd.vp_se = *se_props;
1194 prop_hd.vp_type = VS_PTYPE_SE;
1195 prop_hd.vp_ids = propids;
1196 prop_hd.vp_all = VS_PROPID_SE_ALL;
1198 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1199 if ((propids & propid) == 0)
1200 continue;
1202 if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1203 return (VS_ERR_INVALID_VALUE);
1206 return (VS_ERR_NONE);
1211 * vs_is_valid_types
1213 * Checks that types property is a valid format:
1214 * - doesn't exceed VS_VAL_TYPES_MAX
1215 * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1216 * - is correctly formatted - passes the parsing tests
1218 * Returns 1 on success, 0 on failure
1220 static int
1221 vs_is_valid_types(const char *types)
1223 char buf[VS_VAL_TYPES_LEN];
1224 uint32_t len = VS_VAL_TYPES_LEN;
1226 if (strlen(types) > VS_VAL_TYPES_LEN)
1227 return (0);
1229 if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
1230 return (0);
1232 if (vs_parse_types(types, buf, &len) != 0)
1233 return (0);
1235 return (1);
1240 * vs_is_valid_host
1242 * Returns 1 on success, 0 on failure
1244 static int
1245 vs_is_valid_host(const char *host)
1247 long naddr;
1248 const char *p;
1250 if (!host || *host == '\0')
1251 return (0);
1253 if ('0' <= host[0] && host[0] <= '9') {
1254 /* ip address */
1255 if ((inet_pton(AF_INET, host, &naddr)) == 0)
1256 return (0);
1257 if ((naddr & IN_CLASSA_NET) == 0)
1258 return (0);
1259 if ((naddr & IN_CLASSC_HOST) == 0)
1260 return (0);
1261 } else {
1262 /* hostname */
1263 p = host;
1264 while (*p != '\0') {
1265 if (!isascii(*p))
1266 return (0);
1268 if (isalnum(*p) ||
1269 (*p == '.') || (*p == '-') || (*p == '_')) {
1270 ++p;
1271 } else {
1272 return (0);
1277 return (1);
1282 * vs_parse_types
1284 * Replace comma separators with '\0'.
1286 * Types contains comma separated rules each beginning with +|-
1287 * - embedded commas are escaped by backslash
1288 * - backslash is escaped by backslash
1289 * - a single backslash not followed by comma is illegal
1291 * On entry to the function len must contain the length of
1292 * the buffer. On sucecssful exit len will contain the length
1293 * of the parsed data within the buffer.
1295 * Returns 0 on success, -1 on failure
1298 vs_parse_types(const char *types, char *buf, uint32_t *len)
1300 char *p = (char *)types;
1301 char *b = buf;
1303 if (strlen(types) > *len)
1304 return (-1);
1306 if (strchr(VS_TYPES_RULES, *p) == NULL)
1307 return (-1);
1309 (void) memset(buf, 0, *len);
1311 while (*p) {
1312 switch (*p) {
1313 case VS_TYPES_SEP:
1314 if (*(p + 1) &&
1315 (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
1316 return (-1);
1317 *b = '\0';
1318 break;
1319 case VS_TYPES_ESCAPE:
1320 ++p;
1321 if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
1322 *b = *p;
1323 else
1324 return (-1);
1325 break;
1326 default:
1327 *b = *p;
1329 ++p;
1330 ++b;
1333 *len = (b - buf) + 1;
1335 return (0);
1340 * vs_statistics
1343 vs_statistics(vs_stats_t *stats)
1345 int door_fd, rc = VS_ERR_NONE;
1346 vs_stats_req_t *req;
1347 vs_stats_rsp_t *rsp;
1348 door_arg_t arg;
1350 if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1351 return (VS_ERR_SYS);
1353 if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
1354 free(req);
1355 return (VS_ERR_SYS);
1358 if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1359 free(req);
1360 free(rsp);
1361 return (VS_ERR_DAEMON_COMM);
1364 req->vsr_magic = VS_STATS_DOOR_MAGIC;
1365 req->vsr_id = VS_STATS_GET;
1367 arg.data_ptr = (char *)req;
1368 arg.data_size = sizeof (vs_stats_req_t);
1369 arg.desc_ptr = NULL;
1370 arg.desc_num = 0;
1371 arg.rbuf = (char *)rsp;
1372 arg.rsize = sizeof (vs_stats_rsp_t);
1374 rc = vs_door_call(door_fd, &arg);
1376 if ((rc == VS_ERR_NONE) && (rsp->vsr_magic == VS_STATS_DOOR_MAGIC))
1377 *stats = rsp->vsr_stats;
1378 else
1379 rc = VS_ERR_DAEMON_COMM;
1381 (void) close(door_fd);
1383 free(req);
1384 free(rsp);
1385 return (rc);
1390 * vs_statistics_reset
1393 vs_statistics_reset()
1395 int door_fd, rc;
1396 vs_stats_req_t *req;
1397 door_arg_t arg;
1399 /* ensure that caller has authorization to reset stats */
1400 if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
1401 return (rc);
1403 if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1404 return (VS_ERR_SYS);
1406 if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1407 free(req);
1408 return (VS_ERR_DAEMON_COMM);
1411 req->vsr_magic = VS_STATS_DOOR_MAGIC;
1412 req->vsr_id = VS_STATS_RESET;
1414 arg.data_ptr = (char *)req;
1415 arg.data_size = sizeof (vs_stats_req_t);
1416 arg.desc_ptr = NULL;
1417 arg.desc_num = 0;
1418 arg.rbuf = NULL;
1419 arg.rsize = 0;
1421 rc = vs_door_call(door_fd, &arg);
1423 (void) close(door_fd);
1424 free(req);
1425 return (rc);
1429 * Door call with retries.
1431 * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
1433 static int
1434 vs_door_call(int fd, door_arg_t *arg)
1436 int rc = -1;
1437 int i;
1439 for (i = 0; i < VS_DOOR_CALL_RETRIES; ++i) {
1440 errno = 0;
1442 if ((rc = door_call(fd, arg)) == 0)
1443 break;
1445 if (errno != EAGAIN && errno != EINTR)
1446 break;
1449 return ((rc == 0) ? VS_ERR_NONE : VS_ERR_DAEMON_COMM);
1453 * vs_checkauth
1455 static int
1456 vs_checkauth(char *auth)
1458 struct passwd *pw;
1459 uid_t uid;
1461 uid = getuid();
1463 if ((pw = getpwuid(uid)) == NULL)
1464 return (VS_ERR_SYS);
1466 if (chkauthattr(auth, pw->pw_name) != 1) {
1467 return (VS_ERR_AUTH);
1470 return (VS_ERR_NONE);
1475 * vs_props_get_engines
1477 * On input, count specifies the maximum number of engine ids to
1478 * return. engids must be an array with count entries.
1479 * On return, count specifies the number of engine ids being
1480 * returned in engids.
1482 * Caller is responsible for free'ing the engids allocated herein.
1484 static int
1485 vs_props_get_engines(char *engids[], int *count)
1487 int i, prefix_len;
1488 char pgname[VS_PGNAME_ENGINE_LEN];
1489 vs_scfctx_t vsc;
1492 if (((vs_scf_ctx_open(&vsc)) != 0) ||
1493 ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1494 (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1495 SCF_GROUP_APPLICATION) != 0)) {
1496 vs_scf_ctx_close(&vsc);
1497 return (VS_ERR_SCF);
1500 for (i = 0; i < *count; i++)
1501 engids[i] = NULL;
1503 i = 0;
1504 prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
1506 while ((i < VS_SE_MAX) &&
1507 (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
1508 if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
1509 VS_PGNAME_ENGINE_LEN) < 0) {
1510 vs_scf_ctx_close(&vsc);
1511 return (VS_ERR_SCF);
1514 if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
1515 if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
1516 if (++i == *count)
1517 break;
1521 vs_scf_ctx_close(&vsc);
1523 *count = i;
1524 return (VS_ERR_NONE);
1529 * vs_scf_pg_count
1531 static int
1532 vs_scf_pg_count(void)
1534 int count = 0;
1535 vs_scfctx_t vsc;
1537 if ((vs_scf_ctx_open(&vsc) != 0) ||
1538 ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1539 (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1540 SCF_GROUP_APPLICATION) != 0)) {
1541 vs_scf_ctx_close(&vsc);
1542 return (-1);
1545 while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
1546 ++count;
1548 vs_scf_ctx_close(&vsc);
1550 return (count);
1555 * vs_engid_to_pgname
1557 * To convert an engine id (engid) to a property group name (pgname),
1558 * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1560 static void
1561 vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
1563 (void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
1564 VS_PGNAME_ENGINE_PREFIX, engid);
1569 * vs_strtonum
1571 * Converts a size string in the format into an integer.
1573 * A size string is a numeric value followed by an optional unit
1574 * specifier which is used as a multiplier to calculate a raw
1575 * number.
1576 * The size string format is: N[.N][KMGTP][B]
1578 * The numeric value can contain a decimal portion. Unit specifiers
1579 * are either a one-character or two-character string; i.e. "K" or
1580 * "KB" for kilobytes. Unit specifiers must follow the numeric portion
1581 * immediately, and are not case-sensitive.
1583 * If either "B" is specified, or there is no unit specifier portion
1584 * in the string, the numeric value is calculated with no multiplier
1585 * (assumes a basic unit of "bytes").
1587 * Returns:
1588 * -1: Failure; errno set to specify the error.
1589 * 0: Success.
1592 vs_strtonum(const char *value, uint64_t *num)
1594 char *end;
1595 int shift;
1596 double fval;
1598 *num = 0;
1600 /* Check to see if this looks like a number. */
1601 if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1602 errno = EINVAL;
1603 return (-1);
1606 /* Rely on stroll() to process the numeric portion. */
1607 errno = 0;
1608 *num = strtoll(value, &end, 10);
1611 * Check for ERANGE, which indicates that the value is too large to
1612 * fit in a 64-bit value.
1614 if (errno != 0)
1615 return (-1);
1618 * If we have a decimal value, then do the computation with floating
1619 * point arithmetic. Otherwise, use standard arithmetic.
1621 if (*end == '.') {
1622 fval = strtod(value, &end);
1624 if ((shift = vs_strtoshift(end)) == -1)
1625 return (-1); /* errno set */
1627 fval *= pow(2, shift);
1628 if (fval > UINT64_MAX) {
1629 errno = ERANGE;
1630 return (-1);
1633 *num = (uint64_t)fval;
1634 } else {
1635 if ((shift = vs_strtoshift(end)) == -1)
1636 return (-1); /* errno set */
1638 /* Check for overflow */
1639 if (shift >= 64 || (*num << shift) >> shift != *num) {
1640 errno = ERANGE;
1641 return (-1);
1644 *num <<= shift;
1647 return (0);
1652 * vs_strtoshift
1654 * Converts a unit specifier string into a number of bits that
1655 * a numeric value must be shifted.
1657 * Returns:
1658 * -1: Failure; errno set to specify the error.
1659 * >-1: Success; the shift count.
1662 static int
1663 vs_strtoshift(const char *buf)
1665 const char *ends = "BKMGTPEZ";
1666 int i;
1668 if (buf[0] == '\0')
1669 return (0);
1670 for (i = 0; i < strlen(ends); i++) {
1671 if (toupper(buf[0]) == ends[i])
1672 break;
1674 if (i == strlen(ends)) {
1675 errno = EINVAL;
1676 return (-1);
1679 /* Allow trailing 'b' characters except in the case of 'BB'. */
1680 if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
1681 toupper(buf[0]) != 'B')) {
1682 return (10 * i);
1685 errno = EINVAL;
1686 return (-1);