1767Ssjelinek /*
2767Ssjelinek * CDDL HEADER START
3767Ssjelinek *
4767Ssjelinek * The contents of this file are subject to the terms of the
52083Szl149053 * Common Development and Distribution License (the "License").
62083Szl149053 * You may not use this file except in compliance with the License.
7767Ssjelinek *
8767Ssjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9767Ssjelinek * or http://www.opensolaris.org/os/licensing.
10767Ssjelinek * See the License for the specific language governing permissions
11767Ssjelinek * and limitations under the License.
12767Ssjelinek *
13767Ssjelinek * When distributing Covered Code, include this CDDL HEADER in each
14767Ssjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15767Ssjelinek * If applicable, add the following below this CDDL HEADER, with the
16767Ssjelinek * fields enclosed by brackets "[]" replaced with your own identifying
17767Ssjelinek * information: Portions Copyright [yyyy] [name of copyright owner]
18767Ssjelinek *
19767Ssjelinek * CDDL HEADER END
20767Ssjelinek */
21767Ssjelinek /*
22*9958SSharath.Srinivasan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23767Ssjelinek * Use is subject to license terms.
24767Ssjelinek */
25767Ssjelinek
26767Ssjelinek
27767Ssjelinek
28767Ssjelinek /*
29767Ssjelinek * This file contains miscellaneous device validation routines.
30767Ssjelinek */
31767Ssjelinek
32767Ssjelinek #include "global.h"
33767Ssjelinek #include <sys/mnttab.h>
34767Ssjelinek #include <sys/mntent.h>
35767Ssjelinek #include <sys/autoconf.h>
36767Ssjelinek
37767Ssjelinek #include <signal.h>
38767Ssjelinek #include <malloc.h>
39767Ssjelinek #include <unistd.h>
40767Ssjelinek #include <string.h>
41767Ssjelinek #include <errno.h>
42767Ssjelinek #include <fcntl.h>
432083Szl149053 #include <libgen.h>
44767Ssjelinek #include <sys/ioctl.h>
45767Ssjelinek #include <sys/fcntl.h>
46767Ssjelinek #include <sys/stat.h>
47767Ssjelinek #include <sys/swap.h>
48767Ssjelinek #include <sys/sysmacros.h>
492083Szl149053 #include <sys/mkdev.h>
502083Szl149053 #include <sys/modctl.h>
51767Ssjelinek #include <ctype.h>
52767Ssjelinek #include <libdiskmgt.h>
53767Ssjelinek #include <libnvpair.h>
54767Ssjelinek #include "misc.h"
55767Ssjelinek #include "checkdev.h"
56*9958SSharath.Srinivasan@Sun.COM #include <sys/efi_partition.h>
57767Ssjelinek
58767Ssjelinek /* Function prototypes */
59767Ssjelinek #ifdef __STDC__
60767Ssjelinek
61767Ssjelinek static struct swaptable *getswapentries(void);
62767Ssjelinek static void freeswapentries(struct swaptable *);
63767Ssjelinek static int getpartition(char *pathname);
64767Ssjelinek static int checkpartitions(int bm_mounted);
65767Ssjelinek
66767Ssjelinek #else /* __STDC__ */
67767Ssjelinek
68767Ssjelinek static struct swaptable *getswapentries();
69767Ssjelinek static void freeswapentries();
70767Ssjelinek static int getpartition();
71767Ssjelinek static int checkpartitions();
72767Ssjelinek
73767Ssjelinek #endif /* __STDC__ */
74767Ssjelinek
75767Ssjelinek extern char *getfullname();
76767Ssjelinek
77767Ssjelinek static struct swaptable *
getswapentries(void)78767Ssjelinek getswapentries(void)
79767Ssjelinek {
80767Ssjelinek register struct swaptable *st;
81767Ssjelinek register struct swapent *swapent;
82767Ssjelinek int i, num;
83767Ssjelinek char fullpathname[MAXPATHLEN];
84767Ssjelinek
85767Ssjelinek /*
86767Ssjelinek * get the number of swap entries
87767Ssjelinek */
88767Ssjelinek if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) {
89767Ssjelinek err_print("swapctl error ");
90767Ssjelinek fullabort();
91767Ssjelinek }
92767Ssjelinek if (num == 0)
93767Ssjelinek return (NULL);
94767Ssjelinek if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int)))
95*9958SSharath.Srinivasan@Sun.COM == NULL) {
96767Ssjelinek err_print("getswapentries: malloc failed.\n");
97767Ssjelinek fullabort();
98767Ssjelinek }
99767Ssjelinek swapent = st->swt_ent;
100767Ssjelinek for (i = 0; i < num; i++, swapent++) {
101767Ssjelinek if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) {
102767Ssjelinek err_print("getswapentries: malloc failed.\n");
103767Ssjelinek fullabort();
104767Ssjelinek }
105767Ssjelinek }
106767Ssjelinek st->swt_n = num;
107767Ssjelinek if ((num = swapctl(SC_LIST, (void *)st)) == -1) {
108767Ssjelinek err_print("swapctl error ");
109767Ssjelinek fullabort();
110767Ssjelinek }
111767Ssjelinek swapent = st->swt_ent;
112767Ssjelinek for (i = 0; i < num; i++, swapent++) {
113767Ssjelinek if (*swapent->ste_path != '/') {
114767Ssjelinek (void) snprintf(fullpathname, sizeof (fullpathname),
115767Ssjelinek "/dev/%s", swapent->ste_path);
116767Ssjelinek (void) strcpy(swapent->ste_path, fullpathname);
117767Ssjelinek }
118767Ssjelinek }
119767Ssjelinek return (st);
120767Ssjelinek }
121767Ssjelinek
122767Ssjelinek static void
freeswapentries(st)123767Ssjelinek freeswapentries(st)
124767Ssjelinek struct swaptable *st;
125767Ssjelinek {
126767Ssjelinek register struct swapent *swapent;
127767Ssjelinek int i;
128767Ssjelinek
129767Ssjelinek swapent = st->swt_ent;
130767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++)
131767Ssjelinek free(swapent->ste_path);
132767Ssjelinek free(st);
133767Ssjelinek
134767Ssjelinek }
135767Ssjelinek
136767Ssjelinek /*
137767Ssjelinek * function getpartition:
138767Ssjelinek */
139767Ssjelinek static int
getpartition(pathname)140767Ssjelinek getpartition(pathname)
141767Ssjelinek char *pathname;
142767Ssjelinek {
143767Ssjelinek int mfd;
144767Ssjelinek struct dk_cinfo dkinfo;
145767Ssjelinek struct stat stbuf;
146767Ssjelinek char raw_device[MAXPATHLEN];
147767Ssjelinek int found = -1;
148767Ssjelinek
149767Ssjelinek /*
150767Ssjelinek * Map the block device name to the raw device name.
151767Ssjelinek * If it doesn't appear to be a device name, skip it.
152767Ssjelinek */
153767Ssjelinek if (match_substr(pathname, "/dev/") == 0)
154767Ssjelinek return (found);
155767Ssjelinek (void) strcpy(raw_device, "/dev/r");
156767Ssjelinek (void) strcat(raw_device, pathname + strlen("/dev/"));
157767Ssjelinek /*
158767Ssjelinek * Determine if this appears to be a disk device.
159767Ssjelinek * First attempt to open the device. If if fails, skip it.
160767Ssjelinek */
161767Ssjelinek if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
162767Ssjelinek return (found);
163767Ssjelinek }
164767Ssjelinek /*
165767Ssjelinek * Must be a character device
166767Ssjelinek */
167767Ssjelinek if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
168767Ssjelinek (void) close(mfd);
169767Ssjelinek return (found);
170767Ssjelinek }
171767Ssjelinek /*
172767Ssjelinek * Attempt to read the configuration info on the disk.
173767Ssjelinek */
174767Ssjelinek if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) {
175767Ssjelinek (void) close(mfd);
176767Ssjelinek return (found);
177767Ssjelinek }
178767Ssjelinek /*
179767Ssjelinek * Finished with the opened device
180767Ssjelinek */
181767Ssjelinek (void) close(mfd);
182767Ssjelinek
183767Ssjelinek /*
184767Ssjelinek * If it's not the disk we're interested in, it doesn't apply.
185767Ssjelinek */
186767Ssjelinek if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype ||
187767Ssjelinek cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum ||
188767Ssjelinek cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit ||
189767Ssjelinek strcmp(cur_disk->disk_dkinfo.dki_dname,
190767Ssjelinek dkinfo.dki_dname) != 0) {
191767Ssjelinek return (found);
192767Ssjelinek }
193767Ssjelinek
194767Ssjelinek /*
195767Ssjelinek * Extract the partition that is mounted.
196767Ssjelinek */
197767Ssjelinek return (PARTITION(stbuf.st_rdev));
198767Ssjelinek }
199767Ssjelinek
200767Ssjelinek /*
201767Ssjelinek * This Routine checks to see if there are partitions used for swapping overlaps
202767Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means
203767Ssjelinek * that the entire disk should be checked
204767Ssjelinek */
205767Ssjelinek int
checkswap(start,end)206767Ssjelinek checkswap(start, end)
207767Ssjelinek diskaddr_t start, end;
208767Ssjelinek {
209767Ssjelinek struct swaptable *st;
210767Ssjelinek struct swapent *swapent;
211767Ssjelinek int i;
212767Ssjelinek int found = 0;
213767Ssjelinek struct dk_map32 *map;
214767Ssjelinek int part;
215767Ssjelinek
216767Ssjelinek /*
217767Ssjelinek * If we are only checking part of the disk, the disk must
218767Ssjelinek * have a partition map to check against. If it doesn't,
219767Ssjelinek * we hope for the best.
220767Ssjelinek */
221767Ssjelinek if (cur_parts == NULL)
222767Ssjelinek return (0);
223767Ssjelinek
224767Ssjelinek /*
225767Ssjelinek * check for swap entries
226767Ssjelinek */
227767Ssjelinek st = getswapentries();
228767Ssjelinek /*
229767Ssjelinek * if there are no swap entries return.
230767Ssjelinek */
231767Ssjelinek if (st == (struct swaptable *)NULL)
232767Ssjelinek return (0);
233767Ssjelinek swapent = st->swt_ent;
234767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) {
235767Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) {
236767Ssjelinek if (start == UINT_MAX64) {
237767Ssjelinek found = -1;
238767Ssjelinek break;
239767Ssjelinek }
240767Ssjelinek map = &cur_parts->pinfo_map[part];
241767Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() +
242767Ssjelinek map->dkl_nblk)) || (end < (int)(map->dkl_cylno
243767Ssjelinek * spc()))) {
244767Ssjelinek continue;
245767Ssjelinek }
246767Ssjelinek found = -1;
247767Ssjelinek break;
248767Ssjelinek };
249767Ssjelinek }
250767Ssjelinek freeswapentries(st);
251767Ssjelinek /*
252767Ssjelinek * If we found trouble and we're running from a command file,
253767Ssjelinek * quit before doing something we really regret.
254767Ssjelinek */
255767Ssjelinek
256767Ssjelinek if (found && option_f) {
257767Ssjelinek err_print(
258767Ssjelinek "Operation on disks being used for swapping must be interactive.\n");
259767Ssjelinek cmdabort(SIGINT);
260767Ssjelinek }
261767Ssjelinek
262767Ssjelinek return (found);
263767Ssjelinek
264767Ssjelinek
265767Ssjelinek }
266767Ssjelinek /*
267767Ssjelinek * Determines if there are partitions that are a part of an SVM, VxVM, zpool
268767Ssjelinek * volume or a live upgrade device, overlapping a given portion of a disk.
269767Ssjelinek * Mounts and swap devices are checked in legacy format code.
270767Ssjelinek */
271767Ssjelinek int
checkdevinuse(char * cur_disk_path,diskaddr_t start,diskaddr_t end,int print,int check_label)272767Ssjelinek checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print,
273767Ssjelinek int check_label)
274767Ssjelinek {
275767Ssjelinek
276767Ssjelinek int error;
277767Ssjelinek int found = 0;
278767Ssjelinek int check = 0;
279767Ssjelinek int i;
280767Ssjelinek int bm_inuse = 0;
281767Ssjelinek int part = 0;
282767Ssjelinek uint64_t slice_start, slice_size;
283767Ssjelinek dm_descriptor_t *slices = NULL;
284767Ssjelinek nvlist_t *attrs = NULL;
285767Ssjelinek char *usage;
286767Ssjelinek char *name;
287767Ssjelinek
288767Ssjelinek /*
2891107Ssjelinek * If the user does not want to do in use checking, return immediately.
2901107Ssjelinek * Normally, this is handled in libdiskmgt. For format, there is more
2911107Ssjelinek * processing required, so we want to bypass the in use checking
2921107Ssjelinek * here.
2931107Ssjelinek */
2941107Ssjelinek
2951107Ssjelinek if (NOINUSE_SET)
2961107Ssjelinek return (0);
2971107Ssjelinek
2981107Ssjelinek /*
2992083Szl149053 * Skip if it is not a real disk
3002083Szl149053 *
3012083Szl149053 * There could be two kinds of strings in cur_disk_path
3022083Szl149053 * One starts with c?t?d?, while the other is a absolute path of a
3032083Szl149053 * block device file.
3042083Szl149053 */
3052083Szl149053
3062083Szl149053 if (*cur_disk_path != 'c') {
3072083Szl149053 struct stat stbuf;
3082083Szl149053 char majorname[16];
3092083Szl149053 major_t majornum;
3102083Szl149053
3112083Szl149053 (void) stat(cur_disk_path, &stbuf);
3122083Szl149053 majornum = major(stbuf.st_rdev);
3132083Szl149053 (void) modctl(MODGETNAME, majorname, sizeof (majorname),
314*9958SSharath.Srinivasan@Sun.COM &majornum);
3152083Szl149053
3162083Szl149053 if (strcmp(majorname, "sd"))
3172083Szl149053 if (strcmp(majorname, "ssd"))
3182083Szl149053 if (strcmp(majorname, "cmdk"))
3192083Szl149053 return (0);
3202083Szl149053 }
3212083Szl149053
3222083Szl149053 /*
3232083Szl149053 * Truncate the characters following "d*", such as "s*" or "p*"
3242083Szl149053 */
3252083Szl149053 cur_disk_path = basename(cur_disk_path);
3262083Szl149053 name = strrchr(cur_disk_path, 'd');
3272083Szl149053 if (name) {
3282083Szl149053 name++;
329*9958SSharath.Srinivasan@Sun.COM for (; (*name <= '9') && (*name >= '0'); name++) {
330*9958SSharath.Srinivasan@Sun.COM }
3312083Szl149053 *name = (char)0;
3322083Szl149053 }
3332083Szl149053
3342083Szl149053
3352083Szl149053 /*
336767Ssjelinek * For format, we get basic 'in use' details from libdiskmgt. After
337767Ssjelinek * that we must do the appropriate checking to see if the 'in use'
338767Ssjelinek * details require a bit of additional work.
339767Ssjelinek */
340767Ssjelinek
341767Ssjelinek dm_get_slices(cur_disk_path, &slices, &error);
342767Ssjelinek if (error) {
3436798Sny155746 /*
3446798Sny155746 * If ENODEV, it actually means the device is not in use.
3456798Sny155746 * We will return 0 without displaying error.
3466798Sny155746 */
3476798Sny155746 if (error != ENODEV) {
3486798Sny155746 err_print("Error occurred with device in use"
3496798Sny155746 "checking: %s\n", strerror(error));
3506798Sny155746 return (found);
3516798Sny155746 }
352767Ssjelinek }
353767Ssjelinek if (slices == NULL)
354767Ssjelinek return (found);
355767Ssjelinek
356767Ssjelinek for (i = 0; slices[i] != NULL; i++) {
357767Ssjelinek /*
358767Ssjelinek * If we are checking the whole disk
359767Ssjelinek * then any and all in use data is
360767Ssjelinek * relevant.
361767Ssjelinek */
362767Ssjelinek if (start == UINT_MAX64) {
363767Ssjelinek name = dm_get_name(slices[i], &error);
364767Ssjelinek if (error != 0 || !name) {
365767Ssjelinek err_print("Error occurred with device "
366*9958SSharath.Srinivasan@Sun.COM "in use checking: %s\n", strerror(error));
367767Ssjelinek continue;
368767Ssjelinek }
369767Ssjelinek if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) ||
370767Ssjelinek error) {
371767Ssjelinek if (error != 0) {
372767Ssjelinek dm_free_name(name);
373767Ssjelinek name = NULL;
374*9958SSharath.Srinivasan@Sun.COM err_print("Error occurred with "
375*9958SSharath.Srinivasan@Sun.COM "device in use checking: "
376*9958SSharath.Srinivasan@Sun.COM "%s\n", strerror(error));
377767Ssjelinek continue;
378767Ssjelinek }
379767Ssjelinek dm_free_name(name);
380767Ssjelinek name = NULL;
381767Ssjelinek /*
382767Ssjelinek * If this is a dump device, then it is
383767Ssjelinek * a failure. You cannot format a slice
384767Ssjelinek * that is a dedicated dump device.
385767Ssjelinek */
386767Ssjelinek
387767Ssjelinek if (strstr(usage, DM_USE_DUMP)) {
388767Ssjelinek if (print) {
389767Ssjelinek err_print(usage);
390767Ssjelinek free(usage);
391767Ssjelinek }
392767Ssjelinek dm_free_descriptors(slices);
393767Ssjelinek return (1);
394767Ssjelinek }
395767Ssjelinek /*
396767Ssjelinek * We really found a device that is in use.
397767Ssjelinek * Set 'found' for the return value, and set
398767Ssjelinek * 'check' to indicate below that we must
399767Ssjelinek * get the partition number to set bm_inuse
400767Ssjelinek * in the event we are trying to label this
401767Ssjelinek * device. check_label is set when we are
402767Ssjelinek * checking modifications for in use slices
403767Ssjelinek * on the device.
404767Ssjelinek */
405767Ssjelinek found ++;
406767Ssjelinek check = 1;
407767Ssjelinek if (print) {
408767Ssjelinek err_print(usage);
409767Ssjelinek free(usage);
410767Ssjelinek }
411767Ssjelinek }
412767Ssjelinek } else {
413767Ssjelinek /*
414767Ssjelinek * Before getting the in use data, verify that the
415767Ssjelinek * current slice is within the range we are checking.
416767Ssjelinek */
417767Ssjelinek attrs = dm_get_attributes(slices[i], &error);
418767Ssjelinek if (error) {
419767Ssjelinek err_print("Error occurred with device in use "
420767Ssjelinek "checking: %s\n", strerror(error));
421767Ssjelinek continue;
422767Ssjelinek }
423767Ssjelinek if (attrs == NULL) {
424767Ssjelinek continue;
425767Ssjelinek }
426767Ssjelinek
427767Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_START,
428767Ssjelinek &slice_start);
429767Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_SIZE,
430767Ssjelinek &slice_size);
431767Ssjelinek if (start >= (slice_start + slice_size) ||
432767Ssjelinek (end < slice_start)) {
433767Ssjelinek nvlist_free(attrs);
434767Ssjelinek attrs = NULL;
435767Ssjelinek continue;
436767Ssjelinek }
437767Ssjelinek name = dm_get_name(slices[i], &error);
438767Ssjelinek if (error != 0 || !name) {
439767Ssjelinek err_print("Error occurred with device "
440*9958SSharath.Srinivasan@Sun.COM "in use checking: %s\n", strerror(error));
441767Ssjelinek nvlist_free(attrs);
442767Ssjelinek attrs = NULL;
443767Ssjelinek continue;
444767Ssjelinek }
445767Ssjelinek if (dm_inuse(name, &usage,
446767Ssjelinek DM_WHO_FORMAT, &error) || error) {
447767Ssjelinek if (error != 0) {
448767Ssjelinek dm_free_name(name);
449767Ssjelinek name = NULL;
450*9958SSharath.Srinivasan@Sun.COM err_print("Error occurred with "
451*9958SSharath.Srinivasan@Sun.COM "device in use checking: "
452*9958SSharath.Srinivasan@Sun.COM "%s\n", strerror(error));
453767Ssjelinek nvlist_free(attrs);
454767Ssjelinek attrs = NULL;
455767Ssjelinek continue;
456767Ssjelinek }
457767Ssjelinek dm_free_name(name);
458767Ssjelinek name = NULL;
459767Ssjelinek /*
460767Ssjelinek * If this is a dump device, then it is
461767Ssjelinek * a failure. You cannot format a slice
462767Ssjelinek * that is a dedicated dump device.
463767Ssjelinek */
464767Ssjelinek if (strstr(usage, DM_USE_DUMP)) {
465767Ssjelinek if (print) {
466767Ssjelinek err_print(usage);
467767Ssjelinek free(usage);
468767Ssjelinek }
469767Ssjelinek dm_free_descriptors(slices);
470767Ssjelinek nvlist_free(attrs);
471767Ssjelinek return (1);
472767Ssjelinek }
473767Ssjelinek /*
474767Ssjelinek * We really found a device that is in use.
475767Ssjelinek * Set 'found' for the return value, and set
476767Ssjelinek * 'check' to indicate below that we must
477767Ssjelinek * get the partition number to set bm_inuse
478767Ssjelinek * in the event we are trying to label this
479767Ssjelinek * device. check_label is set when we are
480767Ssjelinek * checking modifications for in use slices
481767Ssjelinek * on the device.
482767Ssjelinek */
483767Ssjelinek found ++;
484767Ssjelinek check = 1;
485767Ssjelinek if (print) {
486767Ssjelinek err_print(usage);
487767Ssjelinek free(usage);
488767Ssjelinek }
489767Ssjelinek }
490767Ssjelinek }
491767Ssjelinek /*
492767Ssjelinek * If check is set it means we found a slice(the current slice)
493767Ssjelinek * on this device in use in some way. We potentially want
494767Ssjelinek * to check this slice when labeling is
495767Ssjelinek * requested. We set bm_inuse with this partition value
496767Ssjelinek * for use later if check_label was set when called.
497767Ssjelinek */
498767Ssjelinek if (check) {
499767Ssjelinek name = dm_get_name(slices[i], &error);
500767Ssjelinek if (error != 0 || !name) {
501767Ssjelinek err_print("Error occurred with device "
502*9958SSharath.Srinivasan@Sun.COM "in use checking: %s\n", strerror(error));
503767Ssjelinek nvlist_free(attrs);
504767Ssjelinek attrs = NULL;
505767Ssjelinek continue;
506767Ssjelinek }
507767Ssjelinek part = getpartition(name);
508767Ssjelinek dm_free_name(name);
509767Ssjelinek name = NULL;
510767Ssjelinek if (part != -1) {
511767Ssjelinek bm_inuse |= 1 << part;
512767Ssjelinek }
513767Ssjelinek check = 0;
514767Ssjelinek }
515767Ssjelinek /*
516767Ssjelinek * If we have attributes then we have successfully
517767Ssjelinek * found the slice we were looking for and we also
518767Ssjelinek * know this means we are not searching the whole
519767Ssjelinek * disk so break out of the loop
520767Ssjelinek * now.
521767Ssjelinek */
522767Ssjelinek if (attrs) {
523767Ssjelinek nvlist_free(attrs);
524767Ssjelinek break;
525767Ssjelinek }
526767Ssjelinek }
527767Ssjelinek
528767Ssjelinek if (slices) {
529767Ssjelinek dm_free_descriptors(slices);
530767Ssjelinek }
531767Ssjelinek
532767Ssjelinek /*
533767Ssjelinek * The user is trying to label the disk. We have to do special
534767Ssjelinek * checking here to ensure they are not trying to modify a slice
535767Ssjelinek * that is in use in an incompatible way.
536767Ssjelinek */
537767Ssjelinek if (check_label && bm_inuse) {
538767Ssjelinek /*
539767Ssjelinek * !0 indicates that we found a
540767Ssjelinek * problem. In this case, we have overloaded
541767Ssjelinek * the use of checkpartitions to work for
542767Ssjelinek * in use devices. bm_inuse is representative
543767Ssjelinek * of the slice that is in use, not that
544767Ssjelinek * is mounted as is in the case of the normal
545767Ssjelinek * use of checkpartitions.
546767Ssjelinek *
547767Ssjelinek * The call to checkpartitions will return !0 if
548767Ssjelinek * we are trying to shrink a device that we have found
549767Ssjelinek * to be in use above.
550767Ssjelinek */
551767Ssjelinek return (checkpartitions(bm_inuse));
552767Ssjelinek }
553767Ssjelinek
554767Ssjelinek return (found);
555767Ssjelinek }
556767Ssjelinek /*
557767Ssjelinek * This routine checks to see if there are mounted partitions overlapping
558767Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means
559767Ssjelinek * that the entire disk should be checked.
560767Ssjelinek */
561767Ssjelinek int
checkmount(start,end)562767Ssjelinek checkmount(start, end)
563767Ssjelinek diskaddr_t start, end;
564767Ssjelinek {
565767Ssjelinek FILE *fp;
566767Ssjelinek int found = 0;
567767Ssjelinek struct dk_map32 *map;
568767Ssjelinek int part;
569767Ssjelinek struct mnttab mnt_record;
570767Ssjelinek struct mnttab *mp = &mnt_record;
571767Ssjelinek
572767Ssjelinek /*
573767Ssjelinek * If we are only checking part of the disk, the disk must
574767Ssjelinek * have a partition map to check against. If it doesn't,
575767Ssjelinek * we hope for the best.
576767Ssjelinek */
577767Ssjelinek if (cur_parts == NULL)
578767Ssjelinek return (0);
579767Ssjelinek
580767Ssjelinek /*
581767Ssjelinek * Lock out interrupts because of the mntent protocol.
582767Ssjelinek */
583767Ssjelinek enter_critical();
584767Ssjelinek /*
585767Ssjelinek * Open the mount table.
586767Ssjelinek */
587767Ssjelinek fp = fopen(MNTTAB, "r");
588767Ssjelinek if (fp == NULL) {
589767Ssjelinek err_print("Unable to open mount table.\n");
590767Ssjelinek fullabort();
591767Ssjelinek }
592767Ssjelinek /*
593767Ssjelinek * Loop through the mount table until we run out of entries.
594767Ssjelinek */
595767Ssjelinek while ((getmntent(fp, mp)) != -1) {
596767Ssjelinek
597767Ssjelinek if ((part = getpartition(mp->mnt_special)) == -1)
598767Ssjelinek continue;
599767Ssjelinek
600767Ssjelinek /*
601767Ssjelinek * It's a mount on the disk we're checking. If we are
602767Ssjelinek * checking whole disk, then we found trouble. We can
603767Ssjelinek * quit searching.
604767Ssjelinek */
605767Ssjelinek if (start == UINT_MAX64) {
606767Ssjelinek found = -1;
607767Ssjelinek break;
608767Ssjelinek }
609767Ssjelinek
610767Ssjelinek /*
611767Ssjelinek * If the partition overlaps the zone we're checking,
612767Ssjelinek * then we found trouble. We can quit searching.
613767Ssjelinek */
614767Ssjelinek map = &cur_parts->pinfo_map[part];
615767Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) ||
616767Ssjelinek (end < (int)(map->dkl_cylno * spc()))) {
617767Ssjelinek continue;
618767Ssjelinek }
619767Ssjelinek found = -1;
620767Ssjelinek break;
621767Ssjelinek }
622767Ssjelinek /*
623767Ssjelinek * Close down the mount table.
624767Ssjelinek */
625767Ssjelinek (void) fclose(fp);
626767Ssjelinek exit_critical();
627767Ssjelinek
628767Ssjelinek /*
629767Ssjelinek * If we found trouble and we're running from a command file,
630767Ssjelinek * quit before doing something we really regret.
631767Ssjelinek */
632767Ssjelinek
633767Ssjelinek if (found && option_f) {
634767Ssjelinek err_print("Operation on mounted disks must be interactive.\n");
635767Ssjelinek cmdabort(SIGINT);
636767Ssjelinek }
637767Ssjelinek /*
638767Ssjelinek * Return the result.
639767Ssjelinek */
640767Ssjelinek return (found);
641767Ssjelinek }
642767Ssjelinek
643767Ssjelinek int
check_label_with_swap()644767Ssjelinek check_label_with_swap()
645767Ssjelinek {
646767Ssjelinek int i;
647767Ssjelinek struct swaptable *st;
648767Ssjelinek struct swapent *swapent;
649767Ssjelinek int part;
650767Ssjelinek int bm_swap = 0;
651767Ssjelinek
652767Ssjelinek /*
653767Ssjelinek * If we are only checking part of the disk, the disk must
654767Ssjelinek * have a partition map to check against. If it doesn't,
655767Ssjelinek * we hope for the best.
656767Ssjelinek */
657767Ssjelinek if (cur_parts == NULL)
658767Ssjelinek return (0); /* Will be checked later */
659767Ssjelinek
660767Ssjelinek /*
661767Ssjelinek * Check for swap entries
662767Ssjelinek */
663767Ssjelinek st = getswapentries();
664767Ssjelinek /*
665767Ssjelinek * if there are no swap entries return.
666767Ssjelinek */
667767Ssjelinek if (st == (struct swaptable *)NULL)
668767Ssjelinek return (0);
669767Ssjelinek swapent = st->swt_ent;
670767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++)
671767Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1)
672767Ssjelinek bm_swap |= (1 << part);
673767Ssjelinek freeswapentries(st);
674767Ssjelinek
675767Ssjelinek return (checkpartitions(bm_swap));
676767Ssjelinek }
677767Ssjelinek
678767Ssjelinek /*
679767Ssjelinek * Check the new label with the existing label on the disk,
680767Ssjelinek * to make sure that any mounted partitions are not being
681767Ssjelinek * affected by writing the new label.
682767Ssjelinek */
683767Ssjelinek int
check_label_with_mount()684767Ssjelinek check_label_with_mount()
685767Ssjelinek {
686767Ssjelinek FILE *fp;
687767Ssjelinek int part;
688767Ssjelinek struct mnttab mnt_record;
689767Ssjelinek struct mnttab *mp = &mnt_record;
690767Ssjelinek int bm_mounted = 0;
691767Ssjelinek
692767Ssjelinek
693767Ssjelinek /*
694767Ssjelinek * If we are only checking part of the disk, the disk must
695767Ssjelinek * have a partition map to check against. If it doesn't,
696767Ssjelinek * we hope for the best.
697767Ssjelinek */
698767Ssjelinek if (cur_parts == NULL)
699767Ssjelinek return (0); /* Will be checked later */
700767Ssjelinek
701767Ssjelinek /*
702767Ssjelinek * Lock out interrupts because of the mntent protocol.
703767Ssjelinek */
704767Ssjelinek enter_critical();
705767Ssjelinek /*
706767Ssjelinek * Open the mount table.
707767Ssjelinek */
708767Ssjelinek fp = fopen(MNTTAB, "r");
709767Ssjelinek if (fp == NULL) {
710767Ssjelinek err_print("Unable to open mount table.\n");
711767Ssjelinek fullabort();
712767Ssjelinek }
713767Ssjelinek /*
714767Ssjelinek * Loop through the mount table until we run out of entries.
715767Ssjelinek */
716767Ssjelinek while ((getmntent(fp, mp)) != -1) {
717767Ssjelinek if ((part = getpartition(mp->mnt_special)) != -1)
718767Ssjelinek bm_mounted |= (1 << part);
719767Ssjelinek }
720767Ssjelinek /*
721767Ssjelinek * Close down the mount table.
722767Ssjelinek */
723767Ssjelinek (void) fclose(fp);
724767Ssjelinek exit_critical();
725767Ssjelinek
726767Ssjelinek return (checkpartitions(bm_mounted));
727767Ssjelinek
728767Ssjelinek }
729767Ssjelinek
730767Ssjelinek /*
731767Ssjelinek * This Routine checks if any partitions specified
732767Ssjelinek * are affected by writing the new label
733767Ssjelinek */
734767Ssjelinek static int
checkpartitions(int bm_mounted)735767Ssjelinek checkpartitions(int bm_mounted)
736767Ssjelinek {
737767Ssjelinek struct dk_map32 *n;
738767Ssjelinek struct dk_map *o;
739767Ssjelinek struct dk_allmap old_map;
740767Ssjelinek int i, found = 0;
741*9958SSharath.Srinivasan@Sun.COM struct partition64 o_efi;
742767Ssjelinek
743767Ssjelinek /*
744767Ssjelinek * Now we need to check that the current partition list and the
745767Ssjelinek * previous partition list (which there must be if we actually
746767Ssjelinek * have partitions mounted) overlap in any way on the mounted
747767Ssjelinek * partitions
748767Ssjelinek */
749767Ssjelinek
750767Ssjelinek /*
751*9958SSharath.Srinivasan@Sun.COM * Check if the user wants to online-label an
752*9958SSharath.Srinivasan@Sun.COM * existing EFI label.
753767Ssjelinek */
754*9958SSharath.Srinivasan@Sun.COM if (cur_label == L_TYPE_EFI) {
755*9958SSharath.Srinivasan@Sun.COM for (i = 0; i < EFI_NUMPAR; i++) {
756*9958SSharath.Srinivasan@Sun.COM if (bm_mounted & (1 << i)) {
757*9958SSharath.Srinivasan@Sun.COM o_efi.p_partno = i;
758*9958SSharath.Srinivasan@Sun.COM if (ioctl(cur_file, DKIOCPARTITION, &o_efi)
759*9958SSharath.Srinivasan@Sun.COM == -1) {
760*9958SSharath.Srinivasan@Sun.COM err_print("Unable to get information "
761*9958SSharath.Srinivasan@Sun.COM "for EFI partition %d.\n", i);
762*9958SSharath.Srinivasan@Sun.COM return (-1);
763*9958SSharath.Srinivasan@Sun.COM }
764*9958SSharath.Srinivasan@Sun.COM
765*9958SSharath.Srinivasan@Sun.COM /*
766*9958SSharath.Srinivasan@Sun.COM * Partition can grow or remain same.
767*9958SSharath.Srinivasan@Sun.COM */
768*9958SSharath.Srinivasan@Sun.COM if (o_efi.p_start == cur_parts->etoc->
769*9958SSharath.Srinivasan@Sun.COM efi_parts[i].p_start && o_efi.p_size
770*9958SSharath.Srinivasan@Sun.COM <= cur_parts->etoc->efi_parts[i].p_size) {
771*9958SSharath.Srinivasan@Sun.COM continue;
772*9958SSharath.Srinivasan@Sun.COM }
773*9958SSharath.Srinivasan@Sun.COM
774*9958SSharath.Srinivasan@Sun.COM found = -1;
775*9958SSharath.Srinivasan@Sun.COM }
776*9958SSharath.Srinivasan@Sun.COM if (found)
777*9958SSharath.Srinivasan@Sun.COM break;
778*9958SSharath.Srinivasan@Sun.COM }
779*9958SSharath.Srinivasan@Sun.COM
780*9958SSharath.Srinivasan@Sun.COM } else {
781*9958SSharath.Srinivasan@Sun.COM
782*9958SSharath.Srinivasan@Sun.COM /*
783*9958SSharath.Srinivasan@Sun.COM * Get the "real" (on-disk) version of the partition table
784*9958SSharath.Srinivasan@Sun.COM */
785*9958SSharath.Srinivasan@Sun.COM if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) {
786*9958SSharath.Srinivasan@Sun.COM err_print("Unable to get current partition map.\n");
787*9958SSharath.Srinivasan@Sun.COM return (-1);
788*9958SSharath.Srinivasan@Sun.COM }
789*9958SSharath.Srinivasan@Sun.COM for (i = 0; i < NDKMAP; i++) {
790*9958SSharath.Srinivasan@Sun.COM if (bm_mounted & (1 << i)) {
791*9958SSharath.Srinivasan@Sun.COM /*
792*9958SSharath.Srinivasan@Sun.COM * This partition is mounted
793*9958SSharath.Srinivasan@Sun.COM */
794*9958SSharath.Srinivasan@Sun.COM o = &old_map.dka_map[i];
795*9958SSharath.Srinivasan@Sun.COM n = &cur_parts->pinfo_map[i];
796767Ssjelinek #ifdef DEBUG
797*9958SSharath.Srinivasan@Sun.COM fmt_print(
798767Ssjelinek "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE);
799767Ssjelinek #endif
800*9958SSharath.Srinivasan@Sun.COM /*
801*9958SSharath.Srinivasan@Sun.COM * If partition is identical, we're fine.
802*9958SSharath.Srinivasan@Sun.COM * If the partition grows, we're also fine,
803*9958SSharath.Srinivasan@Sun.COM * because the routines in partition.c check
804*9958SSharath.Srinivasan@Sun.COM * for overflow. It will (ultimately) be up
805*9958SSharath.Srinivasan@Sun.COM * to the routines in partition.c to warn
806*9958SSharath.Srinivasan@Sun.COM * about creation of overlapping partitions.
807*9958SSharath.Srinivasan@Sun.COM */
808*9958SSharath.Srinivasan@Sun.COM if (o->dkl_cylno == n->dkl_cylno &&
809*9958SSharath.Srinivasan@Sun.COM o->dkl_nblk <= n->dkl_nblk) {
810767Ssjelinek #ifdef DEBUG
811*9958SSharath.Srinivasan@Sun.COM if (o->dkl_nblk < n->dkl_nblk) {
812*9958SSharath.Srinivasan@Sun.COM fmt_print(
813767Ssjelinek "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk);
814*9958SSharath.Srinivasan@Sun.COM }
815*9958SSharath.Srinivasan@Sun.COM fmt_print("\n");
816767Ssjelinek #endif
817*9958SSharath.Srinivasan@Sun.COM continue;
818*9958SSharath.Srinivasan@Sun.COM }
819767Ssjelinek #ifdef DEBUG
820*9958SSharath.Srinivasan@Sun.COM fmt_print("- changes; old (%d,%d)->new "
821*9958SSharath.Srinivasan@Sun.COM "(%d,%d)\n", o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, n->dkl_nblk);
822767Ssjelinek #endif
823*9958SSharath.Srinivasan@Sun.COM found = -1;
824*9958SSharath.Srinivasan@Sun.COM }
825*9958SSharath.Srinivasan@Sun.COM if (found)
826*9958SSharath.Srinivasan@Sun.COM break;
827767Ssjelinek }
828767Ssjelinek }
829767Ssjelinek
830767Ssjelinek /*
831767Ssjelinek * If we found trouble and we're running from a command file,
832767Ssjelinek * quit before doing something we really regret.
833767Ssjelinek */
834767Ssjelinek
835767Ssjelinek if (found && option_f) {
836767Ssjelinek err_print("Operation on mounted disks or \
837767Ssjelinek disks currently being used for swapping must be interactive.\n");
838767Ssjelinek cmdabort(SIGINT);
839767Ssjelinek }
840767Ssjelinek /*
841767Ssjelinek * Return the result.
842767Ssjelinek */
843767Ssjelinek return (found);
844767Ssjelinek }
845