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