xref: /onnv-gate/usr/src/cmd/format/checkdev.c (revision 9958:108c82b6bad3)
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