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 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 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