8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libdscfg / common / cfg_vols.c
blob6f0f8bb44736b8e377f0b654e987e9dbc7dec23c
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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <sys/mkdev.h>
32 #include <strings.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <locale.h>
36 #include <errno.h>
38 #include <sys/nsctl/cfg.h>
40 #include <sys/unistat/spcs_s.h>
41 #include <sys/unistat/spcs_s_u.h>
42 #include <sys/unistat/spcs_errors.h>
43 #include <sys/unistat/spcs_s_impl.h>
45 #include <sys/nsctl/sv.h>
46 #include <sys/nsctl/nsc_hash.h>
48 #define DEV_EXPAND 32
50 #define DO_DISABLE 0
51 #define DO_ENABLE 1
54 * Utility functions for iiadm and rdcadm/sndradm.
57 typedef struct hash_data_s {
58 union {
59 char *users;
60 char *mode;
61 } u;
62 char *path;
63 char *node;
64 int setno;
65 } hash_data_t;
67 typedef struct {
68 dev_t rdev;
69 mode_t mode;
70 char *path;
71 } device_t;
73 static hash_data_t *make_svol_data(char *, char *, char *, int);
74 static hash_data_t *make_dsvol_data(char *, char *, char *, int);
75 static void delete_svol_data(void *);
76 static void delete_dsvol_data(void *);
77 static int sv_action(char *, CFGFILE *, char *, int);
79 static int add_dev_entry(const char *);
80 static int compare(const void *, const void *);
81 static char *find_devid(const char *);
82 static void free_dev_entries();
83 static void rebuild_devhash();
85 static hash_node_t **dsvol;
86 static int dsvol_loaded = 0;
88 static hash_node_t **svol;
89 static int svol_loaded = 0;
91 static hash_node_t **shadowvol;
93 static hash_node_t **devhash;
94 static device_t *devlist;
95 static int devcount = 0;
96 static int devalloc = 0;
99 * cfg_add_user
101 * Description:
102 * Adds the calling tool as a user of the volume.
104 * Inputs:
105 * char *path: The pathname of the volume to be enabled.
106 * char *cnode: The device group name, or NULL if -C local or not cluster
107 * CFGFILE *cfg: A pointer to the current config file, or NULL if this
108 * function is to open/write/commit/close the change itself.
110 * Return values:
111 * CFG_USER_FIRST: Indicates that this is the first user of this
112 * particular volume.
113 * CFG_USER_OK: Indicates that the volume has already been entered into
114 * the config file.
115 * CFG_USER_ERR: Indicates that some failure has occurred and no changes
116 * to the config file have been made.
117 * CFG_USER_REPEAT: Indicates that this user has already registered for
118 * the volume.
121 cfg_add_user(CFGFILE* cfg, char *path, char *cnode, char *user)
123 int self_open, self_loaded, change_made;
124 char *ctag, search_key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
125 int retval, rc;
126 hash_data_t *data;
128 self_open = (cfg == NULL);
129 self_loaded = 0;
130 change_made = 0;
132 if (self_open) {
133 cfg = cfg_open(NULL);
134 if (cfg == NULL) {
135 return (CFG_USER_ERR);
138 if (!cfg_lock(cfg, CFG_WRLOCK)) {
139 /* oops */
140 cfg_close(cfg);
141 return (CFG_USER_ERR);
145 /* Check cnode */
146 ctag = cfg_get_resource(cfg);
147 if (cnode) {
148 if (ctag) {
149 if (strcmp(cnode, ctag))
150 return (CFG_USER_ERR);
151 } else
152 cfg_resource(cfg, cnode);
153 } else
154 cnode = ctag;
156 if (!dsvol_loaded) {
157 if (cfg_load_dsvols(cfg) < 0) {
158 if (self_open) {
159 cfg_close(cfg);
161 return (CFG_USER_ERR);
163 self_loaded = 1;
166 /* find the volume */
167 (void) snprintf(search_key, CFG_MAX_KEY, "%s:%s", path, cnode);
168 data = nsc_lookup(dsvol, search_key);
170 if (!data) {
171 /* whoops, not found. Add as new user */
172 cfg_rewind(cfg, CFG_SEC_CONF);
173 (void) snprintf(buf, CFG_MAX_BUF, "%s %s %s", path, cnode,
174 user);
175 rc = cfg_put_cstring(cfg, "dsvol", buf, strlen(buf));
176 if (rc < 0) {
177 if (self_loaded) {
178 cfg_unload_dsvols();
180 if (self_open) {
181 cfg_close(cfg);
183 return (CFG_USER_ERR);
185 /* reload hash, if we need to */
186 if (!self_loaded) {
187 cfg_unload_dsvols();
188 if (cfg_load_dsvols(cfg) < 0) {
189 if (self_open) {
190 cfg_close(cfg);
192 return (CFG_USER_ERR);
195 retval = CFG_USER_FIRST;
196 change_made = 1;
197 } else {
198 /* Check to ensure we're not already listed */
199 char *p = strdup(data->u.users);
200 char *q = strtok(p, ",");
201 while (q && (strcmp(q, user) != 0)) {
202 q = strtok(0, ",");
204 free(p); /* not using data; only testing 'q' ptr */
206 if (!q) {
207 /* not listed as a user */
208 cfg_rewind(cfg, CFG_SEC_CONF);
209 (void) snprintf(buf, CFG_MAX_BUF, "%s %s %s,%s",
210 data->path, data->node, data->u.users, user);
211 (void) snprintf(search_key, CFG_MAX_KEY, "dsvol.set%d",
212 data->setno);
213 if (cfg_put_cstring(cfg, search_key, buf,
214 strlen(buf)) < 0) {
215 if (self_loaded) {
216 cfg_unload_dsvols();
218 if (self_open) {
219 cfg_close(cfg);
221 return (CFG_USER_ERR);
225 * Since we deleted an entry from the config
226 * file, we don't know what all the new
227 * set numbers are. We need to reload
228 * everything
230 if (!self_loaded) {
231 cfg_unload_dsvols();
232 if (cfg_load_dsvols(cfg) < 0) {
233 if (self_open) {
234 cfg_close(cfg);
236 return (CFG_USER_ERR);
239 change_made = 1;
240 retval = CFG_USER_OK;
241 } else {
242 retval = CFG_USER_REPEAT;
246 if (self_loaded) {
247 cfg_unload_dsvols();
250 if (self_open) {
251 if (change_made)
252 (void) cfg_commit(cfg);
253 cfg_close(cfg);
256 return (retval);
260 * cfg_rem_user
262 * Description:
263 * Removes a user from the config file.
265 * Inputs:
266 * char *path: The pathname of the volume to be enabled.
267 * char *cnode: The device group name, or NULL if -C local or not cluster
268 * char *user: The subsystem that is adding this tag (sv, ii, sndr)
269 * CFGFILE *cfg: A pointer to the current config file, or NULL if this
270 * function is to open/write/commit/close the change itself.
271 * Return values:
272 * CFG_USER_ERR: An error occurred during the processing of this
273 * directive.
274 * CFG_USER_OK: User successfully removed; volume in use by other(s).
275 * CFG_USER_LAST: User successfuly removed; no other users registered
276 * CFG_USER_GONE: The volume is no longer listed in the dsvol section,
277 * indicating some sort of application-level error.
281 cfg_rem_user(CFGFILE *cfg, char *path, char *cnode, char *user)
283 int self_open, self_loaded, change_made;
284 char *ctag, search_key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
285 char cfg_key[ CFG_MAX_KEY ];
286 hash_data_t *data;
287 int retval;
288 int force_remove;
290 self_open = (cfg == NULL);
291 self_loaded = 0;
292 change_made = 0;
293 force_remove = (strcmp(user, "sv") == 0);
295 if ('-' == *user) {
296 ++user;
299 /* Check cnode */
300 ctag = cfg_get_resource(cfg);
301 if (cnode) {
302 if (ctag) {
303 if (strcmp(cnode, ctag))
304 return (CFG_USER_ERR);
305 } else
306 cfg_resource(cfg, cnode);
307 } else
308 cnode = ctag;
310 if (self_open) {
311 cfg = cfg_open(NULL);
312 if (cfg == NULL) {
313 return (CFG_USER_ERR);
316 if (!cfg_lock(cfg, CFG_WRLOCK)) {
317 /* oops */
318 cfg_close(cfg);
319 return (CFG_USER_ERR);
324 change_made = 0;
325 if (!dsvol_loaded) {
326 if (cfg_load_dsvols(cfg) < 0) {
327 if (self_open) {
328 cfg_close(cfg);
330 return (CFG_USER_ERR);
332 self_loaded = 1;
335 /* find the volume */
336 (void) snprintf(search_key, CFG_MAX_KEY, "%s:%s", path, cnode);
337 data = nsc_lookup(dsvol, search_key);
339 if (!data) {
340 /* yipes */
341 retval = CFG_USER_GONE;
342 } else if (force_remove) {
343 retval = CFG_USER_LAST;
344 cfg_rewind(cfg, CFG_SEC_CONF);
345 (void) snprintf(cfg_key, CFG_MAX_KEY, "dsvol.set%d",
346 data->setno);
347 if (cfg_put_cstring(cfg, cfg_key, NULL, 0) < 0) {
348 if (self_loaded) {
349 cfg_unload_dsvols();
351 if (self_open) {
352 cfg_close(cfg);
354 return (CFG_USER_ERR);
356 if (!self_loaded) {
357 cfg_unload_dsvols();
358 if (cfg_load_dsvols(cfg) < 0) {
359 if (self_open) {
360 cfg_close(cfg);
362 return (CFG_USER_ERR);
365 } else {
366 char *p = strdup(data->u.users);
367 char *q = strtok(p, ",");
368 int appended = 0;
370 (void) snprintf(buf, CFG_MAX_BUF, "%s %s ", data->path,
371 data->node);
372 while (q && (strcmp(q, user) != 0)) {
373 if (appended) {
374 strcat(buf, ",");
375 strcat(buf, q);
376 } else {
377 strcat(buf, q);
378 appended = 1;
380 q = strtok(0, ",");
383 if (!q) {
384 /* uh-oh */
385 retval = CFG_USER_GONE;
386 } else {
387 /* old user skipped; add in remaining users */
388 while (q = strtok(0, ", ")) {
389 if (appended) {
390 strcat(buf, ",");
391 strcat(buf, q);
392 } else {
393 strcat(buf, q);
394 appended = 1;
398 if (appended) {
399 retval = CFG_USER_OK;
400 cfg_rewind(cfg, CFG_SEC_CONF);
401 (void) snprintf(cfg_key, CFG_MAX_KEY,
402 "dsvol.set%d", data->setno);
403 if (cfg_put_cstring(cfg, cfg_key, buf,
404 strlen(buf)) < 0) {
405 if (self_loaded) {
406 cfg_unload_dsvols();
408 if (self_open) {
409 cfg_close(cfg);
411 return (CFG_USER_ERR);
413 if (!self_loaded) {
414 cfg_unload_dsvols();
415 if (cfg_load_dsvols(cfg) < 0) {
416 if (self_open) {
417 cfg_close(cfg);
419 return (CFG_USER_ERR);
422 } else {
423 retval = CFG_USER_LAST;
424 cfg_rewind(cfg, CFG_SEC_CONF);
425 (void) snprintf(cfg_key, CFG_MAX_KEY,
426 "dsvol.set%d", data->setno);
427 if (cfg_put_cstring(cfg, cfg_key, NULL,
428 0) < 0) {
429 if (self_loaded) {
430 cfg_unload_dsvols();
432 if (self_open) {
433 cfg_close(cfg);
435 return (CFG_USER_ERR);
438 * Since we deleted an entry from the config
439 * file, we don't know what all the new
440 * set numbers are. We need to reload
441 * everything
443 if (!self_loaded) {
444 cfg_unload_dsvols();
445 if (cfg_load_dsvols(cfg) < 0) {
446 if (self_open) {
447 cfg_close(cfg);
449 return (CFG_USER_ERR);
453 change_made = 1;
457 if (self_loaded) {
458 cfg_unload_dsvols();
461 if (self_open) {
462 if (change_made)
463 (void) cfg_commit(cfg);
464 cfg_close(cfg);
467 return (retval);
471 * Enable a volume under SV control (or add this char *user to the list
472 * of users of that volume).
474 * Parameters:
475 * cfg - The config file to use.
476 * path - The pathname of the volume
477 * ctag - The cluster tag for this volume (if any)
478 * user - The user (sv, ii, sndr) of the volume.
481 cfg_vol_enable(CFGFILE *cfg, char *path, char *ctag, char *user)
483 int rc;
484 int retval;
486 if (!ctag || *ctag == '\0') {
487 ctag = "-";
490 retval = -1;
491 rc = cfg_add_user(cfg, path, ctag, user);
492 switch (rc) {
493 case CFG_USER_ERR:
494 spcs_log("dsvol", NULL,
495 gettext("unable to set up dsvol section of config for %s"),
496 path);
497 break;
498 case CFG_USER_OK:
499 retval = 0;
500 break;
501 case CFG_USER_FIRST:
502 /* enable sv! */
503 retval = sv_action(path, cfg, ctag, DO_ENABLE);
504 if (retval < 0) {
505 (void) cfg_rem_user(cfg, path, ctag, user);
507 break;
508 default:
509 spcs_log("dsvol", NULL,
510 gettext("unexpected return from cfg_add_user(%d)"), rc);
511 break;
514 return (retval);
518 * Disable a volume from SV control (or remove this char *user from the list
519 * of users of that volume).
521 * Parameters:
522 * cfg - The config file to use.
523 * path - The pathname of the volume
524 * ctag - The cluster tag for this volume (if any)
525 * user - The user (sv, ii, sndr) of the volume.
528 cfg_vol_disable(CFGFILE *cfg, char *path, char *ctag, char *user)
530 int rc;
531 int retval;
533 if (!ctag || *ctag == '\0') {
534 ctag = "-";
537 retval = -1;
538 rc = cfg_rem_user(cfg, path, ctag, user);
539 switch (rc) {
540 case CFG_USER_ERR:
541 spcs_log("dsvol", NULL,
542 gettext("unable to set up dsvol section of config for %s"),
543 path);
544 break;
545 case CFG_USER_OK:
546 retval = 0;
547 break;
548 case CFG_USER_GONE:
549 spcs_log("dsvol", NULL,
550 gettext("%s tried to remove non-existent tag for %s"),
551 user, path);
552 break;
553 case CFG_USER_LAST:
554 /* diable sv! */
555 retval = sv_action(path, cfg, ctag, DO_DISABLE);
556 break;
557 default:
558 spcs_log("dsvol", NULL,
559 gettext("unexpected return from cfg_rem_user(%d)"), rc);
560 break;
563 return (retval);
567 * cfg_load_dsvols
569 * Description:
570 * Loads the dsvol section of the config file into a giant hash, to
571 * make searching faster. The important bit to remember is to not
572 * release the write lock between calling cfg_load_dsvols() and the
573 * cfg_*_user() functions.
575 * Assumptions:
576 * 1/ cfg file is open
577 * 2/ cfg file has been write-locked
578 * 3/ user of this routine may already be using hcreate/hsearch
580 * Return value:
581 * -1 if error, or total number of sets found
584 cfg_load_dsvols(CFGFILE *cfg)
586 int set, rc, entries;
587 char search_key[ CFG_MAX_KEY ];
588 char *buf;
589 char **entry, *path, *cnode, *users;
590 hash_data_t *data;
591 int devs_added = 0;
592 int offset = 0;
593 char *ctag = cfg_get_resource(cfg);
594 if (!ctag || *ctag == '\0') {
595 ctag = "-";
598 dsvol = nsc_create_hash();
599 if (!dsvol) {
600 return (-1);
603 rc = 0;
604 cfg_rewind(cfg, CFG_SEC_CONF);
605 entries = cfg_get_section(cfg, &entry, "dsvol");
606 for (set = 1; set <= entries; set++) {
607 buf = entry[set - 1];
609 /* split up the line */
610 if (!(path = strtok(buf, " "))) {
611 /* oops, now what? */
612 free(buf);
613 break;
615 if (!(cnode = strtok(0, " "))) {
616 free(buf);
617 break;
619 if (ctag && (strcmp(cnode, ctag) != 0)) {
620 ++offset;
621 free(buf);
622 continue;
625 if (!(users = strtok(0, " "))) {
626 free(buf);
627 break;
630 data = make_dsvol_data(path, cnode, users, set - offset);
631 if (!data) {
632 free(buf);
633 break;
635 (void) snprintf(search_key, CFG_MAX_KEY, "%s:%s", path, cnode);
636 rc = nsc_insert_node(dsvol, data, search_key);
637 if (rc < 0) {
638 free(buf);
639 break;
642 /* we also need to keep track of node information */
643 rc = add_dev_entry(path);
644 if (rc < 0) {
645 free(buf);
646 break;
647 } else if (rc)
648 ++devs_added;
650 free(buf);
651 rc = 0;
654 while (set < entries)
655 free(entry[set++]);
656 if (entries)
657 free(entry);
659 if (devs_added) {
660 qsort(devlist, devcount, sizeof (device_t), compare);
661 rebuild_devhash();
664 dsvol_loaded = 1;
665 return (rc < 0? rc : entries);
669 * cfg_unload_dsvols
671 * Description:
672 * Free all memory allocated with cfg_load_dsvols.
674 void
675 cfg_unload_dsvols()
677 if (dsvol) {
678 nsc_remove_all(dsvol, delete_dsvol_data);
679 dsvol = 0;
680 dsvol_loaded = 0;
685 * cfg_load_svols
687 * Description:
688 * Loads the sv section of the config file into a giant hash, to make
689 * searching faster. The important bit to remember is to not release
690 * the write lock between calling cfg_load_svols() and the cfg_*_user()
691 * functions.
693 * Assumptions:
694 * 1/ cfg file is open
695 * 2/ cfg file has been write-locked
696 * 3/ user of this routine may already be using builtin hcreate/hsearch
699 cfg_load_svols(CFGFILE *cfg)
701 int set, entries, offset = 0;
702 char *buf, **entry;
703 char *path, *mode, *cnode;
704 hash_data_t *data;
705 char *ctag = cfg_get_resource(cfg);
706 if (!ctag || *ctag == '\0') {
707 ctag = "-";
710 svol = nsc_create_hash();
711 if (!svol) {
712 return (-1);
715 cfg_rewind(cfg, CFG_SEC_CONF);
716 entries = cfg_get_section(cfg, &entry, "sv");
717 for (set = 1; set <= entries; set++) {
718 buf = entry[set - 1];
720 /* split up the line */
721 if (!(path = strtok(buf, " "))) {
722 free(buf);
723 break;
725 if (!(mode = strtok(0, " "))) {
726 free(buf);
727 break;
729 if (!(cnode = strtok(0, " "))) {
730 cnode = "";
733 if (ctag && (strcmp(cnode, ctag) != 0)) {
734 ++offset;
735 free(buf);
736 continue;
739 data = make_svol_data(path, mode, cnode, set - offset);
740 if (!data) {
741 free(buf);
742 break;
744 if (nsc_insert_node(svol, data, path) < 0) {
745 free(buf);
746 break;
748 free(buf);
750 while (set < entries)
751 free(entry[set++]);
752 if (entries)
753 free(entry);
755 svol_loaded = 1;
756 return (0);
760 * cfg_unload_svols
762 * Description:
763 * Frees all memory allocated with cfg_load_dsvols
765 void
766 cfg_unload_svols()
768 if (svol) {
769 nsc_remove_all(svol, delete_svol_data);
770 svol = 0;
771 svol_loaded = 0;
776 * cfg_get_canonical_name
778 * Description:
779 * Find out whether a device is already known by another name in
780 * the config file.
782 * Parameters:
783 * cfg - The config file to use
784 * path - The pathname of the device
785 * result - (output) The name it is otherwise known as. This parameter
786 * must be freed by the caller.
788 * Return values:
789 * -1: error
790 * 0: name is as expected, or is not known
791 * 1: Name is known by different name (stored in 'result')
794 cfg_get_canonical_name(CFGFILE *cfg, const char *path, char **result)
796 int self_loaded;
797 char *alt_path;
798 int retval;
800 if (devlist) {
801 self_loaded = 0;
802 } else {
803 if (cfg_load_shadows(cfg) < 0) {
804 return (-1);
806 self_loaded = 1;
809 /* see if it exists under a different name */
810 alt_path = find_devid(path);
811 if (!alt_path || strcmp(path, alt_path) == 0) {
812 *result = NULL;
813 retval = 0;
814 } else {
815 /* a-ha */
816 *result = strdup(alt_path);
817 retval = 1;
820 if (self_loaded) {
821 free_dev_entries();
824 return (retval);
828 * cfg_load_shadows
830 * Description:
831 * Load in shadow and bitmap volumes from the II section of the
832 * config file. SNDR's volumes are handled already by cfg_load_dsvols.
833 * Not all shadow volumes are listed under dsvol: they can be exported.
835 * Parameters:
836 * cfg - The config file to use
838 * Return values:
839 * -1: error
840 * 0: success
843 cfg_load_shadows(CFGFILE *cfg)
845 int set, self_loaded, rc, entries;
846 char *buf, **entry, *ptr;
847 int devs_added = 0;
849 if (dsvol_loaded) {
850 self_loaded = 0;
851 } else {
852 if (cfg_load_dsvols(cfg) < 0) {
853 return (-1);
855 self_loaded = 1;
858 shadowvol = nsc_create_hash();
859 if (!shadowvol) {
860 return (-1);
863 rc = 0;
864 cfg_rewind(cfg, CFG_SEC_CONF);
865 entries = cfg_get_section(cfg, &entry, "ii");
866 for (set = 1; set <= entries; set++) {
867 buf = entry[set - 1];
869 /* skip the master vol */
870 ptr = strtok(buf, " ");
872 /* shadow is next */
873 ptr = strtok(NULL, " ");
875 rc = add_dev_entry(ptr);
876 if (rc < 0) {
877 free(buf);
878 break;
879 } else if (rc)
880 ++devs_added;
882 /* and next is bitmap */
883 ptr = strtok(NULL, " ");
885 rc = add_dev_entry(ptr);
886 if (rc < 0) {
887 free(buf);
888 break;
889 } else if (rc)
890 ++devs_added;
891 rc = 0;
892 free(buf);
894 while (set < entries)
895 free(entry[set++]);
896 if (entries)
897 free(entry);
899 if (self_loaded) {
900 cfg_unload_dsvols();
903 if (devs_added) {
904 /* sort it, in preparation for lookups */
905 qsort(devlist, devcount, sizeof (device_t), compare);
906 rebuild_devhash();
909 return (rc);
912 void
913 cfg_unload_shadows()
915 /* do nothing */
918 /* ---------------------------------------------------------------------- */
920 static hash_data_t *
921 make_dsvol_data(char *path, char *cnode, char *users, int set)
923 hash_data_t *data;
925 data = (hash_data_t *)malloc(sizeof (hash_data_t));
926 if (!data) {
927 return (0);
930 data->u.users = strdup(users);
931 data->path = strdup(path);
932 data->node = strdup(cnode);
933 data->setno = set;
935 return (data);
938 static void
939 delete_dsvol_data(void *data)
941 hash_data_t *p = (hash_data_t *)data;
943 free(p->u.users);
944 free(p->path);
945 free(p->node);
946 free(p);
949 static hash_data_t *
950 make_svol_data(char *path, char *mode, char *cnode, int set)
952 hash_data_t *data;
954 data = (hash_data_t *)malloc(sizeof (hash_data_t));
955 if (!data) {
956 return (0);
959 data->u.mode = strdup(mode);
960 data->path = strdup(path);
961 data->node = strdup(cnode);
962 data->setno = set;
964 return (data);
968 static void
969 delete_svol_data(void *data)
971 hash_data_t *p = (hash_data_t *)data;
973 free(p->u.mode);
974 free(p->path);
975 free(p->node);
976 free(p);
979 static int
980 sv_action(char *path, CFGFILE *caller_cfg, char *ctag, int enable)
982 struct stat stb;
983 sv_conf_t svc;
984 int fd = -1;
985 int cfg_changed = 0;
986 CFGFILE *cfg;
987 int print_log = 0;
988 int err = 0, rc;
989 int sv_ioctl, spcs_err, self_loaded;
990 char *log_str1, *log_str2;
991 char key[ CFG_MAX_KEY ];
992 char buf[ CFG_MAX_BUF ];
993 hash_data_t *node;
994 device_t *statinfo = 0;
996 if (caller_cfg == NULL) {
997 cfg = cfg_open(NULL);
998 if (cfg == NULL)
999 return (-1);
1001 if (ctag)
1002 cfg_resource(cfg, ctag);
1003 } else
1004 cfg = caller_cfg;
1007 self_loaded = 0;
1008 sv_ioctl = (enable? SVIOC_ENABLE : SVIOC_DISABLE);
1009 log_str1 = (enable? gettext("enabled %s") : gettext("disabled %s"));
1010 log_str2 = (enable? gettext("unable to enable %s") :
1011 gettext("unable to disable %s"));
1012 spcs_err = (enable? SV_EENABLED : SV_EDISABLED);
1013 bzero(&svc, sizeof (svc));
1015 if (devhash)
1016 statinfo = nsc_lookup(devhash, path);
1018 if (statinfo) {
1019 if (!S_ISCHR(statinfo->mode))
1020 goto error;
1021 svc.svc_major = major(statinfo->rdev);
1022 svc.svc_minor = minor(statinfo->rdev);
1023 } else {
1024 if (stat(path, &stb) != 0)
1025 goto error;
1027 if (!S_ISCHR(stb.st_mode))
1028 goto error;
1029 svc.svc_major = major(stb.st_rdev);
1030 svc.svc_minor = minor(stb.st_rdev);
1033 strncpy(svc.svc_path, path, sizeof (svc.svc_path));
1035 fd = open(SV_DEVICE, O_RDONLY);
1036 if (fd < 0)
1037 goto error;
1039 svc.svc_flag = (NSC_DEVICE | NSC_CACHE);
1040 svc.svc_error = spcs_s_ucreate();
1042 do {
1043 rc = ioctl(fd, sv_ioctl, &svc);
1044 } while (rc < 0 && errno == EINTR);
1046 if (rc < 0) {
1047 if (errno != spcs_err) {
1048 spcs_log("sv", &svc.svc_error, log_str2, svc.svc_path);
1049 if (enable)
1050 goto error;
1051 else
1052 err = errno;
1053 } else
1054 err = spcs_err;
1057 spcs_log("sv", NULL, log_str1, svc.svc_path);
1059 /* SV enable succeeded */
1060 if (caller_cfg == NULL) /* was not previously locked */
1061 if (!cfg_lock(cfg, CFG_WRLOCK))
1062 goto error;
1064 if (err != spcs_err) { /* already enabled, already in config */
1065 if (enable) {
1066 cfg_rewind(cfg, CFG_SEC_CONF);
1067 (void) snprintf(buf, CFG_MAX_BUF, "%s - %s", path,
1068 ctag? ctag : "-");
1069 if (cfg_put_cstring(cfg, "sv", buf, CFG_MAX_BUF) < 0) {
1070 /* SV config not updated, so SV disable again */
1071 (void) ioctl(fd, SVIOC_DISABLE, &svc);
1072 print_log++;
1073 } else
1074 cfg_changed = 1;
1075 } else {
1076 /* pull it out of the config */
1077 if (!svol_loaded) {
1078 if (cfg_load_svols(cfg) < 0) {
1079 if (NULL == caller_cfg) {
1080 cfg_close(cfg);
1082 return (-1);
1084 self_loaded = 1;
1086 node = nsc_lookup(svol, svc.svc_path);
1087 if (node) {
1088 cfg_rewind(cfg, CFG_SEC_CONF);
1089 (void) snprintf(key, CFG_MAX_KEY, "sv.set%d",
1090 node->setno);
1091 if (cfg_put_cstring(cfg, key, NULL, NULL) < 0) {
1092 spcs_log("sv", NULL,
1093 gettext("failed to remove %s from "
1094 "sv config"), svc.svc_path);
1097 * Since we deleted an entry from the config
1098 * file, we don't know what all the new
1099 * set numbers are. We need to reload
1100 * everything
1102 if (!self_loaded) {
1103 cfg_unload_svols();
1104 if (cfg_load_svols(cfg) < 0) {
1105 if (NULL == caller_cfg) {
1106 cfg_close(cfg);
1108 return (-1);
1111 cfg_changed = 1;
1113 if (self_loaded) {
1114 cfg_unload_svols();
1115 self_loaded = 0;
1120 #ifdef lint
1121 (void) printf("extra line to shut lint up %s\n", module_names[0]);
1122 #endif
1124 error:
1125 if (fd >= 0)
1126 (void) close(fd);
1128 if (cfg == NULL)
1129 return (-1);
1131 if (cfg_changed)
1132 if (caller_cfg == NULL) /* we opened config */
1133 (void) cfg_commit(cfg);
1135 if (caller_cfg == NULL)
1136 cfg_close(cfg);
1137 if ((cfg_changed) || (err == spcs_err))
1138 return (1);
1139 if (print_log)
1140 spcs_log("sv", NULL,
1141 gettext("unable to add to configuration, disabled %s"),
1142 svc.svc_path);
1143 spcs_s_ufree(&svc.svc_error);
1145 return (-1);
1149 * add_dev_entry
1151 * Add an entry into the devlist and the devhash for future lookups.
1153 * Return values:
1154 * -1 An error occurred.
1155 * 0 Entry added
1156 * 1 Entry already exists.
1158 static int
1159 add_dev_entry(const char *path)
1161 struct stat buf;
1162 device_t *newmem;
1163 hash_data_t *data;
1165 if (!devhash) {
1166 devhash = nsc_create_hash();
1167 if (!devhash) {
1168 return (-1);
1170 } else {
1171 data = nsc_lookup(devhash, path);
1172 if (data) {
1173 return (1);
1177 if (stat(path, &buf) < 0) {
1178 /* ignore error, we are most likely deleting entry anyway */
1179 buf.st_rdev = 0;
1182 if (devcount >= devalloc) {
1183 /* make some room */
1184 devalloc += DEV_EXPAND;
1185 newmem = (device_t *)realloc(devlist, devalloc *
1186 sizeof (device_t));
1187 if (!newmem) {
1188 free_dev_entries();
1189 return (-1);
1190 } else {
1191 devlist = newmem;
1195 devlist[ devcount ].path = strdup(path);
1196 devlist[ devcount ].rdev = buf.st_rdev;
1197 devlist[ devcount ].mode = buf.st_mode;
1199 if (nsc_insert_node(devhash, &devlist[devcount], path) < 0) {
1200 return (-1);
1203 ++devcount;
1204 return (0);
1207 static void
1208 rebuild_devhash()
1210 int i;
1212 if (!devhash)
1213 nsc_remove_all(devhash, 0);
1215 devhash = nsc_create_hash();
1216 if (!devhash)
1217 return;
1219 for (i = 0; i < devcount; i++) {
1220 nsc_insert_node(devhash, &devlist[i], devlist[i].path);
1224 static int
1225 compare(const void *va, const void *vb)
1227 device_t *a = (device_t *)va;
1228 device_t *b = (device_t *)vb;
1230 return (b->rdev - a->rdev);
1233 static char *
1234 find_devid(const char *path)
1236 device_t key;
1237 device_t *result;
1238 struct stat buf;
1240 if (!devlist || !devhash)
1241 return (NULL);
1243 /* See if we already know the device id by this name */
1244 result = (device_t *)nsc_lookup(devhash, path);
1245 if (result) {
1246 return (NULL);
1249 /* try to find it by another name */
1250 if (stat(path, &buf) < 0)
1251 return (NULL);
1253 key.rdev = buf.st_rdev;
1255 /* it's storted, so we use the binary-chop method to find it */
1256 result = bsearch(&key, devlist, devcount, sizeof (device_t), compare);
1258 if (result) {
1259 return (result->path);
1262 return (NULL);
1265 static void
1266 free_dev_entries()
1268 int i;
1269 device_t *p;
1271 if (!devlist) {
1272 return;
1274 for (i = 0, p = devlist; i < devcount; i++, p++) {
1275 free(p->path);
1277 free(devlist);
1278 devlist = NULL;
1279 devcount = 0;
1280 devalloc = 0;
1282 if (devhash) {
1283 nsc_remove_all(devhash, 0);
1284 devhash = NULL;