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