xref: /onnv-gate/usr/src/cmd/format/checkdev.c (revision 1107:1f78db36dee1)
1767Ssjelinek /*
2767Ssjelinek  * CDDL HEADER START
3767Ssjelinek  *
4767Ssjelinek  * The contents of this file are subject to the terms of the
5767Ssjelinek  * Common Development and Distribution License, Version 1.0 only
6767Ssjelinek  * (the "License").  You may not use this file except in compliance
7767Ssjelinek  * with the License.
8767Ssjelinek  *
9767Ssjelinek  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10767Ssjelinek  * or http://www.opensolaris.org/os/licensing.
11767Ssjelinek  * See the License for the specific language governing permissions
12767Ssjelinek  * and limitations under the License.
13767Ssjelinek  *
14767Ssjelinek  * When distributing Covered Code, include this CDDL HEADER in each
15767Ssjelinek  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16767Ssjelinek  * If applicable, add the following below this CDDL HEADER, with the
17767Ssjelinek  * fields enclosed by brackets "[]" replaced with your own identifying
18767Ssjelinek  * information: Portions Copyright [yyyy] [name of copyright owner]
19767Ssjelinek  *
20767Ssjelinek  * CDDL HEADER END
21767Ssjelinek  */
22767Ssjelinek /*
23767Ssjelinek  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24767Ssjelinek  * Use is subject to license terms.
25767Ssjelinek  */
26767Ssjelinek 
27767Ssjelinek 
28767Ssjelinek #pragma ident	"%Z%%M%	%I%	%E% SMI"
29767Ssjelinek 
30767Ssjelinek /*
31767Ssjelinek  * This file contains miscellaneous device validation routines.
32767Ssjelinek  */
33767Ssjelinek 
34767Ssjelinek #include "global.h"
35767Ssjelinek #include <sys/mnttab.h>
36767Ssjelinek #include <sys/mntent.h>
37767Ssjelinek #include <sys/autoconf.h>
38767Ssjelinek 
39767Ssjelinek #include <signal.h>
40767Ssjelinek #include <malloc.h>
41767Ssjelinek #include <unistd.h>
42767Ssjelinek #include <string.h>
43767Ssjelinek #include <errno.h>
44767Ssjelinek #include <fcntl.h>
45767Ssjelinek #include <sys/ioctl.h>
46767Ssjelinek #include <sys/fcntl.h>
47767Ssjelinek #include <sys/stat.h>
48767Ssjelinek #include <sys/swap.h>
49767Ssjelinek #include <sys/sysmacros.h>
50767Ssjelinek #include <ctype.h>
51767Ssjelinek #include <libdiskmgt.h>
52767Ssjelinek #include <libnvpair.h>
53767Ssjelinek #include "misc.h"
54767Ssjelinek #include "checkdev.h"
55767Ssjelinek 
56767Ssjelinek /* Function prototypes */
57767Ssjelinek #ifdef	__STDC__
58767Ssjelinek 
59767Ssjelinek static struct 	swaptable *getswapentries(void);
60767Ssjelinek static void 	freeswapentries(struct swaptable *);
61767Ssjelinek static int	getpartition(char *pathname);
62767Ssjelinek static int 	checkpartitions(int bm_mounted);
63767Ssjelinek 
64767Ssjelinek #else	/* __STDC__ */
65767Ssjelinek 
66767Ssjelinek static struct swaptable *getswapentries();
67767Ssjelinek static void freeswapentries();
68767Ssjelinek static int	getpartition();
69767Ssjelinek static int 	checkpartitions();
70767Ssjelinek 
71767Ssjelinek #endif	/* __STDC__ */
72767Ssjelinek 
73767Ssjelinek extern char	*getfullname();
74767Ssjelinek 
75767Ssjelinek static struct swaptable *
76767Ssjelinek getswapentries(void)
77767Ssjelinek {
78767Ssjelinek 	register struct swaptable *st;
79767Ssjelinek 	register struct swapent *swapent;
80767Ssjelinek 	int	i, num;
81767Ssjelinek 	char	fullpathname[MAXPATHLEN];
82767Ssjelinek 
83767Ssjelinek 	/*
84767Ssjelinek 	 * get the number of swap entries
85767Ssjelinek 	 */
86767Ssjelinek 	if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) {
87767Ssjelinek 		err_print("swapctl error ");
88767Ssjelinek 		fullabort();
89767Ssjelinek 	}
90767Ssjelinek 	if (num == 0)
91767Ssjelinek 		return (NULL);
92767Ssjelinek 	if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int)))
93767Ssjelinek 			== NULL) {
94767Ssjelinek 		err_print("getswapentries: malloc  failed.\n");
95767Ssjelinek 		fullabort();
96767Ssjelinek 	}
97767Ssjelinek 	swapent = st->swt_ent;
98767Ssjelinek 	for (i = 0; i < num; i++, swapent++) {
99767Ssjelinek 		if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) {
100767Ssjelinek 			err_print("getswapentries: malloc  failed.\n");
101767Ssjelinek 			fullabort();
102767Ssjelinek 		}
103767Ssjelinek 	}
104767Ssjelinek 	st->swt_n = num;
105767Ssjelinek 	if ((num = swapctl(SC_LIST, (void *)st)) == -1) {
106767Ssjelinek 		err_print("swapctl error ");
107767Ssjelinek 		fullabort();
108767Ssjelinek 	}
109767Ssjelinek 	swapent = st->swt_ent;
110767Ssjelinek 	for (i = 0; i < num; i++, swapent++) {
111767Ssjelinek 		if (*swapent->ste_path != '/') {
112767Ssjelinek 			(void) snprintf(fullpathname, sizeof (fullpathname),
113767Ssjelinek 			    "/dev/%s", swapent->ste_path);
114767Ssjelinek 			(void) strcpy(swapent->ste_path, fullpathname);
115767Ssjelinek 		}
116767Ssjelinek 	}
117767Ssjelinek 	return (st);
118767Ssjelinek }
119767Ssjelinek 
120767Ssjelinek static void
121767Ssjelinek freeswapentries(st)
122767Ssjelinek struct swaptable *st;
123767Ssjelinek {
124767Ssjelinek 	register struct swapent *swapent;
125767Ssjelinek 	int i;
126767Ssjelinek 
127767Ssjelinek 	swapent = st->swt_ent;
128767Ssjelinek 	for (i = 0; i < st->swt_n; i++, swapent++)
129767Ssjelinek 		free(swapent->ste_path);
130767Ssjelinek 	free(st);
131767Ssjelinek 
132767Ssjelinek }
133767Ssjelinek 
134767Ssjelinek /*
135767Ssjelinek  *  function getpartition:
136767Ssjelinek  */
137767Ssjelinek static int
138767Ssjelinek getpartition(pathname)
139767Ssjelinek char *pathname;
140767Ssjelinek {
141767Ssjelinek 	int		mfd;
142767Ssjelinek 	struct dk_cinfo dkinfo;
143767Ssjelinek 	struct stat	stbuf;
144767Ssjelinek 	char		raw_device[MAXPATHLEN];
145767Ssjelinek 	int		found = -1;
146767Ssjelinek 
147767Ssjelinek 	/*
148767Ssjelinek 	 * Map the block device name to the raw device name.
149767Ssjelinek 	 * If it doesn't appear to be a device name, skip it.
150767Ssjelinek 	 */
151767Ssjelinek 	if (match_substr(pathname, "/dev/") == 0)
152767Ssjelinek 		return (found);
153767Ssjelinek 	(void) strcpy(raw_device, "/dev/r");
154767Ssjelinek 	(void) strcat(raw_device, pathname + strlen("/dev/"));
155767Ssjelinek 	/*
156767Ssjelinek 	 * Determine if this appears to be a disk device.
157767Ssjelinek 	 * First attempt to open the device.  If if fails, skip it.
158767Ssjelinek 	 */
159767Ssjelinek 	if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
160767Ssjelinek 		return (found);
161767Ssjelinek 	}
162767Ssjelinek 	/*
163767Ssjelinek 	 * Must be a character device
164767Ssjelinek 	 */
165767Ssjelinek 	if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
166767Ssjelinek 		(void) close(mfd);
167767Ssjelinek 		return (found);
168767Ssjelinek 	}
169767Ssjelinek 	/*
170767Ssjelinek 	 * Attempt to read the configuration info on the disk.
171767Ssjelinek 	 */
172767Ssjelinek 	if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) {
173767Ssjelinek 		(void) close(mfd);
174767Ssjelinek 		return (found);
175767Ssjelinek 	}
176767Ssjelinek 	/*
177767Ssjelinek 	 * Finished with the opened device
178767Ssjelinek 	 */
179767Ssjelinek 	(void) close(mfd);
180767Ssjelinek 
181767Ssjelinek 	/*
182767Ssjelinek 	 * If it's not the disk we're interested in, it doesn't apply.
183767Ssjelinek 	 */
184767Ssjelinek 	if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype ||
185767Ssjelinek 		cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum ||
186767Ssjelinek 		cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit ||
187767Ssjelinek 		strcmp(cur_disk->disk_dkinfo.dki_dname,
188767Ssjelinek 				dkinfo.dki_dname) != 0) {
189767Ssjelinek 		return (found);
190767Ssjelinek 	}
191767Ssjelinek 
192767Ssjelinek 	/*
193767Ssjelinek 	 *  Extract the partition that is mounted.
194767Ssjelinek 	 */
195767Ssjelinek 	return (PARTITION(stbuf.st_rdev));
196767Ssjelinek }
197767Ssjelinek 
198767Ssjelinek /*
199767Ssjelinek  * This Routine checks to see if there are partitions used for swapping overlaps
200767Ssjelinek  * a given portion of a disk. If the start parameter is < 0, it means
201767Ssjelinek  * that the entire disk should be checked
202767Ssjelinek  */
203767Ssjelinek int
204767Ssjelinek checkswap(start, end)
205767Ssjelinek 	diskaddr_t start, end;
206767Ssjelinek {
207767Ssjelinek 	struct swaptable *st;
208767Ssjelinek 	struct swapent *swapent;
209767Ssjelinek 	int		i;
210767Ssjelinek 	int		found = 0;
211767Ssjelinek 	struct dk_map32	*map;
212767Ssjelinek 	int		part;
213767Ssjelinek 
214767Ssjelinek 	/*
215767Ssjelinek 	 * If we are only checking part of the disk, the disk must
216767Ssjelinek 	 * have a partition map to check against.  If it doesn't,
217767Ssjelinek 	 * we hope for the best.
218767Ssjelinek 	 */
219767Ssjelinek 	if (cur_parts == NULL)
220767Ssjelinek 		return (0);
221767Ssjelinek 
222767Ssjelinek 	/*
223767Ssjelinek 	 * check for swap entries
224767Ssjelinek 	 */
225767Ssjelinek 	st = getswapentries();
226767Ssjelinek 	/*
227767Ssjelinek 	 * if there are no swap entries return.
228767Ssjelinek 	 */
229767Ssjelinek 	if (st == (struct swaptable *)NULL)
230767Ssjelinek 		return (0);
231767Ssjelinek 	swapent = st->swt_ent;
232767Ssjelinek 	for (i = 0; i < st->swt_n; i++, swapent++) {
233767Ssjelinek 		if ((part = getpartition(swapent->ste_path)) != -1) {
234767Ssjelinek 			if (start == UINT_MAX64) {
235767Ssjelinek 				found = -1;
236767Ssjelinek 				break;
237767Ssjelinek 			}
238767Ssjelinek 			map = &cur_parts->pinfo_map[part];
239767Ssjelinek 			if ((start >= (int)(map->dkl_cylno * spc() +
240767Ssjelinek 				map->dkl_nblk)) || (end < (int)(map->dkl_cylno
241767Ssjelinek 							* spc()))) {
242767Ssjelinek 					continue;
243767Ssjelinek 			}
244767Ssjelinek 			found = -1;
245767Ssjelinek 			break;
246767Ssjelinek 		};
247767Ssjelinek 	}
248767Ssjelinek 	freeswapentries(st);
249767Ssjelinek 	/*
250767Ssjelinek 	 * If we found trouble and we're running from a command file,
251767Ssjelinek 	 * quit before doing something we really regret.
252767Ssjelinek 	 */
253767Ssjelinek 
254767Ssjelinek 	if (found && option_f) {
255767Ssjelinek 		err_print(
256767Ssjelinek "Operation on disks being used for swapping must be interactive.\n");
257767Ssjelinek 		cmdabort(SIGINT);
258767Ssjelinek 	}
259767Ssjelinek 
260767Ssjelinek 	return (found);
261767Ssjelinek 
262767Ssjelinek 
263767Ssjelinek }
264767Ssjelinek /*
265767Ssjelinek  * Determines if there are partitions that are a part of an SVM, VxVM, zpool
266767Ssjelinek  * volume or a live upgrade device,  overlapping a given portion of a disk.
267767Ssjelinek  * Mounts and swap devices are checked in legacy format code.
268767Ssjelinek  */
269767Ssjelinek int
270767Ssjelinek checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print,
271767Ssjelinek 	int check_label)
272767Ssjelinek {
273767Ssjelinek 
274767Ssjelinek 	int 		error;
275767Ssjelinek 	int 		found = 0;
276767Ssjelinek 	int		check = 0;
277767Ssjelinek 	int 		i;
278767Ssjelinek 	int		bm_inuse = 0;
279767Ssjelinek 	int		part = 0;
280767Ssjelinek 	uint64_t	slice_start, slice_size;
281767Ssjelinek 	dm_descriptor_t	*slices = NULL;
282767Ssjelinek 	nvlist_t	*attrs = NULL;
283767Ssjelinek 	char		*usage;
284767Ssjelinek 	char		*name;
285767Ssjelinek 
286767Ssjelinek 	/*
287*1107Ssjelinek 	 * If the user does not want to do in use checking, return immediately.
288*1107Ssjelinek 	 * Normally, this is handled in libdiskmgt. For format, there is more
289*1107Ssjelinek 	 * processing required, so we want to bypass the in use checking
290*1107Ssjelinek 	 * here.
291*1107Ssjelinek 	 */
292*1107Ssjelinek 
293*1107Ssjelinek 	if (NOINUSE_SET)
294*1107Ssjelinek 		return (0);
295*1107Ssjelinek 
296*1107Ssjelinek 	/*
297767Ssjelinek 	 * For format, we get basic 'in use' details from libdiskmgt. After
298767Ssjelinek 	 * that we must do the appropriate checking to see if the 'in use'
299767Ssjelinek 	 * details require a bit of additional work.
300767Ssjelinek 	 */
301767Ssjelinek 
302767Ssjelinek 	dm_get_slices(cur_disk_path, &slices, &error);
303767Ssjelinek 	if (error) {
304767Ssjelinek 		err_print("Error occurred with device in use checking: %s\n",
305767Ssjelinek 		    strerror(error));
306767Ssjelinek 		return (found);
307767Ssjelinek 	}
308767Ssjelinek 	if (slices == NULL)
309767Ssjelinek 		return (found);
310767Ssjelinek 
311767Ssjelinek 	for (i = 0; slices[i] != NULL; i++) {
312767Ssjelinek 		/*
313767Ssjelinek 		 * If we are checking the whole disk
314767Ssjelinek 		 * then any and all in use data is
315767Ssjelinek 		 * relevant.
316767Ssjelinek 		 */
317767Ssjelinek 		if (start == UINT_MAX64) {
318767Ssjelinek 			name = dm_get_name(slices[i], &error);
319767Ssjelinek 			if (error != 0 || !name) {
320767Ssjelinek 				err_print("Error occurred with device "
321767Ssjelinek 				    "in use checking: %s\n",
322767Ssjelinek 				    strerror(error));
323767Ssjelinek 				continue;
324767Ssjelinek 			}
325767Ssjelinek 			if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) ||
326767Ssjelinek 			    error) {
327767Ssjelinek 				if (error != 0) {
328767Ssjelinek 					dm_free_name(name);
329767Ssjelinek 					name = NULL;
330767Ssjelinek 					err_print("Error occurred with device "
331767Ssjelinek 					    "in use checking: %s\n",
332767Ssjelinek 					    strerror(error));
333767Ssjelinek 					continue;
334767Ssjelinek 				}
335767Ssjelinek 				dm_free_name(name);
336767Ssjelinek 				name = NULL;
337767Ssjelinek 				/*
338767Ssjelinek 				 * If this is a dump device, then it is
339767Ssjelinek 				 * a failure. You cannot format a slice
340767Ssjelinek 				 * that is a dedicated dump device.
341767Ssjelinek 				 */
342767Ssjelinek 
343767Ssjelinek 				if (strstr(usage, DM_USE_DUMP)) {
344767Ssjelinek 					if (print) {
345767Ssjelinek 						err_print(usage);
346767Ssjelinek 						free(usage);
347767Ssjelinek 					}
348767Ssjelinek 					dm_free_descriptors(slices);
349767Ssjelinek 					return (1);
350767Ssjelinek 				}
351767Ssjelinek 				/*
352767Ssjelinek 				 * We really found a device that is in use.
353767Ssjelinek 				 * Set 'found' for the return value, and set
354767Ssjelinek 				 * 'check' to indicate below that we must
355767Ssjelinek 				 * get the partition number to set bm_inuse
356767Ssjelinek 				 * in the event we are trying to label this
357767Ssjelinek 				 * device. check_label is set when we are
358767Ssjelinek 				 * checking modifications for in use slices
359767Ssjelinek 				 * on the device.
360767Ssjelinek 				 */
361767Ssjelinek 				found ++;
362767Ssjelinek 				check = 1;
363767Ssjelinek 				if (print) {
364767Ssjelinek 					err_print(usage);
365767Ssjelinek 					free(usage);
366767Ssjelinek 				}
367767Ssjelinek 			}
368767Ssjelinek 		} else {
369767Ssjelinek 			/*
370767Ssjelinek 			 * Before getting the in use data, verify that the
371767Ssjelinek 			 * current slice is within the range we are checking.
372767Ssjelinek 			 */
373767Ssjelinek 			attrs = dm_get_attributes(slices[i], &error);
374767Ssjelinek 			if (error) {
375767Ssjelinek 				err_print("Error occurred with device in use "
376767Ssjelinek 				    "checking: %s\n", strerror(error));
377767Ssjelinek 				continue;
378767Ssjelinek 			}
379767Ssjelinek 			if (attrs == NULL) {
380767Ssjelinek 				continue;
381767Ssjelinek 			}
382767Ssjelinek 
383767Ssjelinek 			(void) nvlist_lookup_uint64(attrs, DM_START,
384767Ssjelinek 			    &slice_start);
385767Ssjelinek 			(void) nvlist_lookup_uint64(attrs, DM_SIZE,
386767Ssjelinek 			    &slice_size);
387767Ssjelinek 			if (start >= (slice_start + slice_size) ||
388767Ssjelinek 			    (end < slice_start)) {
389767Ssjelinek 				nvlist_free(attrs);
390767Ssjelinek 				attrs = NULL;
391767Ssjelinek 				continue;
392767Ssjelinek 			}
393767Ssjelinek 			name = dm_get_name(slices[i], &error);
394767Ssjelinek 			if (error != 0 || !name) {
395767Ssjelinek 				err_print("Error occurred with device "
396767Ssjelinek 				    "in use checking: %s\n",
397767Ssjelinek 				    strerror(error));
398767Ssjelinek 				nvlist_free(attrs);
399767Ssjelinek 				attrs = NULL;
400767Ssjelinek 				continue;
401767Ssjelinek 			}
402767Ssjelinek 			if (dm_inuse(name, &usage,
403767Ssjelinek 			    DM_WHO_FORMAT, &error) || error) {
404767Ssjelinek 				if (error != 0) {
405767Ssjelinek 					dm_free_name(name);
406767Ssjelinek 					name = NULL;
407767Ssjelinek 					err_print("Error occurred with device "
408767Ssjelinek 					    "in use checking: %s\n",
409767Ssjelinek 					    strerror(error));
410767Ssjelinek 					nvlist_free(attrs);
411767Ssjelinek 					attrs = NULL;
412767Ssjelinek 					continue;
413767Ssjelinek 				}
414767Ssjelinek 				dm_free_name(name);
415767Ssjelinek 				name = NULL;
416767Ssjelinek 				/*
417767Ssjelinek 				 * If this is a dump device, then it is
418767Ssjelinek 				 * a failure. You cannot format a slice
419767Ssjelinek 				 * that is a dedicated dump device.
420767Ssjelinek 				 */
421767Ssjelinek 				if (strstr(usage, DM_USE_DUMP)) {
422767Ssjelinek 					if (print) {
423767Ssjelinek 						err_print(usage);
424767Ssjelinek 						free(usage);
425767Ssjelinek 					}
426767Ssjelinek 					dm_free_descriptors(slices);
427767Ssjelinek 					nvlist_free(attrs);
428767Ssjelinek 					return (1);
429767Ssjelinek 				}
430767Ssjelinek 				/*
431767Ssjelinek 				 * We really found a device that is in use.
432767Ssjelinek 				 * Set 'found' for the return value, and set
433767Ssjelinek 				 * 'check' to indicate below that we must
434767Ssjelinek 				 * get the partition number to set bm_inuse
435767Ssjelinek 				 * in the event we are trying to label this
436767Ssjelinek 				 * device. check_label is set when we are
437767Ssjelinek 				 * checking modifications for in use slices
438767Ssjelinek 				 * on the device.
439767Ssjelinek 				 */
440767Ssjelinek 				found ++;
441767Ssjelinek 				check = 1;
442767Ssjelinek 				if (print) {
443767Ssjelinek 					err_print(usage);
444767Ssjelinek 					free(usage);
445767Ssjelinek 				}
446767Ssjelinek 			}
447767Ssjelinek 		}
448767Ssjelinek 		/*
449767Ssjelinek 		 * If check is set it means we found a slice(the current slice)
450767Ssjelinek 		 * on this device in use in some way.  We potentially want
451767Ssjelinek 		 * to check this slice when labeling is
452767Ssjelinek 		 * requested. We set bm_inuse with this partition value
453767Ssjelinek 		 * for use later if check_label was set when called.
454767Ssjelinek 		 */
455767Ssjelinek 		if (check) {
456767Ssjelinek 			name = dm_get_name(slices[i], &error);
457767Ssjelinek 			if (error != 0 || !name) {
458767Ssjelinek 				err_print("Error occurred with device "
459767Ssjelinek 				    "in use checking: %s\n",
460767Ssjelinek 				    strerror(error));
461767Ssjelinek 				nvlist_free(attrs);
462767Ssjelinek 				attrs = NULL;
463767Ssjelinek 				continue;
464767Ssjelinek 			}
465767Ssjelinek 			part = getpartition(name);
466767Ssjelinek 			dm_free_name(name);
467767Ssjelinek 			name = NULL;
468767Ssjelinek 			if (part != -1) {
469767Ssjelinek 				bm_inuse |= 1 << part;
470767Ssjelinek 			}
471767Ssjelinek 			check = 0;
472767Ssjelinek 		}
473767Ssjelinek 		/*
474767Ssjelinek 		 * If we have attributes then we have successfully
475767Ssjelinek 		 * found the slice we were looking for and we also
476767Ssjelinek 		 * know this means we are not searching the whole
477767Ssjelinek 		 * disk so break out of the loop
478767Ssjelinek 		 * now.
479767Ssjelinek 		 */
480767Ssjelinek 		if (attrs) {
481767Ssjelinek 			nvlist_free(attrs);
482767Ssjelinek 			break;
483767Ssjelinek 		}
484767Ssjelinek 	}
485767Ssjelinek 
486767Ssjelinek 	if (slices) {
487767Ssjelinek 		dm_free_descriptors(slices);
488767Ssjelinek 	}
489767Ssjelinek 
490767Ssjelinek 	/*
491767Ssjelinek 	 * The user is trying to label the disk. We have to do special
492767Ssjelinek 	 * checking here to ensure they are not trying to modify a slice
493767Ssjelinek 	 * that is in use in an incompatible way.
494767Ssjelinek 	 */
495767Ssjelinek 	if (check_label && bm_inuse) {
496767Ssjelinek 		/*
497767Ssjelinek 		 * !0 indicates that we found a
498767Ssjelinek 		 * problem. In this case, we have overloaded
499767Ssjelinek 		 * the use of checkpartitions to work for
500767Ssjelinek 		 * in use devices. bm_inuse is representative
501767Ssjelinek 		 * of the slice that is in use, not that
502767Ssjelinek 		 * is mounted as is in the case of the normal
503767Ssjelinek 		 * use of checkpartitions.
504767Ssjelinek 		 *
505767Ssjelinek 		 * The call to checkpartitions will return !0 if
506767Ssjelinek 		 * we are trying to shrink a device that we have found
507767Ssjelinek 		 * to be in use above.
508767Ssjelinek 		 */
509767Ssjelinek 		return (checkpartitions(bm_inuse));
510767Ssjelinek 	}
511767Ssjelinek 
512767Ssjelinek 	return (found);
513767Ssjelinek }
514767Ssjelinek /*
515767Ssjelinek  * This routine checks to see if there are mounted partitions overlapping
516767Ssjelinek  * a given portion of a disk.  If the start parameter is < 0, it means
517767Ssjelinek  * that the entire disk should be checked.
518767Ssjelinek  */
519767Ssjelinek int
520767Ssjelinek checkmount(start, end)
521767Ssjelinek 	diskaddr_t	start, end;
522767Ssjelinek {
523767Ssjelinek 	FILE		*fp;
524767Ssjelinek 	int		found = 0;
525767Ssjelinek 	struct dk_map32	*map;
526767Ssjelinek 	int		part;
527767Ssjelinek 	struct mnttab	mnt_record;
528767Ssjelinek 	struct mnttab	*mp = &mnt_record;
529767Ssjelinek 
530767Ssjelinek 	/*
531767Ssjelinek 	 * If we are only checking part of the disk, the disk must
532767Ssjelinek 	 * have a partition map to check against.  If it doesn't,
533767Ssjelinek 	 * we hope for the best.
534767Ssjelinek 	 */
535767Ssjelinek 	if (cur_parts == NULL)
536767Ssjelinek 		return (0);
537767Ssjelinek 
538767Ssjelinek 	/*
539767Ssjelinek 	 * Lock out interrupts because of the mntent protocol.
540767Ssjelinek 	 */
541767Ssjelinek 	enter_critical();
542767Ssjelinek 	/*
543767Ssjelinek 	 * Open the mount table.
544767Ssjelinek 	 */
545767Ssjelinek 	fp = fopen(MNTTAB, "r");
546767Ssjelinek 	if (fp == NULL) {
547767Ssjelinek 		err_print("Unable to open mount table.\n");
548767Ssjelinek 		fullabort();
549767Ssjelinek 	}
550767Ssjelinek 	/*
551767Ssjelinek 	 * Loop through the mount table until we run out of entries.
552767Ssjelinek 	 */
553767Ssjelinek 	while ((getmntent(fp, mp)) != -1) {
554767Ssjelinek 
555767Ssjelinek 		if ((part = getpartition(mp->mnt_special)) == -1)
556767Ssjelinek 			continue;
557767Ssjelinek 
558767Ssjelinek 		/*
559767Ssjelinek 		 * It's a mount on the disk we're checking.  If we are
560767Ssjelinek 		 * checking whole disk, then we found trouble.  We can
561767Ssjelinek 		 * quit searching.
562767Ssjelinek 		 */
563767Ssjelinek 		if (start == UINT_MAX64) {
564767Ssjelinek 			found = -1;
565767Ssjelinek 			break;
566767Ssjelinek 		}
567767Ssjelinek 
568767Ssjelinek 		/*
569767Ssjelinek 		 * If the partition overlaps the zone we're checking,
570767Ssjelinek 		 * then we found trouble.  We can quit searching.
571767Ssjelinek 		 */
572767Ssjelinek 		map = &cur_parts->pinfo_map[part];
573767Ssjelinek 		if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) ||
574767Ssjelinek 			(end < (int)(map->dkl_cylno * spc()))) {
575767Ssjelinek 			continue;
576767Ssjelinek 		}
577767Ssjelinek 		found = -1;
578767Ssjelinek 		break;
579767Ssjelinek 	}
580767Ssjelinek 	/*
581767Ssjelinek 	 * Close down the mount table.
582767Ssjelinek 	 */
583767Ssjelinek 	(void) fclose(fp);
584767Ssjelinek 	exit_critical();
585767Ssjelinek 
586767Ssjelinek 	/*
587767Ssjelinek 	 * If we found trouble and we're running from a command file,
588767Ssjelinek 	 * quit before doing something we really regret.
589767Ssjelinek 	 */
590767Ssjelinek 
591767Ssjelinek 	if (found && option_f) {
592767Ssjelinek 		err_print("Operation on mounted disks must be interactive.\n");
593767Ssjelinek 		cmdabort(SIGINT);
594767Ssjelinek 	}
595767Ssjelinek 	/*
596767Ssjelinek 	 * Return the result.
597767Ssjelinek 	 */
598767Ssjelinek 	return (found);
599767Ssjelinek }
600767Ssjelinek 
601767Ssjelinek int
602767Ssjelinek check_label_with_swap()
603767Ssjelinek {
604767Ssjelinek 	int			i;
605767Ssjelinek 	struct swaptable *st;
606767Ssjelinek 	struct swapent *swapent;
607767Ssjelinek 	int	part;
608767Ssjelinek 	int	bm_swap = 0;
609767Ssjelinek 
610767Ssjelinek 	/*
611767Ssjelinek 	 * If we are only checking part of the disk, the disk must
612767Ssjelinek 	 * have a partition map to check against.  If it doesn't,
613767Ssjelinek 	 * we hope for the best.
614767Ssjelinek 	 */
615767Ssjelinek 	if (cur_parts == NULL)
616767Ssjelinek 		return (0);	/* Will be checked later */
617767Ssjelinek 
618767Ssjelinek 	/*
619767Ssjelinek 	 * Check for swap entries
620767Ssjelinek 	 */
621767Ssjelinek 	st = getswapentries();
622767Ssjelinek 	/*
623767Ssjelinek 	 * if there are no swap entries return.
624767Ssjelinek 	 */
625767Ssjelinek 	if (st == (struct swaptable *)NULL)
626767Ssjelinek 		return (0);
627767Ssjelinek 	swapent = st->swt_ent;
628767Ssjelinek 	for (i = 0; i < st->swt_n; i++, swapent++)
629767Ssjelinek 		if ((part = getpartition(swapent->ste_path)) != -1)
630767Ssjelinek 				bm_swap |= (1 << part);
631767Ssjelinek 	freeswapentries(st);
632767Ssjelinek 
633767Ssjelinek 	return (checkpartitions(bm_swap));
634767Ssjelinek }
635767Ssjelinek 
636767Ssjelinek /*
637767Ssjelinek  * Check the new label with the existing label on the disk,
638767Ssjelinek  * to make sure that any mounted partitions are not being
639767Ssjelinek  * affected by writing the new label.
640767Ssjelinek  */
641767Ssjelinek int
642767Ssjelinek check_label_with_mount()
643767Ssjelinek {
644767Ssjelinek 	FILE			*fp;
645767Ssjelinek 	int			part;
646767Ssjelinek 	struct mnttab		mnt_record;
647767Ssjelinek 	struct mnttab		*mp = &mnt_record;
648767Ssjelinek 	int			bm_mounted = 0;
649767Ssjelinek 
650767Ssjelinek 
651767Ssjelinek 	/*
652767Ssjelinek 	 * If we are only checking part of the disk, the disk must
653767Ssjelinek 	 * have a partition map to check against.  If it doesn't,
654767Ssjelinek 	 * we hope for the best.
655767Ssjelinek 	 */
656767Ssjelinek 	if (cur_parts == NULL)
657767Ssjelinek 		return (0);	/* Will be checked later */
658767Ssjelinek 
659767Ssjelinek 	/*
660767Ssjelinek 	 * Lock out interrupts because of the mntent protocol.
661767Ssjelinek 	 */
662767Ssjelinek 	enter_critical();
663767Ssjelinek 	/*
664767Ssjelinek 	 * Open the mount table.
665767Ssjelinek 	 */
666767Ssjelinek 	fp = fopen(MNTTAB, "r");
667767Ssjelinek 	if (fp == NULL) {
668767Ssjelinek 		err_print("Unable to open mount table.\n");
669767Ssjelinek 		fullabort();
670767Ssjelinek 	}
671767Ssjelinek 	/*
672767Ssjelinek 	 * Loop through the mount table until we run out of entries.
673767Ssjelinek 	 */
674767Ssjelinek 	while ((getmntent(fp, mp)) != -1) {
675767Ssjelinek 		if ((part = getpartition(mp->mnt_special)) != -1)
676767Ssjelinek 			bm_mounted |= (1 << part);
677767Ssjelinek 	}
678767Ssjelinek 	/*
679767Ssjelinek 	 * Close down the mount table.
680767Ssjelinek 	 */
681767Ssjelinek 	(void) fclose(fp);
682767Ssjelinek 	exit_critical();
683767Ssjelinek 
684767Ssjelinek 	return (checkpartitions(bm_mounted));
685767Ssjelinek 
686767Ssjelinek }
687767Ssjelinek 
688767Ssjelinek /*
689767Ssjelinek  * This Routine checks if any partitions specified
690767Ssjelinek  * are affected by writing the new label
691767Ssjelinek  */
692767Ssjelinek static int
693767Ssjelinek checkpartitions(int bm_mounted)
694767Ssjelinek {
695767Ssjelinek 	struct dk_map32		*n;
696767Ssjelinek 	struct dk_map		*o;
697767Ssjelinek 	struct dk_allmap	old_map;
698767Ssjelinek 	int			i, found = 0;
699767Ssjelinek 
700767Ssjelinek 	/*
701767Ssjelinek 	 * Now we need to check that the current partition list and the
702767Ssjelinek 	 * previous partition list (which there must be if we actually
703767Ssjelinek 	 * have partitions mounted) overlap  in any way on the mounted
704767Ssjelinek 	 * partitions
705767Ssjelinek 	 */
706767Ssjelinek 
707767Ssjelinek 	/*
708767Ssjelinek 	 * Get the "real" (on-disk) version of the partition table
709767Ssjelinek 	 */
710767Ssjelinek 	if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) {
711767Ssjelinek 		err_print("Unable to get current partition map.\n");
712767Ssjelinek 		return (-1);
713767Ssjelinek 	}
714767Ssjelinek 	for (i = 0; i < NDKMAP; i++) {
715767Ssjelinek 		if (bm_mounted & (1 << i)) {
716767Ssjelinek 			/*
717767Ssjelinek 			 * This partition is mounted
718767Ssjelinek 			 */
719767Ssjelinek 			o = &old_map.dka_map[i];
720767Ssjelinek 			n = &cur_parts->pinfo_map[i];
721767Ssjelinek #ifdef DEBUG
722767Ssjelinek 			fmt_print(
723767Ssjelinek "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE);
724767Ssjelinek #endif
725767Ssjelinek 			/*
726767Ssjelinek 			 * If partition is identical, we're fine.
727767Ssjelinek 			 * If the partition grows, we're also fine, because
728767Ssjelinek 			 * the routines in partition.c check for overflow.
729767Ssjelinek 			 * It will (ultimately) be up to the routines in
730767Ssjelinek 			 * partition.c to warn about creation of overlapping
731767Ssjelinek 			 * partitions
732767Ssjelinek 			 */
733767Ssjelinek 			if (o->dkl_cylno == n->dkl_cylno &&
734767Ssjelinek 					o->dkl_nblk <= n->dkl_nblk) {
735767Ssjelinek #ifdef	DEBUG
736767Ssjelinek 				if (o->dkl_nblk < n->dkl_nblk) {
737767Ssjelinek 					fmt_print(
738767Ssjelinek "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk);
739767Ssjelinek 				}
740767Ssjelinek 				fmt_print("\n");
741767Ssjelinek #endif
742767Ssjelinek 				continue;
743767Ssjelinek 			}
744767Ssjelinek #ifdef DEBUG
745767Ssjelinek 			fmt_print("- changes; old (%d,%d)->new (%d,%d)\n",
746767Ssjelinek 				o->dkl_cylno, o->dkl_nblk, n->dkl_cylno,
747767Ssjelinek 				n->dkl_nblk);
748767Ssjelinek #endif
749767Ssjelinek 			found = -1;
750767Ssjelinek 		}
751767Ssjelinek 		if (found)
752767Ssjelinek 			break;
753767Ssjelinek 	}
754767Ssjelinek 
755767Ssjelinek 	/*
756767Ssjelinek 	 * If we found trouble and we're running from a command file,
757767Ssjelinek 	 * quit before doing something we really regret.
758767Ssjelinek 	 */
759767Ssjelinek 
760767Ssjelinek 	if (found && option_f) {
761767Ssjelinek 		err_print("Operation on mounted disks or \
762767Ssjelinek disks currently being used for swapping must be interactive.\n");
763767Ssjelinek 		cmdabort(SIGINT);
764767Ssjelinek 	}
765767Ssjelinek 	/*
766767Ssjelinek 	 * Return the result.
767767Ssjelinek 	 */
768767Ssjelinek 	return (found);
769767Ssjelinek }
770