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 1991-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contians miscellaneous routines. 31 */ 32 #include "global.h" 33 34 #include <sys/mnttab.h> 35 #include <sys/mntent.h> 36 #include <sys/autoconf.h> 37 38 #include <signal.h> 39 #include <malloc.h> 40 #include <unistd.h> 41 #include <string.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <sys/ioctl.h> 45 #include <sys/fcntl.h> 46 #include <sys/stat.h> 47 #include <sys/swap.h> 48 #include <sys/sysmacros.h> 49 #include <ctype.h> 50 #include "misc.h" 51 #include "checkmount.h" 52 53 /* Function prototypes */ 54 #ifdef __STDC__ 55 56 static struct swaptable *getswapentries(void); 57 static void freeswapentries(struct swaptable *); 58 static int getpartition(char *pathname); 59 static int checkpartitions(int mounted); 60 61 #else /* __STDC__ */ 62 63 static struct swaptable *getswapentries(); 64 static void freeswapentries(); 65 static int getpartition(); 66 static int checkpartitions(); 67 68 #endif /* __STDC__ */ 69 70 static struct swaptable * 71 getswapentries(void) 72 { 73 register struct swaptable *st; 74 register struct swapent *swapent; 75 int i, num; 76 char fullpathname[MAXPATHLEN]; 77 78 /* 79 * get the number of swap entries 80 */ 81 if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { 82 err_print("swapctl error "); 83 fullabort(); 84 } 85 if (num == 0) 86 return (NULL); 87 if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) 88 == NULL) { 89 err_print("getswapentries: malloc failed.\n"); 90 fullabort(); 91 } 92 swapent = st->swt_ent; 93 for (i = 0; i < num; i++, swapent++) { 94 if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { 95 err_print("getswapentries: malloc failed.\n"); 96 fullabort(); 97 } 98 } 99 st->swt_n = num; 100 if ((num = swapctl(SC_LIST, (void *)st)) == -1) { 101 err_print("swapctl error "); 102 fullabort(); 103 } 104 swapent = st->swt_ent; 105 for (i = 0; i < num; i++, swapent++) { 106 if (*swapent->ste_path != '/') { 107 (void) snprintf(fullpathname, sizeof (fullpathname), 108 "/dev/%s", swapent->ste_path); 109 (void) strcpy(swapent->ste_path, fullpathname); 110 } 111 } 112 return (st); 113 } 114 115 static void 116 freeswapentries(st) 117 struct swaptable *st; 118 { 119 register struct swapent *swapent; 120 int i; 121 122 swapent = st->swt_ent; 123 for (i = 0; i < st->swt_n; i++, swapent++) 124 free(swapent->ste_path); 125 free(st); 126 127 } 128 129 /* 130 * function getpartition: 131 */ 132 static int 133 getpartition(pathname) 134 char *pathname; 135 { 136 int mfd; 137 struct dk_cinfo dkinfo; 138 struct stat stbuf; 139 char raw_device[MAXPATHLEN]; 140 int found = -1; 141 142 /* 143 * Map the block device name to the raw device name. 144 * If it doesn't appear to be a device name, skip it. 145 */ 146 if (match_substr(pathname, "/dev/") == 0) 147 return (found); 148 (void) strcpy(raw_device, "/dev/r"); 149 (void) strcat(raw_device, pathname + strlen("/dev/")); 150 /* 151 * Determine if this appears to be a disk device. 152 * First attempt to open the device. If if fails, skip it. 153 */ 154 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 155 return (found); 156 } 157 /* 158 * Must be a character device 159 */ 160 if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 161 (void) close(mfd); 162 return (found); 163 } 164 /* 165 * Attempt to read the configuration info on the disk. 166 */ 167 if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { 168 (void) close(mfd); 169 return (found); 170 } 171 /* 172 * Finished with the opened device 173 */ 174 (void) close(mfd); 175 176 /* 177 * If it's not the disk we're interested in, it doesn't apply. 178 */ 179 if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype || 180 cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum || 181 cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit || 182 strcmp(cur_disk->disk_dkinfo.dki_dname, 183 dkinfo.dki_dname) != 0) { 184 return (found); 185 } 186 187 /* 188 * Extract the partition that is mounted. 189 */ 190 return (PARTITION(stbuf.st_rdev)); 191 } 192 193 /* 194 * This Routine checks to see if there are partitions used for swapping overlaps 195 * a given portion of a disk. If the start parameter is < 0, it means 196 * that the entire disk should be checked 197 */ 198 int 199 checkswap(start, end) 200 diskaddr_t start, end; 201 { 202 struct swaptable *st; 203 struct swapent *swapent; 204 int i; 205 int found = 0; 206 struct dk_map32 *map; 207 int part; 208 209 /* 210 * If we are only checking part of the disk, the disk must 211 * have a partition map to check against. If it doesn't, 212 * we hope for the best. 213 */ 214 if (cur_parts == NULL) 215 return (0); 216 217 /* 218 * check for swap entries 219 */ 220 st = getswapentries(); 221 /* 222 * if there are no swap entries return. 223 */ 224 if (st == (struct swaptable *)NULL) 225 return (0); 226 swapent = st->swt_ent; 227 for (i = 0; i < st->swt_n; i++, swapent++) { 228 if ((part = getpartition(swapent->ste_path)) != -1) { 229 if (start == UINT_MAX64) { 230 found = -1; 231 break; 232 } 233 map = &cur_parts->pinfo_map[part]; 234 if ((start >= (int)(map->dkl_cylno * spc() + 235 map->dkl_nblk)) || (end < (int)(map->dkl_cylno 236 * spc()))) { 237 continue; 238 } 239 found = -1; 240 break; 241 }; 242 } 243 freeswapentries(st); 244 /* 245 * If we found trouble and we're running from a command file, 246 * quit before doing something we really regret. 247 */ 248 249 if (found && option_f) { 250 err_print( 251 "Operation on disks being used for swapping must be interactive.\n"); 252 cmdabort(SIGINT); 253 } 254 255 return (found); 256 257 258 } 259 260 /* 261 * This routine checks to see if there are mounted partitions overlapping 262 * a given portion of a disk. If the start parameter is < 0, it means 263 * that the entire disk should be checked. 264 */ 265 int 266 checkmount(start, end) 267 diskaddr_t start, end; 268 { 269 FILE *fp; 270 int found = 0; 271 struct dk_map32 *map; 272 int part; 273 struct mnttab mnt_record; 274 struct mnttab *mp = &mnt_record; 275 276 /* 277 * If we are only checking part of the disk, the disk must 278 * have a partition map to check against. If it doesn't, 279 * we hope for the best. 280 */ 281 if (cur_parts == NULL) 282 return (0); 283 284 /* 285 * Lock out interrupts because of the mntent protocol. 286 */ 287 enter_critical(); 288 /* 289 * Open the mount table. 290 */ 291 fp = fopen(MNTTAB, "r"); 292 if (fp == NULL) { 293 err_print("Unable to open mount table.\n"); 294 fullabort(); 295 } 296 /* 297 * Loop through the mount table until we run out of entries. 298 */ 299 while ((getmntent(fp, mp)) != -1) { 300 301 if ((part = getpartition(mp->mnt_special)) == -1) 302 continue; 303 304 /* 305 * It's a mount on the disk we're checking. If we are 306 * checking whole disk, then we found trouble. We can 307 * quit searching. 308 */ 309 if (start == UINT_MAX64) { 310 found = -1; 311 break; 312 } 313 314 /* 315 * If the partition overlaps the zone we're checking, 316 * then we found trouble. We can quit searching. 317 */ 318 map = &cur_parts->pinfo_map[part]; 319 if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) || 320 (end < (int)(map->dkl_cylno * spc()))) { 321 continue; 322 } 323 found = -1; 324 break; 325 } 326 /* 327 * Close down the mount table. 328 */ 329 (void) fclose(fp); 330 exit_critical(); 331 332 /* 333 * If we found trouble and we're running from a command file, 334 * quit before doing something we really regret. 335 */ 336 337 if (found && option_f) { 338 err_print("Operation on mounted disks must be interactive.\n"); 339 cmdabort(SIGINT); 340 } 341 /* 342 * Return the result. 343 */ 344 return (found); 345 } 346 347 int 348 check_label_with_swap() 349 { 350 int i; 351 struct swaptable *st; 352 struct swapent *swapent; 353 int part; 354 int bm_swap = 0; 355 356 /* 357 * If we are only checking part of the disk, the disk must 358 * have a partition map to check against. If it doesn't, 359 * we hope for the best. 360 */ 361 if (cur_parts == NULL) 362 return (0); /* Will be checked later */ 363 364 /* 365 * Check for swap entries 366 */ 367 st = getswapentries(); 368 /* 369 * if there are no swap entries return. 370 */ 371 if (st == (struct swaptable *)NULL) 372 return (0); 373 swapent = st->swt_ent; 374 for (i = 0; i < st->swt_n; i++, swapent++) 375 if ((part = getpartition(swapent->ste_path)) != -1) 376 bm_swap |= (1 << part); 377 freeswapentries(st); 378 379 return (checkpartitions(bm_swap)); 380 } 381 382 /* 383 * Check the new label with the existing label on the disk, 384 * to make sure that any mounted partitions are not being 385 * affected by writing the new label. 386 */ 387 int 388 check_label_with_mount() 389 { 390 FILE *fp; 391 int part; 392 struct mnttab mnt_record; 393 struct mnttab *mp = &mnt_record; 394 int bm_mounted = 0; 395 396 397 /* 398 * If we are only checking part of the disk, the disk must 399 * have a partition map to check against. If it doesn't, 400 * we hope for the best. 401 */ 402 if (cur_parts == NULL) 403 return (0); /* Will be checked later */ 404 405 /* 406 * Lock out interrupts because of the mntent protocol. 407 */ 408 enter_critical(); 409 /* 410 * Open the mount table. 411 */ 412 fp = fopen(MNTTAB, "r"); 413 if (fp == NULL) { 414 err_print("Unable to open mount table.\n"); 415 fullabort(); 416 } 417 /* 418 * Loop through the mount table until we run out of entries. 419 */ 420 while ((getmntent(fp, mp)) != -1) { 421 if ((part = getpartition(mp->mnt_special)) != -1) 422 bm_mounted |= (1 << part); 423 } 424 /* 425 * Close down the mount table. 426 */ 427 (void) fclose(fp); 428 exit_critical(); 429 430 return (checkpartitions(bm_mounted)); 431 432 } 433 434 /* 435 * This Routine checks if any partitions specified by the 436 * bit-map of mounted/swap partitions are affected by 437 * writing the new label 438 */ 439 static int 440 checkpartitions(bm_mounted) 441 int bm_mounted; 442 { 443 struct dk_map32 *n; 444 struct dk_map *o; 445 struct dk_allmap old_map; 446 int i, found = 0; 447 448 /* 449 * Now we need to check that the current partition list and the 450 * previous partition list (which there must be if we actually 451 * have partitions mounted) overlap in any way on the mounted 452 * partitions 453 */ 454 455 /* 456 * Get the "real" (on-disk) version of the partition table 457 */ 458 if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) { 459 err_print("Unable to get current partition map.\n"); 460 return (-1); 461 } 462 for (i = 0; i < NDKMAP; i++) { 463 if (bm_mounted & (1 << i)) { 464 /* 465 * This partition is mounted 466 */ 467 o = &old_map.dka_map[i]; 468 n = &cur_parts->pinfo_map[i]; 469 #ifdef DEBUG 470 fmt_print( 471 "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE); 472 #endif 473 /* 474 * If partition is identical, we're fine. 475 * If the partition grows, we're also fine, because 476 * the routines in partition.c check for overflow. 477 * It will (ultimately) be up to the routines in 478 * partition.c to warn about creation of overlapping 479 * partitions 480 */ 481 if (o->dkl_cylno == n->dkl_cylno && 482 o->dkl_nblk <= n->dkl_nblk) { 483 #ifdef DEBUG 484 if (o->dkl_nblk < n->dkl_nblk) { 485 fmt_print( 486 "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk); 487 } 488 fmt_print("\n"); 489 #endif 490 continue; 491 } 492 #ifdef DEBUG 493 fmt_print("- changes; old (%d,%d)->new (%d,%d)\n", 494 o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, 495 n->dkl_nblk); 496 #endif 497 found = -1; 498 } 499 if (found) 500 break; 501 } 502 503 /* 504 * If we found trouble and we're running from a command file, 505 * quit before doing something we really regret. 506 */ 507 508 if (found && option_f) { 509 err_print("Operation on mounted disks or \ 510 disks currently being used for swapping must be interactive.\n"); 511 cmdabort(SIGINT); 512 } 513 /* 514 * Return the result. 515 */ 516 return (found); 517 } 518