8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / avs / sv / svadm.c
blob4fee03b27787dacb5f5d661fcdc3a56590192052
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 <sys/stat.h>
28 #include <sys/mkdev.h>
29 #include <sys/param.h>
30 #include <sys/wait.h>
31 #include <fcntl.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <locale.h>
38 #include <unistd.h>
39 #include <search.h>
40 #include <libgen.h>
41 #include <nsctl.h>
43 #include <sys/unistat/spcs_s.h>
44 #include <sys/unistat/spcs_s_u.h>
45 #include <sys/unistat/spcs_errors.h>
47 #include <sys/nsctl/sv.h>
48 #include <sys/nsctl/sv_impl.h>
50 #include <sys/nsctl/cfg.h>
51 #include <sys/nsctl/nsc_hash.h>
53 #include "../sv/svadm.h"
56 static int sv_max_devices;
60 * support for the special cluster tag "local" to be used with -C in a
61 * cluster for local volumes.
64 #define SV_LOCAL_TAG "local"
66 static int sv_islocal;
69 * libcfg access.
72 static CFGFILE *cfg; /* libcfg file pointer */
73 static int cfg_changed; /* set to 1 if we need to commit changes */
75 static char *cfg_cluster_tag; /* local cluster tag */
77 static char *implicit_tag; /* implicit cluster tag */
81 * Print width for print_sv() output.
84 #define STATWIDTH (SV_MAXPATH / 2)
87 * Pathnames.
90 static const caddr_t sv_rpath = SV_DEVICE;
93 * Functions.
96 static int read_config_file(const caddr_t, sv_name_t []);
97 static int enable_dev(sv_name_t *);
98 static int disable_dev(const caddr_t);
99 static void error(spcs_s_info_t *, caddr_t, ...);
100 static void create_cfg_hash();
101 static int find_in_hash(char *path);
102 static void destroy_hashtable();
103 static void remove_from_cfgfile(char *path, int setnumber);
105 static caddr_t program;
107 static void
108 sv_cfg_open(CFGLOCK mode)
110 if (cfg != NULL)
111 return;
113 cfg = cfg_open(NULL);
114 if (cfg == NULL) {
115 error(NULL, gettext("unable to access the configuration"));
116 /* NOTREACHED */
119 if (cfg_cluster_tag && *cfg_cluster_tag) {
120 cfg_resource(cfg, cfg_cluster_tag);
121 } else {
122 cfg_resource(cfg, NULL);
124 if (!cfg_lock(cfg, mode)) {
125 error(NULL, gettext("unable to lock the configuration"));
126 /* NOTREACHED */
131 static void
132 sv_cfg_close(void)
134 if (cfg == NULL)
135 return;
137 if (cfg_changed) {
138 (void) cfg_commit(cfg);
139 cfg_changed = 0;
142 cfg_close(cfg);
143 cfg = NULL;
148 static void
149 usage(void)
151 (void) fprintf(stderr, gettext("usage:\n"));
153 (void) fprintf(stderr, gettext(
154 "\t%s -h help\n"), program);
156 (void) fprintf(stderr, gettext(
157 "\t%s [-C tag] display status\n"),
158 program);
160 (void) fprintf(stderr, gettext(
161 "\t%s [-C tag] -i display "
162 "extended status\n"), program);
164 (void) fprintf(stderr, gettext(
165 "\t%s [-C tag] -v display "
166 "version number\n"), program);
168 (void) fprintf(stderr, gettext(
169 "\t%s [-C tag] -e { -f file | volume } enable\n"), program);
171 (void) fprintf(stderr, gettext(
172 "\t%s [-C tag] -d { -f file | volume } disable\n"), program);
174 (void) fprintf(stderr, gettext(
175 "\t%s [-C tag] -r { -f file | volume } reconfigure\n"), program);
177 sv_cfg_close();
180 static void
181 message(caddr_t prefix, spcs_s_info_t *status, caddr_t string, va_list ap)
183 (void) fprintf(stderr, "%s: %s: ", program, prefix);
184 (void) vfprintf(stderr, string, ap);
185 (void) fprintf(stderr, "\n");
187 if (status) {
188 spcs_s_report(*status, stderr);
189 spcs_s_ufree(status);
194 static void
195 error(spcs_s_info_t *status, caddr_t string, ...)
197 va_list ap;
198 va_start(ap, string);
200 message(gettext("error"), status, string, ap);
202 va_end(ap);
204 sv_cfg_close();
205 exit(1);
209 static void
210 warn(spcs_s_info_t *status, caddr_t string, ...)
212 va_list ap;
213 va_start(ap, string);
215 message(gettext("warning"), status, string, ap);
217 va_end(ap);
221 static void
222 sv_get_maxdevs(void)
224 sv_name_t svn[1];
225 sv_list_t svl;
226 int fd;
228 if (sv_max_devices > 0)
229 return;
231 fd = open(sv_rpath, O_RDONLY);
232 if (fd < 0)
233 error(NULL, gettext("unable to open %s: %s"),
234 sv_rpath, strerror(errno));
236 bzero(&svl, sizeof (svl));
237 bzero(&svn[0], sizeof (svn));
239 svl.svl_names = &svn[0];
240 svl.svl_error = spcs_s_ucreate();
242 if (ioctl(fd, SVIOC_LIST, &svl) < 0) {
243 (void) close(fd);
244 error(&svl.svl_error, gettext("unable to get max devs"));
247 spcs_s_ufree(&svl.svl_error);
248 sv_max_devices = svl.svl_maxdevs;
250 (void) close(fd);
254 static sv_name_t *
255 sv_alloc_svnames(void)
257 sv_name_t *svn = NULL;
259 sv_get_maxdevs();
261 svn = calloc(sv_max_devices, sizeof (*svn));
262 if (svn == NULL) {
263 error(NULL, "unable to allocate %ld bytes of memory",
264 sv_max_devices * sizeof (*svn));
267 return (svn);
271 static void
272 sv_check_dgislocal(char *dgname)
274 char *othernode;
275 int rc;
278 * check where this disk service is mastered
281 rc = cfg_dgname_islocal(dgname, &othernode);
282 if (rc < 0) {
283 error(NULL, gettext("unable to find "
284 "disk service, %s: %s"), dgname, strerror(errno));
287 if (rc == 0) {
288 error(NULL, gettext("disk service, %s, is "
289 "active on node \"%s\"\nPlease re-issue "
290 "the command on that node"), dgname, othernode);
296 * Carry out cluster based checks for a specified volume, or just
297 * global options.
299 static void
300 sv_check_cluster(char *path)
302 char dgname[CFG_MAX_BUF];
303 static int sv_iscluster = -1; /* set to 1 if running in a cluster */
306 * Find out if we are running in a cluster
308 if (sv_iscluster == -1) {
309 if ((sv_iscluster = cfg_iscluster()) < 0) {
310 error(NULL, gettext("unable to ascertain environment"));
314 if (!sv_iscluster && cfg_cluster_tag != NULL) {
315 error(NULL, gettext("-C is not valid when not in a cluster"));
318 if (!sv_iscluster || sv_islocal || path == NULL) {
319 return;
324 * Cluster-only checks on pathname
326 if (cfg_dgname(path, dgname, sizeof (dgname)) == NULL) {
327 error(NULL, gettext("unable to determine "
328 "disk group name for %s"), path);
329 return;
332 if (cfg_cluster_tag != NULL) {
334 * Do dgislocal check now in case path did not contain
335 * a dgname.
337 * E.g. adding a /dev/did/ device to a disk service.
340 sv_check_dgislocal(cfg_cluster_tag);
343 if (strcmp(dgname, "") == 0)
344 return; /* NULL dgname is valid */
346 if (cfg_cluster_tag == NULL) {
348 * Implicitly set the cluster tag to dgname
351 sv_check_dgislocal(dgname);
353 if (implicit_tag) {
354 free(implicit_tag);
355 implicit_tag = NULL;
358 implicit_tag = strdup(dgname);
359 if (implicit_tag == NULL) {
360 error(NULL,
361 gettext("unable to allocate memory "
362 "for cluster tag"));
364 } else {
366 * Check dgname and cluster tag from -C are the same.
369 if (strcmp(dgname, cfg_cluster_tag) != 0) {
370 error(NULL,
371 gettext("-C (%s) does not match disk group "
372 "name (%s) for %s"), cfg_cluster_tag,
373 dgname, path);
377 * sv_check_dgislocal(cfg_cluster_tag) was called above.
383 static void
384 print_version(void)
386 sv_version_t svv;
387 int fd;
389 bzero(&svv, sizeof (svv));
390 svv.svv_error = spcs_s_ucreate();
392 fd = open(sv_rpath, O_RDONLY);
393 if (fd < 0) {
394 warn(NULL, gettext("unable to open %s: %s"),
395 sv_rpath, strerror(errno));
396 return;
399 if (ioctl(fd, SVIOC_VERSION, &svv) != 0) {
400 error(&svv.svv_error,
401 gettext("unable to read the version number"));
402 /* NOTREACHED */
405 spcs_s_ufree(&svv.svv_error);
406 #ifdef DEBUG
407 (void) printf(gettext("Storage Volume version %d.%d.%d.%d\n"),
408 svv.svv_major_rev, svv.svv_minor_rev,
409 svv.svv_micro_rev, svv.svv_baseline_rev);
410 #else
411 if (svv.svv_micro_rev) {
412 (void) printf(gettext("Storage Volume version %d.%d.%d\n"),
413 svv.svv_major_rev, svv.svv_minor_rev, svv.svv_micro_rev);
414 } else {
415 (void) printf(gettext("Storage Volume version %d.%d\n"),
416 svv.svv_major_rev, svv.svv_minor_rev);
418 #endif
420 (void) close(fd);
424 main(int argc, char *argv[])
426 extern int optind;
427 extern char *optarg;
428 char *conf_file = NULL;
429 int enable, disable, compare, print, version;
430 int opt, Cflag, fflag, iflag;
431 int rc;
433 (void) setlocale(LC_ALL, "");
434 (void) textdomain("svadm");
436 program = strdup(basename(argv[0]));
438 Cflag = fflag = iflag = 0;
439 compare = enable = disable = version = 0;
441 print = 1;
443 while ((opt = getopt(argc, argv, "C:def:hirv")) != EOF) {
444 switch (opt) {
446 case 'C':
447 if (Cflag) {
448 warn(NULL,
449 gettext("-C specified multiple times"));
450 usage();
451 exit(2);
452 /* NOTREACHED */
455 Cflag++;
456 cfg_cluster_tag = optarg;
457 break;
459 case 'e':
460 print = 0;
461 enable++;
462 break;
464 case 'd':
465 print = 0;
466 disable++;
467 break;
469 case 'f':
470 fflag++;
471 conf_file = optarg;
472 break;
474 case 'i':
475 iflag++;
476 break;
478 case 'r':
479 /* Compare running system with sv.cf */
480 print = 0;
481 compare++;
482 break;
484 case 'v':
485 print = 0;
486 version++;
487 break;
489 case 'h':
490 usage();
491 exit(0);
493 default:
494 usage();
495 exit(2);
496 /* NOTREACHED */
502 * Usage checks
505 if ((enable + disable + compare) > 1) {
506 warn(NULL, gettext("-d, -e and -r are mutually exclusive"));
507 usage();
508 exit(2);
511 if (fflag && (print || version)) {
512 warn(NULL, gettext("-f is only valid with -d, -e or -r"));
513 usage();
514 exit(2);
517 if (fflag && optind != argc) {
518 usage();
519 exit(2);
522 if (print || version) {
523 /* check for no more args */
525 if (optind != argc) {
526 usage();
527 exit(2);
529 } else {
530 /* check for inline args */
532 if (!fflag && (argc - optind) != 1) {
533 usage();
534 exit(2);
538 if (!print && iflag) {
539 usage();
540 exit(2);
545 * Check for the special cluster tag and convert into the
546 * internal representation.
549 if (cfg_cluster_tag != NULL &&
550 strcmp(cfg_cluster_tag, SV_LOCAL_TAG) == 0) {
551 cfg_cluster_tag = "-";
552 sv_islocal = 1;
557 * Process commands
560 if (optind != argc) {
561 /* deal with inline volume argument */
563 rc = 0;
564 if (enable)
565 rc = enable_one_sv(argv[optind]);
566 else if (disable)
567 rc = disable_one_sv(argv[optind]);
568 else /* if (compare) */
569 compare_one_sv(argv[optind]);
571 if (rc != 0)
572 return (1);
574 return (0);
577 rc = 0;
578 if (enable)
579 rc = enable_sv(conf_file);
580 else if (disable)
581 rc = disable_sv(conf_file);
582 else if (compare)
583 compare_sv(conf_file);
584 else if (print)
585 print_sv(iflag);
586 else /* if (version) */
587 print_version();
589 if (rc != 0)
590 return (1);
592 return (0);
597 /* LINT - not static as fwcadm uses it */
598 static int
599 enable_sv(char *conf_file)
601 int index;
602 sv_name_t *svn;
603 int cnt;
604 int rc, ret;
606 svn = sv_alloc_svnames();
608 index = read_config_file(conf_file, svn);
610 rc = ret = 0;
612 for (cnt = 0; cnt < index; cnt++) {
615 * Check for more data.
617 if (svn[cnt].svn_path[0] == '\0') {
619 * This was set when reading sv.conf. After the last
620 * line svn_path was set to \0, so we are finished.
621 * We shouldn't get here, but put this in just in
622 * case.
624 break;
626 rc = enable_dev(&svn[cnt]);
627 if (rc && !ret)
628 ret = rc;
631 sv_cfg_close();
633 return (ret);
637 /* LINT - not static as fwcadm uses it */
638 static int
639 enable_one_sv(caddr_t path)
641 sv_name_t svn;
642 int rc;
644 sv_get_maxdevs();
646 bzero(&svn, sizeof (svn));
647 (void) strncpy(svn.svn_path, path, sizeof (svn.svn_path));
648 svn.svn_mode = (NSC_DEVICE | NSC_CACHE);
650 /* force NULL termination */
651 svn.svn_path[sizeof (svn.svn_path) - 1] = '\0';
653 rc = enable_dev(&svn);
654 sv_cfg_close();
656 return (rc);
660 static int
661 enable_dev(sv_name_t *svn)
663 char buf[CFG_MAX_BUF];
664 struct stat stb;
665 sv_conf_t svc;
666 int fd;
667 int sev;
668 int rc;
669 char *lcltag;
670 char *altname;
672 sv_check_cluster(svn->svn_path);
673 sv_cfg_open(CFG_WRLOCK);
675 bzero(&svc, sizeof (svc));
677 if (stat(svn->svn_path, &stb) != 0) {
678 warn(NULL, gettext("unable to access %s: %s"),
679 svn->svn_path, strerror(errno));
680 return (1);
683 if (!S_ISCHR(stb.st_mode)) {
684 warn(NULL, gettext("%s is not a character device - ignored"),
685 svn->svn_path);
686 return (1);
689 svc.svc_major = major(stb.st_rdev);
690 svc.svc_minor = minor(stb.st_rdev);
691 (void) strncpy(svc.svc_path, svn->svn_path, sizeof (svc.svc_path));
693 fd = open(sv_rpath, O_RDONLY);
694 if (fd < 0) {
695 warn(NULL, gettext("unable to open %s: %s"),
696 svn->svn_path, strerror(errno));
697 return (1);
700 svc.svc_flag = svn->svn_mode;
701 svc.svc_error = spcs_s_ucreate();
703 /* first, check for duplicates */
704 rc = cfg_get_canonical_name(cfg, svn->svn_path, &altname);
705 if (rc < 0) {
706 spcs_log("sv", NULL, gettext("Unable to parse config file"));
707 warn(NULL, gettext("Unable to parse config file"));
708 (void) close(fd);
709 return (1);
711 if (rc) {
712 error(NULL, gettext("'%s' has already been configured as "
713 "'%s'. Re-enter command with the latter name."),
714 svn->svn_path, altname);
717 /* secondly, try to insert it into the dsvol config */
718 if (implicit_tag && *implicit_tag) {
719 lcltag = implicit_tag;
720 } else if (cfg_cluster_tag && *cfg_cluster_tag) {
721 lcltag = cfg_cluster_tag;
722 } else {
723 lcltag = "-";
725 rc = cfg_add_user(cfg, svn->svn_path, lcltag, "sv");
726 if (CFG_USER_ERR == rc) {
727 spcs_log("sv", NULL,
728 gettext("%s: unable to put %s into dsvol cfg"),
729 program, svn->svn_path);
730 warn(NULL, gettext("unable to put %s into dsvol cfg"),
731 svn->svn_path);
732 (void) close(fd);
733 return (1);
735 cfg_changed = 1;
737 if (CFG_USER_OK == rc) {
738 /* success */
739 (void) close(fd);
740 return (0);
743 if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) {
744 if ((CFG_USER_REPEAT == rc) && (SV_EENABLED == errno)) {
745 /* it's ok -- we were just double-checking */
746 (void) close(fd);
747 return (0);
750 spcs_log("sv", &svc.svc_error,
751 gettext("%s: unable to enable %s"),
752 program, svn->svn_path);
754 warn(&svc.svc_error, gettext("unable to enable %s"),
755 svn->svn_path);
757 /* remove it from dsvol, if we're the ones who put it in */
758 if (CFG_USER_FIRST == rc) {
759 (void) cfg_rem_user(cfg, svn->svn_path, lcltag, "sv");
761 (void) close(fd);
762 return (1);
765 spcs_log("sv", NULL, gettext("%s: enabled %s"),
766 program, svn->svn_path);
768 if (implicit_tag != NULL) {
769 #ifdef DEBUG
770 if (cfg_cluster_tag != NULL) {
771 error(NULL,
772 gettext("enable_dev: -C %s AND implicit_tag %s!"),
773 cfg_cluster_tag, implicit_tag);
775 #endif
777 (void) snprintf(buf, sizeof (buf), "%s - %s",
778 svc.svc_path, implicit_tag);
779 } else {
780 (void) strcpy(buf, svc.svc_path);
783 rc = 0;
784 if (cfg_put_cstring(cfg, "sv", buf, sizeof (buf)) < 0) {
785 warn(NULL,
786 gettext("unable to add %s to configuration storage: %s"),
787 svc.svc_path, cfg_error(&sev));
788 rc = 1;
791 cfg_changed = 1;
792 spcs_s_ufree(&svc.svc_error);
793 (void) close(fd);
795 return (rc);
800 * This routine parses the config file passed in via conf_file and
801 * stores the data in the svn array. The return value is the number
802 * of entries read from conf_file. If an error occurs the error()
803 * routine is called (which exits the program).
805 static int
806 read_config_file(const caddr_t conf_file, sv_name_t svn[])
808 char line[1024], rdev[1024], junk[1024];
809 struct stat stb;
810 int lineno;
811 int cnt, i;
812 int index = 0; /* Current location in svn array */
813 sv_name_t *cur_svn; /* Pointer to svn[index] */
814 FILE *fp;
816 if (access(conf_file, R_OK) != 0 ||
817 stat(conf_file, &stb) != 0 ||
818 !S_ISREG(stb.st_mode)) {
819 error(NULL, gettext("cannot read config file %s"), conf_file);
822 if ((fp = fopen(conf_file, "r")) == NULL) {
823 error(NULL, gettext("unable to open config file %s: %s"),
824 conf_file, strerror(errno));
827 lineno = 0;
829 while (fgets(line, sizeof (line), fp) != NULL) {
830 lineno++;
832 i = strlen(line);
834 if (i < 1)
835 continue;
837 if (line[i-1] == '\n')
838 line[i-1] = '\0';
839 else if (i == (sizeof (line) - 1)) {
840 warn(NULL, gettext(
841 "line %d: line too long -- should be less than %d characters"),
842 lineno, (sizeof (line) - 1));
843 warn(NULL, gettext("line %d: ignored"), lineno);
847 * check for comment line.
849 if (line[0] == '#')
850 continue;
852 cnt = sscanf(line, "%s %s", rdev, junk);
854 if (cnt != 1 && cnt != 2) {
855 if (cnt > 0) {
856 warn(NULL, gettext("line %d: invalid format"),
857 lineno);
858 warn(NULL, gettext("line %d: ignored"), lineno);
860 continue;
863 rdev[sizeof (rdev) - 1] = '\0';
865 cur_svn = &svn[index]; /* For easier reading below */
867 if (strlen(rdev) >= sizeof (cur_svn->svn_path)) {
868 warn(NULL, gettext(
869 "line %d: raw device name (%s) longer than %d characters"),
870 lineno, rdev,
871 (sizeof (cur_svn->svn_path) - 1));
872 warn(NULL, gettext("line %d: ignored"), lineno);
873 continue;
876 (void) strcpy(cur_svn->svn_path, rdev);
877 cur_svn->svn_mode = (NSC_DEVICE | NSC_CACHE);
879 index++;
882 /* Set the last path to NULL */
883 svn[index].svn_path[0] = '\0';
885 (void) fclose(fp);
887 return (index);
892 * Disable the device from the kernel configuration.
894 * RETURN:
895 * 0 on success
896 * non-zero on failure.
898 * Failures are reported to the user.
900 static int
901 disable_dev(const caddr_t path)
903 struct stat stb;
904 sv_conf_t svc;
905 int fd;
907 sv_check_cluster(path);
909 if (stat(path, &stb) < 0) {
910 svc.svc_major = (major_t)-1;
911 svc.svc_minor = (minor_t)-1;
912 } else {
913 svc.svc_major = major(stb.st_rdev);
914 svc.svc_minor = minor(stb.st_rdev);
917 if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
918 warn(NULL, gettext("unable to open %s: %s"),
919 sv_rpath, strerror(errno));
920 return (-1);
923 (void) strcpy(svc.svc_path, path);
924 svc.svc_error = spcs_s_ucreate();
927 * Issue the ioctl to attempt to disable this device. Note that all
928 * the libdscfg details are handled elsewhere.
930 if (ioctl(fd, SVIOC_DISABLE, &svc) < 0) {
931 if (errno != SV_EDISABLED) {
932 spcs_log("sv", &svc.svc_error,
933 gettext("%s: unable to disable %s"),
934 program, path);
936 warn(&svc.svc_error,
937 gettext("unable to disable %s"), path);
938 (void) close(fd);
939 return (-1);
943 spcs_log("sv", NULL, gettext("%s: disabled %s"), program, path);
945 spcs_s_ufree(&svc.svc_error);
946 (void) close(fd);
948 return (0);
952 static void
953 print_cluster_tag(const int setnumber)
955 char buf[CFG_MAX_BUF];
956 char key[CFG_MAX_KEY];
958 bzero(buf, sizeof (buf));
959 (void) snprintf(key, sizeof (key), "sv.set%d.cnode", setnumber);
961 (void) cfg_get_cstring(cfg, key, buf, sizeof (buf));
963 if (*buf != '\0') {
964 if (strcmp(buf, "-") == 0) {
965 (void) printf(" [%s]", gettext("local to node"));
966 } else {
967 (void) printf(" [%s: %s]", gettext("cluster"), buf);
973 /* LINT - not static as fwcadm uses it */
974 static void
975 print_sv(int verbose)
977 sv_name_t *svn, *svn_system; /* Devices in system */
978 sv_list_t svl_system;
979 int fd, i;
980 int setnumber;
982 sv_check_cluster(NULL);
983 sv_cfg_open(CFG_RDLOCK);
985 svn_system = sv_alloc_svnames();
987 if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
988 (void) printf(gettext("unable to open %s: %s"),
989 sv_rpath, strerror(errno));
990 return;
993 /* Grab the system list from the driver */
994 svl_system.svl_count = sv_max_devices;
995 svl_system.svl_names = &svn_system[0];
996 svl_system.svl_error = spcs_s_ucreate();
998 if (ioctl(fd, SVIOC_LIST, &svl_system) < 0) {
999 error(&svl_system.svl_error, gettext("unable to get list"));
1002 spcs_s_ufree(&svl_system.svl_error);
1003 (void) close(fd);
1006 * We build a hashmap out of the entries from the config file to make
1007 * searching faster. We end up taking a performance hit when the # of
1008 * volumes is small, but for larger configurations it's a
1009 * HUGE improvement.
1012 /* build the hashtable */
1013 cfg_rewind(cfg, CFG_SEC_CONF);
1014 create_cfg_hash();
1017 * For each volume found from the kernel, print out
1018 * info about it from the kernel.
1020 for (i = 0; i < svl_system.svl_count; i++) {
1021 if (*svn_system[i].svn_path == '\0') {
1022 break;
1025 svn = &svn_system[i];
1026 if (svn->svn_mode == 0) {
1027 #ifdef DEBUG
1028 (void) printf(gettext("%s [kernel guard]\n"),
1029 svn->svn_path);
1030 #endif
1031 continue;
1033 /* get sv entry from the hashtable */
1034 if ((setnumber = find_in_hash(svn->svn_path)) != -1) {
1035 (void) printf("%-*s", STATWIDTH, svn->svn_path);
1037 if (verbose) {
1038 print_cluster_tag(setnumber);
1041 (void) printf("\n");
1043 } else {
1045 * We didn't find the entry in the hashtable. Let
1046 * the user know that the persistent storage is
1047 * inconsistent with the kernel configuration.
1049 if (cfg_cluster_tag == NULL)
1050 warn(NULL, gettext(
1051 "%s is configured, but not in the "
1052 "config storage"), svn->svn_path);
1056 /* free up the hashtable */
1057 destroy_hashtable();
1059 sv_cfg_close();
1063 /* LINT - not static as fwcadm uses it */
1064 static int
1065 disable_sv(char *conf_file)
1067 sv_name_t *svn, *svn_system; /* Devices in system */
1068 sv_list_t svl_system;
1069 int fd, i, setnumber;
1070 int rc, ret;
1072 svn_system = sv_alloc_svnames();
1074 rc = ret = 0;
1076 if (conf_file == NULL) {
1077 if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
1078 (void) printf(gettext("unable to open %s: %s"),
1079 sv_rpath, strerror(errno));
1080 return (1);
1083 /* Grab the system list from the driver */
1084 svl_system.svl_count = sv_max_devices;
1085 svl_system.svl_names = &svn_system[0];
1086 svl_system.svl_error = spcs_s_ucreate();
1088 if (ioctl(fd, SVIOC_LIST, &svl_system) < 0) {
1089 error(&(svl_system.svl_error),
1090 gettext("unable to get list"));
1093 spcs_s_ufree(&(svl_system.svl_error));
1094 (void) close(fd);
1095 } else {
1096 svl_system.svl_count = read_config_file(conf_file, svn_system);
1100 for (i = 0; i < svl_system.svl_count; i++) {
1101 if (*svn_system[i].svn_path == '\0')
1102 break;
1104 svn = &svn_system[i];
1106 sv_check_cluster(svn->svn_path);
1107 sv_cfg_open(CFG_WRLOCK);
1108 create_cfg_hash();
1109 rc = 0;
1110 if ((setnumber = find_in_hash(svn->svn_path)) != -1) {
1111 if ((rc = disable_dev(svn->svn_path)) != -1) {
1112 remove_from_cfgfile(svn->svn_path, setnumber);
1113 } else if (errno == SV_ENODEV) {
1114 remove_from_cfgfile(svn->svn_path, setnumber);
1116 } else {
1117 /* warn the user that we didn't find it in cfg file */
1118 warn(NULL, gettext(
1119 "%s was not found in the config storage"),
1120 svn->svn_path);
1121 /* try to disable anyway */
1122 (void) disable_dev(svn->svn_path);
1123 rc = 1;
1126 sv_cfg_close();
1127 destroy_hashtable();
1129 if (rc && !ret)
1130 ret = rc;
1133 return (ret);
1137 /* LINT - not static as fwcadm uses it */
1138 static int
1139 disable_one_sv(char *path)
1141 int setnumber;
1142 int rc;
1144 sv_get_maxdevs();
1145 sv_check_cluster(path);
1146 sv_cfg_open(CFG_WRLOCK);
1148 create_cfg_hash();
1149 if ((setnumber = find_in_hash(path)) != -1) {
1150 /* remove from kernel */
1151 if ((rc = disable_dev(path)) == 0) {
1152 /* remove the cfgline */
1153 remove_from_cfgfile(path, setnumber);
1154 } else if (errno == SV_ENODEV) {
1155 remove_from_cfgfile(path, setnumber);
1157 } else {
1158 /* warn the user that we didn't find it in cfg file */
1159 warn(NULL,
1160 gettext("%s was not found in the config storage"), path);
1161 /* still attempt to remove */
1162 (void) disable_dev(path);
1163 rc = 1;
1165 destroy_hashtable();
1167 sv_cfg_close();
1168 return (rc);
1172 static void
1173 compare_tag(char *path)
1175 char buf[CFG_MAX_BUF], vol[CFG_MAX_BUF], cnode[CFG_MAX_BUF];
1176 char key[CFG_MAX_KEY];
1177 int found, setnumber, i;
1178 char *tag;
1180 sv_check_cluster(path);
1181 cfg_resource(cfg, (char *)NULL); /* reset */
1182 cfg_rewind(cfg, CFG_SEC_CONF);
1184 #ifdef DEBUG
1185 if (cfg_cluster_tag != NULL && implicit_tag != NULL) {
1186 error(NULL, gettext("compare_tag: -C %s AND implicit_tag %s!"),
1187 cfg_cluster_tag, implicit_tag);
1189 #endif
1191 if (cfg_cluster_tag != NULL)
1192 tag = cfg_cluster_tag;
1193 else if (implicit_tag != NULL)
1194 tag = implicit_tag;
1195 else
1196 tag = "-";
1198 found = 0;
1199 for (i = 0; i < sv_max_devices; i++) {
1200 setnumber = i + 1;
1201 (void) snprintf(key, sizeof (key), "sv.set%d", setnumber);
1202 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) {
1203 break;
1206 if (sscanf(buf, "%s - %s", vol, cnode) != 2) {
1207 continue;
1210 if (strcmp(path, vol) == 0) {
1211 found = 1;
1212 break;
1216 if (!found) {
1217 warn(NULL, gettext("unable to find %s in the configuration"),
1218 path);
1219 return;
1222 /* have name match, compare cnode to new tag */
1224 if (strcmp(tag, cnode) == 0) {
1225 /* cluster tags match */
1226 return;
1229 /* need to change the cluster tag */
1231 (void) snprintf(key, sizeof (key), "sv.set%d.cnode", setnumber);
1232 if (cfg_put_cstring(cfg, key, tag, strlen(tag)) < 0) {
1233 warn(NULL,
1234 gettext("unable to change cluster tag for %s"), path);
1235 return;
1238 cfg_changed = 1;
1240 /* change "-" tags to "" for display purposes */
1242 if (strcmp(tag, "-") == 0)
1243 tag = "";
1245 if (strcmp(cnode, "-") == 0)
1246 (void) strcpy(cnode, "");
1248 (void) printf(
1249 gettext("%s: changed cluster tag for %s from \"%s\" to \"%s\"\n"),
1250 program, path, cnode, tag);
1252 spcs_log("sv", NULL,
1253 gettext("%s: changed cluster tag for %s from \"%s\" to \"%s\""),
1254 program, path, cnode, tag);
1258 /* LINT - not static as fwcadm uses it */
1259 static void
1260 compare_sv(char *conf_file)
1262 sv_name_t *svn_config; /* Devices in config file */
1263 sv_name_t *svn_system; /* Devices in system */
1264 sv_name_t *enable; /* Devices that need enabled */
1265 sv_list_t svl_system;
1266 int config_cnt;
1267 int sys_cnt = 0;
1268 int setnumber, i, j;
1269 int index = 0; /* Index in enable[] */
1270 int found;
1271 int fd0;
1273 svn_config = sv_alloc_svnames();
1274 svn_system = sv_alloc_svnames();
1275 enable = sv_alloc_svnames();
1277 bzero(svn_system, sizeof (svn_system));
1278 bzero(&svl_system, sizeof (svl_system));
1279 bzero(enable, sizeof (enable));
1282 * Read the configuration file
1283 * The return value is the number of entries
1285 config_cnt = read_config_file(conf_file, svn_config);
1287 if ((fd0 = open(sv_rpath, O_RDONLY)) < 0)
1288 error(NULL, gettext("unable to open %s: %s"),
1289 sv_rpath, strerror(errno));
1291 /* Grab the system list from the driver */
1292 svl_system.svl_count = sv_max_devices;
1293 svl_system.svl_names = &svn_system[0];
1294 svl_system.svl_error = spcs_s_ucreate();
1296 if (ioctl(fd0, SVIOC_LIST, &svl_system) < 0) {
1297 error(&svl_system.svl_error, gettext("unable to get list"));
1300 spcs_s_ufree(&svl_system.svl_error);
1301 (void) close(fd0);
1304 * Count the number of devices in the system.
1305 * The last entry in the array has '\0' for a path name.
1307 for (j = 0; j < sv_max_devices; j++) {
1308 if (svn_system[j].svn_path[0] != '\0') {
1309 sys_cnt++;
1310 } else {
1311 break;
1315 * Compare the configuration array with the system array.
1316 * Mark any differences and disable conflicting devices.
1318 for (i = 0; i < config_cnt; i++) {
1319 found = 0;
1320 for (j = 0; j < sys_cnt; j++) {
1321 if (svn_system[j].svn_path[0] == '\0' ||
1322 svn_system[j].svn_mode == 0)
1323 continue;
1325 /* Check to see if path matches */
1326 if (strcmp(svn_system[j].svn_path,
1327 svn_config[i].svn_path) == 0) {
1328 /* Found a match */
1329 svn_system[j].svn_path[0] = '\0';
1330 found++;
1331 break;
1335 if (!found) {
1336 /* Minor number not in system = > enable device */
1337 enable[index].svn_mode = svn_config[i].svn_mode;
1338 (void) strcpy(enable[index].svn_path,
1339 svn_config[i].svn_path);
1340 index++;
1344 /* Disable any devices that weren't in the config file */
1345 for (j = 0; j < sys_cnt; j++) {
1346 sv_check_cluster(NULL);
1347 sv_cfg_open(CFG_WRLOCK);
1348 create_cfg_hash();
1349 if (svn_system[j].svn_path[0] != '\0' &&
1350 svn_system[j].svn_mode != 0) {
1351 (void) printf(gettext("%s: disabling sv: %s\n"),
1352 program, svn_system[j].svn_path);
1353 if (disable_dev(svn_system[j].svn_path) == 0) {
1354 setnumber =
1355 find_in_hash(svn_system[j].svn_path);
1356 if (setnumber != -1) {
1357 /* the volume was found in cfg store */
1358 remove_from_cfgfile(
1359 svn_system[j].svn_path, setnumber);
1363 sv_cfg_close();
1364 destroy_hashtable();
1367 while (index) {
1369 * Config file doesn't match system => enable the devices
1370 * in enable[]
1372 index--;
1373 (void) printf(gettext("%s: enabling new sv: %s\n"),
1374 program, enable[index].svn_path);
1375 (void) enable_dev(&enable[index]);
1379 * Search for entries where the cluster tag has changed.
1381 sv_check_cluster(NULL);
1382 sv_cfg_open(CFG_WRLOCK);
1384 for (i = 0; i < sv_max_devices; i++) {
1385 if (svn_config[i].svn_path[0] == '\0')
1386 break;
1388 compare_tag(svn_config[i].svn_path);
1391 sv_cfg_close();
1396 * We assume that the volume is already enabled and we can only
1397 * be changing the cluster tag. Anything else is an error.
1399 /* LINT - not static as fwcadm uses it */
1400 static void
1401 compare_one_sv(char *path)
1403 sv_get_maxdevs();
1404 sv_check_cluster(NULL);
1405 sv_cfg_open(CFG_WRLOCK);
1407 compare_tag(path);
1409 sv_cfg_close();
1413 * Read all sets from the libdscfg configuration file, and store everything in
1414 * the hashfile.
1416 * We assume that the config file has been opened & rewound for us. We store
1417 * the volume name as the key, and the setnumber where we found it as the data.
1419 * The caller can pass in a pointer to the maximum number of volumes, or
1420 * a pointer to NULL, specifying we want 'all' the volumes. The table is
1421 * searched using find_in_hash.
1423 static void
1424 create_cfg_hash()
1426 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
1427 char vol[CFG_MAX_BUF], cnode[CFG_MAX_BUF];
1428 int setnumber;
1429 ENTRY item;
1431 if (hcreate((size_t)sv_max_devices) == 0)
1432 error(NULL, gettext("unable to create hash table"));
1434 for (setnumber = 1; /* CSTYLED */; setnumber++) {
1435 (void) snprintf(key, sizeof (key), "sv.set%d", setnumber);
1436 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
1437 break;
1439 if (sscanf(buf, "%s - %s", vol, cnode) != 2) {
1440 continue;
1443 item.key = strdup(vol);
1444 item.data = (void *)setnumber;
1445 if (hsearch(item, ENTER) == NULL) {
1446 error(NULL,
1447 gettext("unable to add entry to hash table"));
1453 * Function to search the hash for a specific volume. If it is found,
1454 * we return the set number. If it isn't found, we return -1
1456 static int
1457 find_in_hash(char *path)
1459 ENTRY *found_entry, item;
1460 int retval = -1;
1462 item.key = path;
1464 if ((found_entry = hsearch(item, FIND)) != NULL) {
1465 retval = (int)found_entry->data;
1468 return (retval);
1472 * Just a wrapper to destory the hashtable. At some point in the future we
1473 * might want to do something more.... For instance, verify that the cfg
1474 * database and the kernel configuration match (?) Just an idea.
1476 static void
1477 destroy_hashtable()
1479 hdestroy();
1483 * This function will remove a particular set from the config file.
1485 * We make a whole host of assumptions:
1486 * o the hashfile is up to date;
1487 * o The config file has been opened with a WRLOCK for us.
1489 static void
1490 remove_from_cfgfile(char *path, int setnumber)
1492 char key[CFG_MAX_KEY];
1493 int sev;
1494 char *lcltag;
1496 /* attempt to remove the volume from config storage */
1497 (void) snprintf(key, sizeof (key), "sv.set%d", setnumber);
1498 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
1499 warn(NULL, gettext("unable to remove %s from "
1500 "config storage: %s"), path, cfg_error(&sev));
1501 } else {
1502 if (implicit_tag && *implicit_tag) {
1503 lcltag = implicit_tag;
1504 } else if (cfg_cluster_tag && *cfg_cluster_tag) {
1505 lcltag = cfg_cluster_tag;
1506 } else {
1507 lcltag = "-";
1509 if (cfg_rem_user(cfg, path, lcltag, "sv") != CFG_USER_LAST) {
1510 warn(NULL, gettext("unable to remove %s from dsvol"),
1511 path);
1513 cfg_changed = 1;