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