0
|
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 (the "License").
|
|
6 * You may not use this file except in compliance with the License.
|
|
7 *
|
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
9 * or http://www.opensolaris.org/os/licensing.
|
|
10 * See the License for the specific language governing permissions
|
|
11 * and limitations under the License.
|
|
12 *
|
|
13 * When distributing Covered Code, include this CDDL HEADER in each
|
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
15 * If applicable, add the following below this CDDL HEADER, with the
|
|
16 * fields enclosed by brackets "[]" replaced with your own identifying
|
|
17 * information: Portions Copyright [yyyy] [name of copyright owner]
|
|
18 *
|
|
19 * CDDL HEADER END
|
|
20 */
|
|
21 /*
|
|
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
|
23 * Use is subject to license terms.
|
|
24 */
|
|
25
|
|
26
|
|
27 #pragma ident "@(#)checkdev.c 1.18 06/04/27 SMI"
|
|
28
|
|
29 /*
|
|
30 * This file contains miscellaneous device validation routines.
|
|
31 */
|
|
32
|
|
33 #include "global.h"
|
|
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 <libgen.h>
|
|
45 #include <sys/ioctl.h>
|
|
46 #include <sys/fcntl.h>
|
|
47 #include <sys/stat.h>
|
|
48 #include <sys/swap.h>
|
|
49 #include <sys/sysmacros.h>
|
|
50 #include <sys/mkdev.h>
|
|
51 #include <sys/modctl.h>
|
|
52 #include <ctype.h>
|
|
53 #include <libdiskmgt.h>
|
|
54 #include <libnvpair.h>
|
|
55 #include "misc.h"
|
|
56 #include "checkdev.h"
|
|
57
|
|
58 /* Function prototypes */
|
|
59 #ifdef __STDC__
|
|
60
|
|
61 static struct swaptable *getswapentries(void);
|
|
62 static void freeswapentries(struct swaptable *);
|
|
63 static int getpartition(char *pathname);
|
|
64 static int checkpartitions(int bm_mounted);
|
|
65
|
|
66 #else /* __STDC__ */
|
|
67
|
|
68 static struct swaptable *getswapentries();
|
|
69 static void freeswapentries();
|
|
70 static int getpartition();
|
|
71 static int checkpartitions();
|
|
72
|
|
73 #endif /* __STDC__ */
|
|
74
|
|
75 extern char *getfullname();
|
|
76
|
|
77 static struct swaptable *
|
|
78 getswapentries(void)
|
|
79 {
|
|
80 register struct swaptable *st;
|
|
81 register struct swapent *swapent;
|
|
82 int i, num;
|
|
83 char fullpathname[MAXPATHLEN];
|
|
84
|
|
85 /*
|
|
86 * get the number of swap entries
|
|
87 */
|
|
88 if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) {
|
|
89 err_print("swapctl error ");
|
|
90 fullabort();
|
|
91 }
|
|
92 if (num == 0)
|
|
93 return (NULL);
|
|
94 if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int)))
|
|
95 == NULL) {
|
|
96 err_print("getswapentries: malloc failed.\n");
|
|
97 fullabort();
|
|
98 }
|
|
99 swapent = st->swt_ent;
|
|
100 for (i = 0; i < num; i++, swapent++) {
|
|
101 if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) {
|
|
102 err_print("getswapentries: malloc failed.\n");
|
|
103 fullabort();
|
|
104 }
|
|
105 }
|
|
106 st->swt_n = num;
|
|
107 if ((num = swapctl(SC_LIST, (void *)st)) == -1) {
|
|
108 err_print("swapctl error ");
|
|
109 fullabort();
|
|
110 }
|
|
111 swapent = st->swt_ent;
|
|
112 for (i = 0; i < num; i++, swapent++) {
|
|
113 if (*swapent->ste_path != '/') {
|
|
114 (void) snprintf(fullpathname, sizeof (fullpathname),
|
|
115 "/dev/%s", swapent->ste_path);
|
|
116 (void) strcpy(swapent->ste_path, fullpathname);
|
|
117 }
|
|
118 }
|
|
119 return (st);
|
|
120 }
|
|
121
|
|
122 static void
|
|
123 freeswapentries(st)
|
|
124 struct swaptable *st;
|
|
125 {
|
|
126 register struct swapent *swapent;
|
|
127 int i;
|
|
128
|
|
129 swapent = st->swt_ent;
|
|
130 for (i = 0; i < st->swt_n; i++, swapent++)
|
|
131 free(swapent->ste_path);
|
|
132 free(st);
|
|
133
|
|
134 }
|
|
135
|
|
136 /*
|
|
137 * function getpartition:
|
|
138 */
|
|
139 static int
|
|
140 getpartition(pathname)
|
|
141 char *pathname;
|
|
142 {
|
|
143 int mfd;
|
|
144 struct dk_cinfo dkinfo;
|
|
145 struct stat stbuf;
|
|
146 char raw_device[MAXPATHLEN];
|
|
147 int found = -1;
|
|
148
|
|
149 /*
|
|
150 * Map the block device name to the raw device name.
|
|
151 * If it doesn't appear to be a device name, skip it.
|
|
152 */
|
|
153 if (match_substr(pathname, "/dev/") == 0)
|
|
154 return (found);
|
|
155 (void) strcpy(raw_device, "/dev/r");
|
|
156 (void) strcat(raw_device, pathname + strlen("/dev/"));
|
|
157 /*
|
|
158 * Determine if this appears to be a disk device.
|
|
159 * First attempt to open the device. If if fails, skip it.
|
|
160 */
|
|
161 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
|
|
162 return (found);
|
|
163 }
|
|
164 /*
|
|
165 * Must be a character device
|
|
166 */
|
|
167 if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
|
|
168 (void) close(mfd);
|
|
169 return (found);
|
|
170 }
|
|
171 /*
|
|
172 * Attempt to read the configuration info on the disk.
|
|
173 */
|
|
174 if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) {
|
|
175 (void) close(mfd);
|
|
176 return (found);
|
|
177 }
|
|
178 /*
|
|
179 * Finished with the opened device
|
|
180 */
|
|
181 (void) close(mfd);
|
|
182
|
|
183 /*
|
|
184 * If it's not the disk we're interested in, it doesn't apply.
|
|
185 */
|
|
186 if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype ||
|
|
187 cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum ||
|
|
188 cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit ||
|
|
189 strcmp(cur_disk->disk_dkinfo.dki_dname,
|
|
190 dkinfo.dki_dname) != 0) {
|
|
191 return (found);
|
|
192 }
|
|
193
|
|
194 /*
|
|
195 * Extract the partition that is mounted.
|
|
196 */
|
|
197 return (PARTITION(stbuf.st_rdev));
|
|
198 }
|
|
199
|
|
200 /*
|
|
201 * This Routine checks to see if there are partitions used for swapping overlaps
|
|
202 * a given portion of a disk. If the start parameter is < 0, it means
|
|
203 * that the entire disk should be checked
|
|
204 */
|
|
205 int
|
|
206 checkswap(start, end)
|
|
207 diskaddr_t start, end;
|
|
208 {
|
|
209 struct swaptable *st;
|
|
210 struct swapent *swapent;
|
|
211 int i;
|
|
212 int found = 0;
|
|
213 struct dk_map32 *map;
|
|
214 int part;
|
|
215
|
|
216 /*
|
|
217 * If we are only checking part of the disk, the disk must
|
|
218 * have a partition map to check against. If it doesn't,
|
|
219 * we hope for the best.
|
|
220 */
|
|
221 if (cur_parts == NULL)
|
|
222 return (0);
|
|
223
|
|
224 /*
|
|
225 * check for swap entries
|
|
226 */
|
|
227 st = getswapentries();
|
|
228 /*
|
|
229 * if there are no swap entries return.
|
|
230 */
|
|
231 if (st == (struct swaptable *)NULL)
|
|
232 return (0);
|
|
233 swapent = st->swt_ent;
|
|
234 for (i = 0; i < st->swt_n; i++, swapent++) {
|
|
235 if ((part = getpartition(swapent->ste_path)) != -1) {
|
|
236 if (start == UINT_MAX64) {
|
|
237 found = -1;
|
|
238 break;
|
|
239 }
|
|
240 map = &cur_parts->pinfo_map[part];
|
|
241 if ((start >= (int)(map->dkl_cylno * spc() +
|
|
242 map->dkl_nblk)) || (end < (int)(map->dkl_cylno
|
|
243 * spc()))) {
|
|
244 continue;
|
|
245 }
|
|
246 found = -1;
|
|
247 break;
|
|
248 };
|
|
249 }
|
|
250 freeswapentries(st);
|
|
251 /*
|
|
252 * If we found trouble and we're running from a command file,
|
|
253 * quit before doing something we really regret.
|
|
254 */
|
|
255
|
|
256 if (found && option_f) {
|
|
257 err_print(
|
|
258 "Operation on disks being used for swapping must be interactive.\n");
|
|
259 cmdabort(SIGINT);
|
|
260 }
|
|
261
|
|
262 return (found);
|
|
263
|
|
264
|
|
265 }
|
|
266 /*
|
|
267 * Determines if there are partitions that are a part of an SVM, VxVM, zpool
|
|
268 * volume or a live upgrade device, overlapping a given portion of a disk.
|
|
269 * Mounts and swap devices are checked in legacy format code.
|
|
270 */
|
|
271 int
|
|
272 checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print,
|
|
273 int check_label)
|
|
274 {
|
|
275
|
|
276 int error;
|
|
277 int found = 0;
|
|
278 int check = 0;
|
|
279 int i;
|
|
280 int bm_inuse = 0;
|
|
281 int part = 0;
|
|
282 uint64_t slice_start, slice_size;
|
|
283 dm_descriptor_t *slices = NULL;
|
|
284 nvlist_t *attrs = NULL;
|
|
285 char *usage;
|
|
286 char *name;
|
|
287
|
|
288 /*
|
|
289 * If the user does not want to do in use checking, return immediately.
|
|
290 * Normally, this is handled in libdiskmgt. For format, there is more
|
|
291 * processing required, so we want to bypass the in use checking
|
|
292 * here.
|
|
293 */
|
|
294
|
|
295 if (NOINUSE_SET)
|
|
296 return (0);
|
|
297
|
|
298 /*
|
|
299 * Skip if it is not a real disk
|
|
300 *
|
|
301 * There could be two kinds of strings in cur_disk_path
|
|
302 * One starts with c?t?d?, while the other is a absolute path of a
|
|
303 * block device file.
|
|
304 */
|
|
305
|
|
306 if (*cur_disk_path != 'c') {
|
|
307 struct stat stbuf;
|
|
308 char majorname[16];
|
|
309 major_t majornum;
|
|
310
|
|
311 (void) stat(cur_disk_path, &stbuf);
|
|
312 majornum = major(stbuf.st_rdev);
|
|
313 (void) modctl(MODGETNAME, majorname, sizeof (majorname),
|
|
314 &majornum);
|
|
315
|
|
316 if (strcmp(majorname, "sd"))
|
|
317 if (strcmp(majorname, "ssd"))
|
|
318 if (strcmp(majorname, "cmdk"))
|
|
319 return (0);
|
|
320 }
|
|
321
|
|
322 /*
|
|
323 * Truncate the characters following "d*", such as "s*" or "p*"
|
|
324 */
|
|
325 cur_disk_path = basename(cur_disk_path);
|
|
326 name = strrchr(cur_disk_path, 'd');
|
|
327 if (name) {
|
|
328 name++;
|
|
329 for (; (*name <= '9') && (*name >= '0'); name++);
|
|
330 *name = (char)0;
|
|
331 }
|
|
332
|
|
333
|
|
334 /*
|
|
335 * For format, we get basic 'in use' details from libdiskmgt. After
|
|
336 * that we must do the appropriate checking to see if the 'in use'
|
|
337 * details require a bit of additional work.
|
|
338 */
|
|
339
|
|
340 dm_get_slices(cur_disk_path, &slices, &error);
|
|
341 if (error) {
|
|
342 err_print("Error occurred with device in use checking: %s\n",
|
|
343 strerror(error));
|
|
344 return (found);
|
|
345 }
|
|
346 if (slices == NULL)
|
|
347 return (found);
|
|
348
|
|
349 for (i = 0; slices[i] != NULL; i++) {
|
|
350 /*
|
|
351 * If we are checking the whole disk
|
|
352 * then any and all in use data is
|
|
353 * relevant.
|
|
354 */
|
|
355 if (start == UINT_MAX64) {
|
|
356 name = dm_get_name(slices[i], &error);
|
|
357 if (error != 0 || !name) {
|
|
358 err_print("Error occurred with device "
|
|
359 "in use checking: %s\n",
|
|
360 strerror(error));
|
|
361 continue;
|
|
362 }
|
|
363 if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) ||
|
|
364 error) {
|
|
365 if (error != 0) {
|
|
366 dm_free_name(name);
|
|
367 name = NULL;
|
|
368 err_print("Error occurred with device "
|
|
369 "in use checking: %s\n",
|
|
370 strerror(error));
|
|
371 continue;
|
|
372 }
|
|
373 dm_free_name(name);
|
|
374 name = NULL;
|
|
375 /*
|
|
376 * If this is a dump device, then it is
|
|
377 * a failure. You cannot format a slice
|
|
378 * that is a dedicated dump device.
|
|
379 */
|
|
380
|
|
381 if (strstr(usage, DM_USE_DUMP)) {
|
|
382 if (print) {
|
|
383 err_print(usage);
|
|
384 free(usage);
|
|
385 }
|
|
386 dm_free_descriptors(slices);
|
|
387 return (1);
|
|
388 }
|
|
389 /*
|
|
390 * We really found a device that is in use.
|
|
391 * Set 'found' for the return value, and set
|
|
392 * 'check' to indicate below that we must
|
|
393 * get the partition number to set bm_inuse
|
|
394 * in the event we are trying to label this
|
|
395 * device. check_label is set when we are
|
|
396 * checking modifications for in use slices
|
|
397 * on the device.
|
|
398 */
|
|
399 found ++;
|
|
400 check = 1;
|
|
401 if (print) {
|
|
402 err_print(usage);
|
|
403 free(usage);
|
|
404 }
|
|
405 }
|
|
406 } else {
|
|
407 /*
|
|
408 * Before getting the in use data, verify that the
|
|
409 * current slice is within the range we are checking.
|
|
410 */
|
|
411 attrs = dm_get_attributes(slices[i], &error);
|
|
412 if (error) {
|
|
413 err_print("Error occurred with device in use "
|
|
414 "checking: %s\n", strerror(error));
|
|
415 continue;
|
|
416 }
|
|
417 if (attrs == NULL) {
|
|
418 continue;
|
|
419 }
|
|
420
|
|
421 (void) nvlist_lookup_uint64(attrs, DM_START,
|
|
422 &slice_start);
|
|
423 (void) nvlist_lookup_uint64(attrs, DM_SIZE,
|
|
424 &slice_size);
|
|
425 if (start >= (slice_start + slice_size) ||
|
|
426 (end < slice_start)) {
|
|
427 nvlist_free(attrs);
|
|
428 attrs = NULL;
|
|
429 continue;
|
|
430 }
|
|
431 name = dm_get_name(slices[i], &error);
|
|
432 if (error != 0 || !name) {
|
|
433 err_print("Error occurred with device "
|
|
434 "in use checking: %s\n",
|
|
435 strerror(error));
|
|
436 nvlist_free(attrs);
|
|
437 attrs = NULL;
|
|
438 continue;
|
|
439 }
|
|
440 if (dm_inuse(name, &usage,
|
|
441 DM_WHO_FORMAT, &error) || error) {
|
|
442 if (error != 0) {
|
|
443 dm_free_name(name);
|
|
444 name = NULL;
|
|
445 err_print("Error occurred with device "
|
|
446 "in use checking: %s\n",
|
|
447 strerror(error));
|
|
448 nvlist_free(attrs);
|
|
449 attrs = NULL;
|
|
450 continue;
|
|
451 }
|
|
452 dm_free_name(name);
|
|
453 name = NULL;
|
|
454 /*
|
|
455 * If this is a dump device, then it is
|
|
456 * a failure. You cannot format a slice
|
|
457 * that is a dedicated dump device.
|
|
458 */
|
|
459 if (strstr(usage, DM_USE_DUMP)) {
|
|
460 if (print) {
|
|
461 err_print(usage);
|
|
462 free(usage);
|
|
463 }
|
|
464 dm_free_descriptors(slices);
|
|
465 nvlist_free(attrs);
|
|
466 return (1);
|
|
467 }
|
|
468 /*
|
|
469 * We really found a device that is in use.
|
|
470 * Set 'found' for the return value, and set
|
|
471 * 'check' to indicate below that we must
|
|
472 * get the partition number to set bm_inuse
|
|
473 * in the event we are trying to label this
|
|
474 * device. check_label is set when we are
|
|
475 * checking modifications for in use slices
|
|
476 * on the device.
|
|
477 */
|
|
478 found ++;
|
|
479 check = 1;
|
|
480 if (print) {
|
|
481 err_print(usage);
|
|
482 free(usage);
|
|
483 }
|
|
484 }
|
|
485 }
|
|
486 /*
|
|
487 * If check is set it means we found a slice(the current slice)
|
|
488 * on this device in use in some way. We potentially want
|
|
489 * to check this slice when labeling is
|
|
490 * requested. We set bm_inuse with this partition value
|
|
491 * for use later if check_label was set when called.
|
|
492 */
|
|
493 if (check) {
|
|
494 name = dm_get_name(slices[i], &error);
|
|
495 if (error != 0 || !name) {
|
|
496 err_print("Error occurred with device "
|
|
497 "in use checking: %s\n",
|
|
498 strerror(error));
|
|
499 nvlist_free(attrs);
|
|
500 attrs = NULL;
|
|
501 continue;
|
|
502 }
|
|
503 part = getpartition(name);
|
|
504 dm_free_name(name);
|
|
505 name = NULL;
|
|
506 if (part != -1) {
|
|
507 bm_inuse |= 1 << part;
|
|
508 }
|
|
509 check = 0;
|
|
510 }
|
|
511 /*
|
|
512 * If we have attributes then we have successfully
|
|
513 * found the slice we were looking for and we also
|
|
514 * know this means we are not searching the whole
|
|
515 * disk so break out of the loop
|
|
516 * now.
|
|
517 */
|
|
518 if (attrs) {
|
|
519 nvlist_free(attrs);
|
|
520 break;
|
|
521 }
|
|
522 }
|
|
523
|
|
524 if (slices) {
|
|
525 dm_free_descriptors(slices);
|
|
526 }
|
|
527
|
|
528 /*
|
|
529 * The user is trying to label the disk. We have to do special
|
|
530 * checking here to ensure they are not trying to modify a slice
|
|
531 * that is in use in an incompatible way.
|
|
532 */
|
|
533 if (check_label && bm_inuse) {
|
|
534 /*
|
|
535 * !0 indicates that we found a
|
|
536 * problem. In this case, we have overloaded
|
|
537 * the use of checkpartitions to work for
|
|
538 * in use devices. bm_inuse is representative
|
|
539 * of the slice that is in use, not that
|
|
540 * is mounted as is in the case of the normal
|
|
541 * use of checkpartitions.
|
|
542 *
|
|
543 * The call to checkpartitions will return !0 if
|
|
544 * we are trying to shrink a device that we have found
|
|
545 * to be in use above.
|
|
546 */
|
|
547 return (checkpartitions(bm_inuse));
|
|
548 }
|
|
549
|
|
550 return (found);
|
|
551 }
|
|
552 /*
|
|
553 * This routine checks to see if there are mounted partitions overlapping
|
|
554 * a given portion of a disk. If the start parameter is < 0, it means
|
|
555 * that the entire disk should be checked.
|
|
556 */
|
|
557 int
|
|
558 checkmount(start, end)
|
|
559 diskaddr_t start, end;
|
|
560 {
|
|
561 FILE *fp;
|
|
562 int found = 0;
|
|
563 struct dk_map32 *map;
|
|
564 int part;
|
|
565 struct mnttab mnt_record;
|
|
566 struct mnttab *mp = &mnt_record;
|
|
567
|
|
568 /*
|
|
569 * If we are only checking part of the disk, the disk must
|
|
570 * have a partition map to check against. If it doesn't,
|
|
571 * we hope for the best.
|
|
572 */
|
|
573 if (cur_parts == NULL)
|
|
574 return (0);
|
|
575
|
|
576 /*
|
|
577 * Lock out interrupts because of the mntent protocol.
|
|
578 */
|
|
579 enter_critical();
|
|
580 /*
|
|
581 * Open the mount table.
|
|
582 */
|
|
583 fp = fopen(MNTTAB, "r");
|
|
584 if (fp == NULL) {
|
|
585 err_print("Unable to open mount table.\n");
|
|
586 fullabort();
|
|
587 }
|
|
588 /*
|
|
589 * Loop through the mount table until we run out of entries.
|
|
590 */
|
|
591 while ((getmntent(fp, mp)) != -1) {
|
|
592
|
|
593 if ((part = getpartition(mp->mnt_special)) == -1)
|
|
594 continue;
|
|
595
|
|
596 /*
|
|
597 * It's a mount on the disk we're checking. If we are
|
|
598 * checking whole disk, then we found trouble. We can
|
|
599 * quit searching.
|
|
600 */
|
|
601 if (start == UINT_MAX64) {
|
|
602 found = -1;
|
|
603 break;
|
|
604 }
|
|
605
|
|
606 /*
|
|
607 * If the partition overlaps the zone we're checking,
|
|
608 * then we found trouble. We can quit searching.
|
|
609 */
|
|
610 map = &cur_parts->pinfo_map[part];
|
|
611 if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) ||
|
|
612 (end < (int)(map->dkl_cylno * spc()))) {
|
|
613 continue;
|
|
614 }
|
|
615 found = -1;
|
|
616 break;
|
|
617 }
|
|
618 /*
|
|
619 * Close down the mount table.
|
|
620 */
|
|
621 (void) fclose(fp);
|
|
622 exit_critical();
|
|
623
|
|
624 /*
|
|
625 * If we found trouble and we're running from a command file,
|
|
626 * quit before doing something we really regret.
|
|
627 */
|
|
628
|
|
629 if (found && option_f) {
|
|
630 err_print("Operation on mounted disks must be interactive.\n");
|
|
631 cmdabort(SIGINT);
|
|
632 }
|
|
633 /*
|
|
634 * Return the result.
|
|
635 */
|
|
636 return (found);
|
|
637 }
|
|
638
|
|
639 int
|
|
640 check_label_with_swap()
|
|
641 {
|
|
642 int i;
|
|
643 struct swaptable *st;
|
|
644 struct swapent *swapent;
|
|
645 int part;
|
|
646 int bm_swap = 0;
|
|
647
|
|
648 /*
|
|
649 * If we are only checking part of the disk, the disk must
|
|
650 * have a partition map to check against. If it doesn't,
|
|
651 * we hope for the best.
|
|
652 */
|
|
653 if (cur_parts == NULL)
|
|
654 return (0); /* Will be checked later */
|
|
655
|
|
656 /*
|
|
657 * Check for swap entries
|
|
658 */
|
|
659 st = getswapentries();
|
|
660 /*
|
|
661 * if there are no swap entries return.
|
|
662 */
|
|
663 if (st == (struct swaptable *)NULL)
|
|
664 return (0);
|
|
665 swapent = st->swt_ent;
|
|
666 for (i = 0; i < st->swt_n; i++, swapent++)
|
|
667 if ((part = getpartition(swapent->ste_path)) != -1)
|
|
668 bm_swap |= (1 << part);
|
|
669 freeswapentries(st);
|
|
670
|
|
671 return (checkpartitions(bm_swap));
|
|
672 }
|
|
673
|
|
674 /*
|
|
675 * Check the new label with the existing label on the disk,
|
|
676 * to make sure that any mounted partitions are not being
|
|
677 * affected by writing the new label.
|
|
678 */
|
|
679 int
|
|
680 check_label_with_mount()
|
|
681 {
|
|
682 FILE *fp;
|
|
683 int part;
|
|
684 struct mnttab mnt_record;
|
|
685 struct mnttab *mp = &mnt_record;
|
|
686 int bm_mounted = 0;
|
|
687
|
|
688
|
|
689 /*
|
|
690 * If we are only checking part of the disk, the disk must
|
|
691 * have a partition map to check against. If it doesn't,
|
|
692 * we hope for the best.
|
|
693 */
|
|
694 if (cur_parts == NULL)
|
|
695 return (0); /* Will be checked later */
|
|
696
|
|
697 /*
|
|
698 * Lock out interrupts because of the mntent protocol.
|
|
699 */
|
|
700 enter_critical();
|
|
701 /*
|
|
702 * Open the mount table.
|
|
703 */
|
|
704 fp = fopen(MNTTAB, "r");
|
|
705 if (fp == NULL) {
|
|
706 err_print("Unable to open mount table.\n");
|
|
707 fullabort();
|
|
708 }
|
|
709 /*
|
|
710 * Loop through the mount table until we run out of entries.
|
|
711 */
|
|
712 while ((getmntent(fp, mp)) != -1) {
|
|
713 if ((part = getpartition(mp->mnt_special)) != -1)
|
|
714 bm_mounted |= (1 << part);
|
|
715 }
|
|
716 /*
|
|
717 * Close down the mount table.
|
|
718 */
|
|
719 (void) fclose(fp);
|
|
720 exit_critical();
|
|
721
|
|
722 return (checkpartitions(bm_mounted));
|
|
723
|
|
724 }
|
|
725
|
|
726 /*
|
|
727 * This Routine checks if any partitions specified
|
|
728 * are affected by writing the new label
|
|
729 */
|
|
730 static int
|
|
731 checkpartitions(int bm_mounted)
|
|
732 {
|
|
733 struct dk_map32 *n;
|
|
734 struct dk_map *o;
|
|
735 struct dk_allmap old_map;
|
|
736 int i, found = 0;
|
|
737
|
|
738 /*
|
|
739 * Now we need to check that the current partition list and the
|
|
740 * previous partition list (which there must be if we actually
|
|
741 * have partitions mounted) overlap in any way on the mounted
|
|
742 * partitions
|
|
743 */
|
|
744
|
|
745 /*
|
|
746 * Get the "real" (on-disk) version of the partition table
|
|
747 */
|
|
748 if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) {
|
|
749 err_print("Unable to get current partition map.\n");
|
|
750 return (-1);
|
|
751 }
|
|
752 for (i = 0; i < NDKMAP; i++) {
|
|
753 if (bm_mounted & (1 << i)) {
|
|
754 /*
|
|
755 * This partition is mounted
|
|
756 */
|
|
757 o = &old_map.dka_map[i];
|
|
758 n = &cur_parts->pinfo_map[i];
|
|
759 #ifdef DEBUG
|
|
760 fmt_print(
|
|
761 "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE);
|
|
762 #endif
|
|
763 /*
|
|
764 * If partition is identical, we're fine.
|
|
765 * If the partition grows, we're also fine, because
|
|
766 * the routines in partition.c check for overflow.
|
|
767 * It will (ultimately) be up to the routines in
|
|
768 * partition.c to warn about creation of overlapping
|
|
769 * partitions
|
|
770 */
|
|
771 if (o->dkl_cylno == n->dkl_cylno &&
|
|
772 o->dkl_nblk <= n->dkl_nblk) {
|
|
773 #ifdef DEBUG
|
|
774 if (o->dkl_nblk < n->dkl_nblk) {
|
|
775 fmt_print(
|
|
776 "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk);
|
|
777 }
|
|
778 fmt_print("\n");
|
|
779 #endif
|
|
780 continue;
|
|
781 }
|
|
782 #ifdef DEBUG
|
|
783 fmt_print("- changes; old (%d,%d)->new (%d,%d)\n",
|
|
784 o->dkl_cylno, o->dkl_nblk, n->dkl_cylno,
|
|
785 n->dkl_nblk);
|
|
786 #endif
|
|
787 found = -1;
|
|
788 }
|
|
789 if (found)
|
|
790 break;
|
|
791 }
|
|
792
|
|
793 /*
|
|
794 * If we found trouble and we're running from a command file,
|
|
795 * quit before doing something we really regret.
|
|
796 */
|
|
797
|
|
798 if (found && option_f) {
|
|
799 err_print("Operation on mounted disks or \
|
|
800 disks currently being used for swapping must be interactive.\n");
|
|
801 cmdabort(SIGINT);
|
|
802 }
|
|
803 /*
|
|
804 * Return the result.
|
|
805 */
|
|
806 return (found);
|
|
807 }
|