Merge commit 'ad3ad82ad2fb99c424a8482bd1908d08b990ccea'
[unleashed.git] / usr / src / cmd / fs.d / fssnapsup.c
blob354d6bab272bd20a03f4fb60c42bd279cbcfbd80
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Routines to support fssnap subcommand of switchout. See switchout.c for
31 * the real fssnap command.
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <kstat.h>
37 #include <libintl.h>
38 #include <sys/fssnap_if.h>
39 #include <string.h>
40 #include <errno.h>
42 static void fssnap_display_info(ulong_t, int *, int);
44 #define MAX_INFO_DESCRIPTORS (10)
46 static char *infosubopts[] = {
47 #define INFO_SNAPSHOT (0)
48 "snapnumber",
49 #define INFO_BLKDEV (1)
50 "blockdevname",
51 #define INFO_CHARDEV (2)
52 "rawdevname",
53 #define INFO_MNTPT (3)
54 "mountpoint",
55 #define INFO_STATE (4)
56 "state",
57 #define INFO_BACKPATH (5)
58 "backing-store",
59 #define INFO_BACKSIZE (6)
60 "backing-store-len",
61 #define INFO_MAXSIZE (7)
62 "maxsize",
63 #define INFO_CREATETIME (8)
64 "createtime",
65 #define INFO_CHUNKSIZE (9)
66 "chunksize",
67 NULL
70 #define BLOCK_PATH "/dev/" SNAP_BLOCK_NAME "/"
71 #define CHAR_PATH "/dev/" SNAP_CHAR_NAME "/"
73 /* labels are truncated to this many characters when displayed */
74 #define MAX_LABEL_LEN (30)
77 * fssnap_show_status() - display file system snapshot status
79 * displays snapshot information. If mountpoint is set, information is
80 * only displayed for the snapshot (if one exists) on that file system.
81 * If mountpoint is NULL, information is displayed for all snapshots.
83 * If opts is defined, it is parsed as a list of suboptions (via
84 * getsubopt()) corresponding to the options list defined above. These
85 * options determine what data should be displayed and in what order. An
86 * option may appear more than once.
88 * The labels parameter is a boolean that determines whether labels
89 * (internationalized) are displayed before each data element. If it is
90 * 0, labels are not displayed, otherwise they are. The labels parameter
91 * is ignored if brief is nonzero.
93 * The brief parameter is also a boolean and specifies a mode where only
94 * the snapshot number and mount point are displayed, regardless of the
95 * value of labels. This could be used for listing all active snapshots.
97 * Based on these parameters, an order list is created that tells
98 * fssnap_display_info() what info to display and in what order.
100 * Note that when labels are not specified, the assumption is that the
101 * output is made for script readable consumption. For this reason, text
102 * is not I18N'd and numbers are left as bytes instead of converted to KB.
104 void
105 fssnap_show_status(char *mountpoint, char *opts, int labels, int brief)
107 int *order, orderlen = MAX_INFO_DESCRIPTORS+1;
108 kstat_ctl_t *kslib;
109 kstat_t *mnt;
110 kstat_t *kshigh;
111 kstat_named_t *highp;
112 char *suboptions, *v, *n;
113 int i = 0;
114 int num, usenum = 0;
116 kslib = kstat_open();
117 kshigh = kstat_lookup(kslib, SNAP_NAME, 0, FSSNAP_KSTAT_HIGHWATER);
120 * First check and see if they gave us a mount point or a device
121 * name (ie /dev/fssnap/X or /dev/rfssnap/X).
123 if (mountpoint) {
124 if (strncmp(BLOCK_PATH, mountpoint, strlen(BLOCK_PATH)) == 0 ||
125 strncmp(CHAR_PATH, mountpoint, strlen(CHAR_PATH)) == 0) {
126 n = strrchr(mountpoint, '/');
127 n++;
128 if (isdigit(*n)) {
129 errno = 0;
130 num = (int)strtol(n, NULL, 10);
131 if (errno == 0) {
132 usenum++;
138 if (opts) {
139 i = 0;
140 order = (int *)malloc(orderlen * sizeof (int));
141 if (order == NULL) {
142 fprintf(stderr,
143 gettext("cannot allocate order list.\n"));
144 return;
146 suboptions = opts;
147 while (*suboptions != '\0') {
149 * -1 means invalid option, MAX_INFO_DESCRIPTORS is
150 * the end.
152 order[i++] = getsubopt(&suboptions, infosubopts, &v);
153 if (i >= orderlen) {
154 order = reallocarray(order, orderlen *= 2,
155 sizeof (int));
156 if (order == NULL) {
157 fprintf(stderr,
158 gettext("cannot reallocate order "
159 "list.\n"));
160 return;
165 order[i] = MAX_INFO_DESCRIPTORS;
166 } else {
167 order = (int *)malloc(orderlen * sizeof (int));
168 if (order == NULL) {
169 fprintf(stderr,
170 gettext("cannot allocate order list.\n"));
171 return;
173 for (i = 0; i <= MAX_INFO_DESCRIPTORS; i++)
174 order[i] = i;
177 /* check if fssnap module is loaded */
178 if (kshigh == NULL) {
179 kstat_close(kslib);
180 return;
183 (void) kstat_read(kslib, kshigh, NULL);
184 highp = kstat_data_lookup(kshigh, FSSNAP_KSTAT_HIGHWATER);
186 /* Loop up to the maximum number of snapshots */
187 for (i = 0; i <= highp->value.ui32; i++) {
188 mnt = kstat_lookup(kslib, SNAP_NAME, i, FSSNAP_KSTAT_MNTPT);
190 /* if this snapshot is not allocated, skip to the next */
191 if (mnt == NULL)
192 continue;
193 if (kstat_read(kslib, mnt, NULL) == -1)
194 continue;
195 if (mountpoint != NULL) {
196 if ((usenum && i != num) ||
197 (!usenum && strcmp(mountpoint, mnt->ks_data) != 0))
198 continue;
201 if (brief)
202 printf("%4d\t%s\n", i, (char *)mnt->ks_data);
203 else
204 fssnap_display_info(i, order, labels);
208 static void
209 fssnap_display_info(ulong_t snapnum, int *order, int labels)
211 kstat_ctl_t *kslib;
212 kstat_t *back, *num;
213 kstat_named_t *numvalp;
214 kstat_t *mnt;
215 u_longlong_t inuse, size = 0;
216 char buf[BUFSIZ], *first;
217 int i;
219 /* load num kstat */
220 kslib = kstat_open();
221 num = kstat_lookup(kslib, SNAP_NAME, snapnum, FSSNAP_KSTAT_NUM);
222 if (num == NULL)
223 return;
225 if (kstat_read(kslib, num, NULL) == -1)
226 return;
228 for (i = 0; order[i] != MAX_INFO_DESCRIPTORS; i++) {
229 switch (order[i]) {
230 case INFO_SNAPSHOT:
231 if (labels)
232 printf("%-*s: %lu\n", MAX_LABEL_LEN,
233 gettext("Snapshot number"), snapnum);
234 else
235 printf("%lu\n", snapnum);
236 break;
237 case INFO_BLKDEV:
238 if (labels)
239 printf("%-*s: /dev/%s/%lu\n", MAX_LABEL_LEN,
240 gettext("Block Device"), SNAP_BLOCK_NAME,
241 snapnum);
242 else
243 printf("/dev/%s/%lu\n", SNAP_BLOCK_NAME,
244 snapnum);
245 break;
246 case INFO_CHARDEV:
247 if (labels)
248 printf("%-*s: /dev/%s/%lu\n", MAX_LABEL_LEN,
249 gettext("Raw Device"), SNAP_CHAR_NAME,
250 snapnum);
251 else
252 printf("/dev/%s/%lu\n", SNAP_CHAR_NAME,
253 snapnum);
254 break;
256 case INFO_MNTPT:
257 mnt = kstat_lookup(kslib, SNAP_NAME, snapnum,
258 FSSNAP_KSTAT_MNTPT);
259 if (mnt == NULL) {
260 fprintf(stderr,
261 gettext("cannot read mount point kstat\n"));
262 continue;
264 if (kstat_read(kslib, mnt, NULL) == -1) {
265 continue;
267 if (labels)
268 printf("%-*s: %s\n", MAX_LABEL_LEN,
269 gettext("Mount point"),
270 (char *)mnt->ks_data);
271 else
272 printf("%s\n", (char *)mnt->ks_data);
273 break;
274 case INFO_STATE:
275 /* state */
276 numvalp = kstat_data_lookup(num,
277 FSSNAP_KSTAT_NUM_STATE);
278 if (numvalp == NULL) {
279 fprintf(stderr,
280 gettext("cannot read state kstat\n"));
281 continue;
284 if (labels) {
285 printf("%-*s: ", MAX_LABEL_LEN,
286 gettext("Device state"));
287 switch (numvalp->value.i32) {
288 case 0: printf(gettext("creating\n"));
289 break;
290 case 1: printf(gettext("idle\n"));
291 break;
292 case 2: printf(gettext("active\n"));
293 break;
294 case 3: printf(gettext("disabled\n"));
295 break;
296 default: printf(gettext("unknown\n"));
297 break;
299 } else {
300 switch (numvalp->value.i32) {
301 case 0: printf("creating\n");
302 break;
303 case 1: printf("idle\n");
304 break;
305 case 2: printf("active\n");
306 break;
307 case 3: printf("disabled\n");
308 break;
309 default: printf("unknown\n");
310 break;
313 break;
315 case INFO_BACKPATH:
316 /* backing file kstat */
317 back = kstat_lookup(kslib, SNAP_NAME, snapnum,
318 FSSNAP_KSTAT_BFNAME);
319 if (back == NULL ||
320 (kstat_read(kslib, back, NULL) == -1) ||
321 (back->ks_data == NULL)) {
322 fprintf(stderr,
323 gettext("cannot read backing file name "
324 "kstat from kernel\n"));
325 continue;
327 if (labels)
328 printf("%-*s: %s\n", MAX_LABEL_LEN,
329 gettext("Backing store path"),
330 (char *)back->ks_data);
331 else
332 printf("%s\n", (char *)back->ks_data);
333 break;
335 case INFO_BACKSIZE:
336 numvalp = kstat_data_lookup(num,
337 FSSNAP_KSTAT_NUM_BFSIZE);
338 if (numvalp == NULL) {
339 fprintf(stderr,
340 gettext("cannot read backing file size "
341 "kstat from kernel\n"));
342 continue;
345 size = numvalp->value.ui64;
347 if (labels)
348 printf("%-*s: %llu KB\n", MAX_LABEL_LEN,
349 gettext("Backing store size"),
350 size / 1024LL);
351 else
352 printf("%llu\n", size);
353 break;
355 case INFO_MAXSIZE:
356 numvalp = kstat_data_lookup(num,
357 FSSNAP_KSTAT_NUM_MAXSIZE);
358 if (numvalp == NULL) {
359 fprintf(stderr,
360 gettext("cannot read backing file maxsize "
361 "kstat from kernel\n"));
362 continue;
364 if (labels) {
365 printf("%-*s: ", MAX_LABEL_LEN,
366 gettext("Maximum backing store size"));
368 if (numvalp->value.ui64 == 0LL)
369 printf(gettext("Unlimited\n"));
370 else
371 printf("%llu KB\n",
372 numvalp->value.ui64 / 1024LL);
373 } else {
374 printf("%llu\n", numvalp->value.ui64);
376 break;
378 case INFO_CREATETIME:
380 /* snapshot creation time */
381 char buf[256];
382 struct tm *tm;
383 char *p;
385 numvalp = kstat_data_lookup(num,
386 FSSNAP_KSTAT_NUM_CREATETIME);
387 if (numvalp == NULL) {
388 fprintf(stderr,
389 gettext("cannot read snapshot create time "
390 "kstat from kernel\n"));
391 continue;
394 if (labels) {
395 printf("%-*s: ", MAX_LABEL_LEN,
396 gettext("Snapshot create time"));
398 /* get the localized time */
399 tm = localtime(&numvalp->value.l);
400 if (strftime(buf, sizeof (buf),
401 "%c\n", tm) == 0)
402 /* Wouldn't fit in buf, fall back */
403 p = ctime(&numvalp->value.l);
404 else
405 p = buf;
406 } else {
408 * for script-readable options we want
409 * the locale-independent time only.
411 p = ctime(&numvalp->value.l);
413 /* p should already have a \n appended */
414 printf("%s", p);
415 break;
418 case INFO_CHUNKSIZE:
419 numvalp = kstat_data_lookup(num,
420 FSSNAP_KSTAT_NUM_CHUNKSIZE);
421 if (numvalp == NULL) {
422 fprintf(stderr,
423 gettext("cannot read chunksize kstat\n"));
424 continue;
426 if (labels)
427 printf("%-*s: %lu KB\n", MAX_LABEL_LEN,
428 gettext("Copy-on-write granularity"),
429 numvalp->value.ui32 / 1024L);
430 else
431 printf("%lu\n", numvalp->value.ui32);
432 break;
434 case -1:
436 * Print a place holder for unknown options so that
437 * the user can determine which option was not
438 * understood and the number outputted is the same
439 * number they requested.
441 printf("?\n");
442 break;
444 default:
445 printf(gettext("No such data type %d.\n"), order[i]);
446 break;