8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / avs / sv / svboot.c
blobccee741c1f6fbb961708c9a0d9ee14776c883ee4
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 <fcntl.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <locale.h>
37 #include <unistd.h>
38 #include <libgen.h>
39 #include <nsctl.h>
41 #include <sys/unistat/spcs_s.h>
42 #include <sys/unistat/spcs_s_u.h>
43 #include <sys/unistat/spcs_errors.h>
45 #include <sys/nsctl/sv.h>
46 #include <sys/nsctl/sv_impl.h>
48 #include <sys/nsctl/cfg.h>
51 static int sv_max_devices;
55 * Pathnames.
58 static const caddr_t sv_rpath = SV_DEVICE;
61 * Functions.
64 static void resume_dev(int, sv_name_t *);
65 static void suspend_dev(int, const caddr_t);
66 static int read_libcfg(sv_name_t svn[]);
67 static void resume_sv();
68 static void suspend_sv();
69 static void prepare_unload_sv();
73 * support for the special cluster tag "local" to be used with -C in a
74 * cluster for local volumes.
77 #define SV_LOCAL_TAG "local"
79 static caddr_t program;
80 static caddr_t cfg_cluster_tag;
83 static void
84 usage(void)
86 (void) fprintf(stderr, gettext("usage:\n"));
88 (void) fprintf(stderr, gettext(
89 "\t%s -h help\n"), program);
91 (void) fprintf(stderr, gettext(
92 "\t%s [-C tag] -r resume all sv devices\n"), program);
94 (void) fprintf(stderr, gettext(
95 "\t%s [-C tag] -s suspend all sv devices\n"), program);
97 (void) fprintf(stderr, gettext(
98 "\t%s -u prepare for sv unload\n"), program);
102 static void
103 message(caddr_t prefix, spcs_s_info_t *status, caddr_t string, va_list ap)
105 (void) fprintf(stderr, "%s: %s: ", program, prefix);
106 (void) vfprintf(stderr, string, ap);
107 (void) fprintf(stderr, "\n");
109 if (status) {
110 spcs_s_report(*status, stderr);
111 spcs_s_ufree(status);
116 static void
117 error(spcs_s_info_t *status, caddr_t string, ...)
119 va_list ap;
120 va_start(ap, string);
122 message(gettext("error"), status, string, ap);
124 va_end(ap);
125 exit(1);
129 static void
130 warn(spcs_s_info_t *status, caddr_t string, ...)
132 va_list ap;
133 va_start(ap, string);
135 message(gettext("warning"), status, string, ap);
137 va_end(ap);
141 static void
142 sv_get_maxdevs(void)
144 sv_name_t svn[1];
145 sv_list_t svl;
146 int fd;
148 if (sv_max_devices > 0)
149 return;
151 fd = open(sv_rpath, O_RDONLY);
152 if (fd < 0)
153 error(NULL, gettext("unable to open %s: %s"),
154 sv_rpath, strerror(errno));
156 bzero(&svl, sizeof (svl));
157 bzero(&svn[0], sizeof (svn));
159 svl.svl_names = &svn[0];
160 svl.svl_error = spcs_s_ucreate();
162 if (ioctl(fd, SVIOC_LIST, &svl) < 0)
163 error(&svl.svl_error, gettext("unable to get max devs"));
165 spcs_s_ufree(&svl.svl_error);
166 sv_max_devices = svl.svl_maxdevs;
168 (void) close(fd);
172 static sv_name_t *
173 sv_alloc_svnames(void)
175 sv_name_t *svn = NULL;
177 sv_get_maxdevs();
179 svn = calloc(sv_max_devices, sizeof (*svn));
180 if (svn == NULL) {
181 error(NULL, "unable to allocate %ld bytes of memory",
182 sv_max_devices * sizeof (*svn));
185 return (svn);
189 main(int argc, char *argv[])
191 extern int optind;
192 extern char *optarg;
193 int Cflag, resume, suspend, unload;
194 int opt;
196 (void) setlocale(LC_ALL, "");
197 (void) textdomain("svboot");
199 program = strdup(basename(argv[0]));
201 Cflag = unload = resume = suspend = 0;
203 while ((opt = getopt(argc, argv, "C:hrsu")) != EOF) {
204 switch (opt) {
206 case 'C':
207 if (Cflag) {
208 warn(NULL,
209 gettext("-C specified multiple times"));
210 usage();
211 exit(2);
212 /* NOTREACHED */
215 Cflag++;
216 cfg_cluster_tag = optarg;
217 break;
219 case 'r':
220 resume++;
221 break;
223 case 's':
224 suspend++;
225 break;
227 case 'u':
228 unload++;
229 break;
231 case 'h':
232 usage();
233 exit(0);
235 case '?': /* FALLTHRU */
237 default:
238 usage();
239 exit(2);
240 /* NOTREACHED */
246 * Usage checks
249 if ((resume + suspend + unload) > 1) {
250 warn(NULL, gettext("-r , -s and -u are mutually exclusive"));
251 usage();
252 exit(2);
255 if (!resume && !suspend && !unload) {
256 warn(NULL, gettext("option required"));
257 usage();
258 exit(2);
261 if (optind != argc) {
262 usage();
263 exit(2);
268 * Check for the special (local) cluster tag
271 if (cfg_cluster_tag != NULL &&
272 strcmp(cfg_cluster_tag, SV_LOCAL_TAG) == 0)
273 cfg_cluster_tag = "-";
276 * Process commands
279 if (resume)
280 resume_sv();
281 else if (suspend)
282 suspend_sv();
283 else if (unload)
284 prepare_unload_sv();
286 return (0);
290 static void
291 resume_sv()
293 int index;
294 sv_name_t *svn;
295 int cnt;
296 int fd;
298 svn = sv_alloc_svnames();
300 index = read_libcfg(svn);
302 fd = open(sv_rpath, O_RDONLY);
303 if (fd < 0) {
304 warn(NULL, gettext("unable to open %s: %s"),
305 svn->svn_path, strerror(errno));
306 return;
309 for (cnt = 0; cnt < index; cnt++) {
312 * Check for more data.
314 if (svn[cnt].svn_path[0] == '\0') {
316 * This was set when reading sv.conf. After the last
317 * line svn_path was set to \0, so we are finished.
318 * We shouldn't get here, but put this in just in
319 * case.
321 break;
323 resume_dev(fd, &svn[cnt]);
325 (void) close(fd);
329 static void
330 resume_dev(int fd, sv_name_t *svn)
332 struct stat stb;
333 sv_conf_t svc;
335 bzero(&svc, sizeof (svc));
337 if (stat(svn->svn_path, &stb) != 0) {
338 warn(NULL, gettext("unable to access %s: %s"),
339 svn->svn_path, strerror(errno));
340 return;
343 svc.svc_major = major(stb.st_rdev);
344 svc.svc_minor = minor(stb.st_rdev);
345 (void) strncpy(svc.svc_path, svn->svn_path, sizeof (svc.svc_path));
347 svc.svc_flag = svn->svn_mode;
348 svc.svc_error = spcs_s_ucreate();
350 if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) {
351 spcs_log("sv", &svc.svc_error,
352 gettext("%s: unable to resume %s"),
353 program, svn->svn_path);
355 warn(&svc.svc_error, gettext("unable to resume %s"),
356 svn->svn_path);
357 return;
360 spcs_log("sv", NULL, gettext("%s: resume %s"),
361 program, svn->svn_path);
363 spcs_s_ufree(&svc.svc_error);
368 * This routine parses the config file and
369 * stores the data in the svn array. The return value is the number
370 * of entries read from conf_file. If an error occurs the error()
371 * routine is called (which exits the program).
373 static int
374 read_libcfg(sv_name_t svn[])
376 char rdev[CFG_MAX_BUF];
377 char key[CFG_MAX_KEY];
378 struct stat stb;
379 int i;
380 int setnumber;
381 int index = 0; /* Current location in svn array */
382 sv_name_t *cur_svn; /* Pointer to svn[index] */
383 CFGFILE *cfg;
385 if ((cfg = cfg_open("")) == NULL) {
386 error(NULL, gettext("Error opening config: %s"),
387 strerror(errno));
390 cfg_resource(cfg, cfg_cluster_tag);
391 if (!cfg_lock(cfg, CFG_RDLOCK)) {
392 error(NULL, gettext("Error locking config: %s"),
393 strerror(errno));
396 for (i = 0; /*CSTYLED*/; i++) {
397 setnumber = i + 1;
399 bzero(rdev, CFG_MAX_BUF);
400 (void) snprintf(key, sizeof (key), "sv.set%d.vol", setnumber);
401 if (cfg_get_cstring(cfg, key, rdev, sizeof (rdev)) < 0)
402 break;
404 /* Check to see if the raw device is present */
405 if (stat(rdev, &stb) != 0) {
406 warn(NULL, gettext("unable to access %s: %s"),
407 rdev, strerror(errno));
408 continue;
411 if (!S_ISCHR(stb.st_mode)) {
412 warn(NULL, gettext("%s is not a character device"),
413 rdev);
414 continue;
417 cur_svn = &svn[index]; /* For easier reading below */
419 if (strlen(rdev) >= sizeof (cur_svn->svn_path)) {
420 warn(NULL, gettext(
421 "raw device name (%s) longer than %d characters"),
422 rdev,
423 (sizeof (cur_svn->svn_path) - 1));
424 continue;
427 (void) strcpy(cur_svn->svn_path, rdev);
428 cur_svn->svn_mode = (NSC_DEVICE | NSC_CACHE);
430 index++;
433 cfg_close(cfg);
435 /* Set the last path to NULL */
436 svn[index].svn_path[0] = '\0';
438 return (index);
442 static void
443 suspend_dev(int fd, const caddr_t path)
445 struct stat stb;
446 sv_conf_t svc;
448 if (stat(path, &stb) < 0) {
449 svc.svc_major = (major_t)-1;
450 svc.svc_minor = (minor_t)-1;
451 } else {
452 svc.svc_major = major(stb.st_rdev);
453 svc.svc_minor = minor(stb.st_rdev);
456 (void) strcpy(svc.svc_path, path);
457 svc.svc_error = spcs_s_ucreate();
459 if (ioctl(fd, SVIOC_DISABLE, &svc) < 0) {
460 if (errno != SV_EDISABLED) {
461 spcs_log("sv", &svc.svc_error,
462 gettext("%s: unable to suspend %s"),
463 program, path);
465 warn(&svc.svc_error,
466 gettext("unable to suspend %s"), path);
467 return;
471 spcs_log("sv", NULL, gettext("%s: suspend %s"), program, path);
473 spcs_s_ufree(&svc.svc_error);
477 static void
478 suspend_sv(void)
480 sv_name_t *svn, *svn_system; /* Devices in system */
481 sv_list_t svl_system;
482 int i;
483 int fd;
485 svn_system = sv_alloc_svnames();
487 svl_system.svl_count = read_libcfg(svn_system);
489 if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
490 warn(NULL, gettext("unable to open %s: %s"),
491 sv_rpath, strerror(errno));
492 return;
495 for (i = 0; i < svl_system.svl_count; i++) {
496 if (*svn_system[i].svn_path == '\0')
497 break;
499 svn = &svn_system[i];
500 suspend_dev(fd, svn->svn_path);
503 (void) close(fd);
508 * Check kernel's sv_ndevices and thread sets,
509 * if empty then change kernel state to allow unload,
510 * and sleep SV_WAIT_UNLAOD (10 seconds).
512 * Only called in pkgrm time.
514 static void
515 prepare_unload_sv(void)
517 int fd;
518 int rc = 0;
520 if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
521 warn(NULL, gettext("unable to open %s: %s"),
522 sv_rpath, strerror(errno));
523 return;
526 if (ioctl(fd, SVIOC_UNLOAD, &rc) < 0)
527 error(NULL, gettext("unable to unload"));
529 if (rc != 0)
530 error(NULL, gettext("still has active devices or threads"));
532 (void) close(fd);