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