xref: /illumos-gate/usr/src/cmd/format/checkdev.c (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1991-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contians miscellaneous routines.
31  */
32 #include "global.h"
33 
34 #include <sys/mnttab.h>
35 #include <sys/mntent.h>
36 #include <sys/autoconf.h>
37 
38 #include <signal.h>
39 #include <malloc.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <sys/ioctl.h>
45 #include <sys/fcntl.h>
46 #include <sys/stat.h>
47 #include <sys/swap.h>
48 #include <sys/sysmacros.h>
49 #include <ctype.h>
50 #include "misc.h"
51 #include "checkmount.h"
52 
53 /* Function prototypes */
54 #ifdef	__STDC__
55 
56 static struct swaptable *getswapentries(void);
57 static void freeswapentries(struct swaptable *);
58 static int	getpartition(char *pathname);
59 static int	checkpartitions(int mounted);
60 
61 #else	/* __STDC__ */
62 
63 static struct swaptable *getswapentries();
64 static void freeswapentries();
65 static int	getpartition();
66 static int	checkpartitions();
67 
68 #endif	/* __STDC__ */
69 
70 static struct swaptable *
71 getswapentries(void)
72 {
73 	register struct swaptable *st;
74 	register struct swapent *swapent;
75 	int	i, num;
76 	char	fullpathname[MAXPATHLEN];
77 
78 	/*
79 	 * get the number of swap entries
80 	 */
81 	if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) {
82 		err_print("swapctl error ");
83 		fullabort();
84 	}
85 	if (num == 0)
86 		return (NULL);
87 	if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int)))
88 			== NULL) {
89 		err_print("getswapentries: malloc  failed.\n");
90 		fullabort();
91 	}
92 	swapent = st->swt_ent;
93 	for (i = 0; i < num; i++, swapent++) {
94 		if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) {
95 			err_print("getswapentries: malloc  failed.\n");
96 			fullabort();
97 		}
98 	}
99 	st->swt_n = num;
100 	if ((num = swapctl(SC_LIST, (void *)st)) == -1) {
101 		err_print("swapctl error ");
102 		fullabort();
103 	}
104 	swapent = st->swt_ent;
105 	for (i = 0; i < num; i++, swapent++) {
106 		if (*swapent->ste_path != '/') {
107 			(void) snprintf(fullpathname, sizeof (fullpathname),
108 			    "/dev/%s", swapent->ste_path);
109 			(void) strcpy(swapent->ste_path, fullpathname);
110 		}
111 	}
112 	return (st);
113 }
114 
115 static void
116 freeswapentries(st)
117 struct swaptable *st;
118 {
119 	register struct swapent *swapent;
120 	int i;
121 
122 	swapent = st->swt_ent;
123 	for (i = 0; i < st->swt_n; i++, swapent++)
124 		free(swapent->ste_path);
125 	free(st);
126 
127 }
128 
129 /*
130  *  function getpartition:
131  */
132 static int
133 getpartition(pathname)
134 char *pathname;
135 {
136 	int		mfd;
137 	struct dk_cinfo dkinfo;
138 	struct stat	stbuf;
139 	char		raw_device[MAXPATHLEN];
140 	int		found = -1;
141 
142 	/*
143 	 * Map the block device name to the raw device name.
144 	 * If it doesn't appear to be a device name, skip it.
145 	 */
146 	if (match_substr(pathname, "/dev/") == 0)
147 		return (found);
148 	(void) strcpy(raw_device, "/dev/r");
149 	(void) strcat(raw_device, pathname + strlen("/dev/"));
150 	/*
151 	 * Determine if this appears to be a disk device.
152 	 * First attempt to open the device.  If if fails, skip it.
153 	 */
154 	if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
155 		return (found);
156 	}
157 	/*
158 	 * Must be a character device
159 	 */
160 	if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
161 		(void) close(mfd);
162 		return (found);
163 	}
164 	/*
165 	 * Attempt to read the configuration info on the disk.
166 	 */
167 	if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) {
168 		(void) close(mfd);
169 		return (found);
170 	}
171 	/*
172 	 * Finished with the opened device
173 	 */
174 	(void) close(mfd);
175 
176 	/*
177 	 * If it's not the disk we're interested in, it doesn't apply.
178 	 */
179 	if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype ||
180 		cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum ||
181 		cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit ||
182 		strcmp(cur_disk->disk_dkinfo.dki_dname,
183 				dkinfo.dki_dname) != 0) {
184 		return (found);
185 	}
186 
187 	/*
188 	 *  Extract the partition that is mounted.
189 	 */
190 	return (PARTITION(stbuf.st_rdev));
191 }
192 
193 /*
194  * This Routine checks to see if there are partitions used for swapping overlaps
195  * a given portion of a disk. If the start parameter is < 0, it means
196  * that the entire disk should be checked
197  */
198 int
199 checkswap(start, end)
200 	diskaddr_t start, end;
201 {
202 	struct swaptable *st;
203 	struct swapent *swapent;
204 	int		i;
205 	int		found = 0;
206 	struct dk_map32	*map;
207 	int		part;
208 
209 	/*
210 	 * If we are only checking part of the disk, the disk must
211 	 * have a partition map to check against.  If it doesn't,
212 	 * we hope for the best.
213 	 */
214 	if (cur_parts == NULL)
215 		return (0);
216 
217 	/*
218 	 * check for swap entries
219 	 */
220 	st = getswapentries();
221 	/*
222 	 * if there are no swap entries return.
223 	 */
224 	if (st == (struct swaptable *)NULL)
225 		return (0);
226 	swapent = st->swt_ent;
227 	for (i = 0; i < st->swt_n; i++, swapent++) {
228 		if ((part = getpartition(swapent->ste_path)) != -1) {
229 			if (start == UINT_MAX64) {
230 				found = -1;
231 				break;
232 			}
233 			map = &cur_parts->pinfo_map[part];
234 			if ((start >= (int)(map->dkl_cylno * spc() +
235 				map->dkl_nblk)) || (end < (int)(map->dkl_cylno
236 							* spc()))) {
237 					continue;
238 			}
239 			found = -1;
240 			break;
241 		};
242 	}
243 	freeswapentries(st);
244 	/*
245 	 * If we found trouble and we're running from a command file,
246 	 * quit before doing something we really regret.
247 	 */
248 
249 	if (found && option_f) {
250 		err_print(
251 "Operation on disks being used for swapping must be interactive.\n");
252 		cmdabort(SIGINT);
253 	}
254 
255 	return (found);
256 
257 
258 }
259 
260 /*
261  * This routine checks to see if there are mounted partitions overlapping
262  * a given portion of a disk.  If the start parameter is < 0, it means
263  * that the entire disk should be checked.
264  */
265 int
266 checkmount(start, end)
267 	diskaddr_t	start, end;
268 {
269 	FILE		*fp;
270 	int		found = 0;
271 	struct dk_map32	*map;
272 	int		part;
273 	struct mnttab	mnt_record;
274 	struct mnttab	*mp = &mnt_record;
275 
276 	/*
277 	 * If we are only checking part of the disk, the disk must
278 	 * have a partition map to check against.  If it doesn't,
279 	 * we hope for the best.
280 	 */
281 	if (cur_parts == NULL)
282 		return (0);
283 
284 	/*
285 	 * Lock out interrupts because of the mntent protocol.
286 	 */
287 	enter_critical();
288 	/*
289 	 * Open the mount table.
290 	 */
291 	fp = fopen(MNTTAB, "r");
292 	if (fp == NULL) {
293 		err_print("Unable to open mount table.\n");
294 		fullabort();
295 	}
296 	/*
297 	 * Loop through the mount table until we run out of entries.
298 	 */
299 	while ((getmntent(fp, mp)) != -1) {
300 
301 		if ((part = getpartition(mp->mnt_special)) == -1)
302 			continue;
303 
304 		/*
305 		 * It's a mount on the disk we're checking.  If we are
306 		 * checking whole disk, then we found trouble.  We can
307 		 * quit searching.
308 		 */
309 		if (start == UINT_MAX64) {
310 			found = -1;
311 			break;
312 		}
313 
314 		/*
315 		 * If the partition overlaps the zone we're checking,
316 		 * then we found trouble.  We can quit searching.
317 		 */
318 		map = &cur_parts->pinfo_map[part];
319 		if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) ||
320 			(end < (int)(map->dkl_cylno * spc()))) {
321 			continue;
322 		}
323 		found = -1;
324 		break;
325 	}
326 	/*
327 	 * Close down the mount table.
328 	 */
329 	(void) fclose(fp);
330 	exit_critical();
331 
332 	/*
333 	 * If we found trouble and we're running from a command file,
334 	 * quit before doing something we really regret.
335 	 */
336 
337 	if (found && option_f) {
338 		err_print("Operation on mounted disks must be interactive.\n");
339 		cmdabort(SIGINT);
340 	}
341 	/*
342 	 * Return the result.
343 	 */
344 	return (found);
345 }
346 
347 int
348 check_label_with_swap()
349 {
350 	int			i;
351 	struct swaptable *st;
352 	struct swapent *swapent;
353 	int	part;
354 	int	bm_swap = 0;
355 
356 	/*
357 	 * If we are only checking part of the disk, the disk must
358 	 * have a partition map to check against.  If it doesn't,
359 	 * we hope for the best.
360 	 */
361 	if (cur_parts == NULL)
362 		return (0);	/* Will be checked later */
363 
364 	/*
365 	 * Check for swap entries
366 	 */
367 	st = getswapentries();
368 	/*
369 	 * if there are no swap entries return.
370 	 */
371 	if (st == (struct swaptable *)NULL)
372 		return (0);
373 	swapent = st->swt_ent;
374 	for (i = 0; i < st->swt_n; i++, swapent++)
375 		if ((part = getpartition(swapent->ste_path)) != -1)
376 				bm_swap |= (1 << part);
377 	freeswapentries(st);
378 
379 	return (checkpartitions(bm_swap));
380 }
381 
382 /*
383  * Check the new label with the existing label on the disk,
384  * to make sure that any mounted partitions are not being
385  * affected by writing the new label.
386  */
387 int
388 check_label_with_mount()
389 {
390 	FILE			*fp;
391 	int			part;
392 	struct mnttab		mnt_record;
393 	struct mnttab		*mp = &mnt_record;
394 	int			bm_mounted = 0;
395 
396 
397 	/*
398 	 * If we are only checking part of the disk, the disk must
399 	 * have a partition map to check against.  If it doesn't,
400 	 * we hope for the best.
401 	 */
402 	if (cur_parts == NULL)
403 		return (0);	/* Will be checked later */
404 
405 	/*
406 	 * Lock out interrupts because of the mntent protocol.
407 	 */
408 	enter_critical();
409 	/*
410 	 * Open the mount table.
411 	 */
412 	fp = fopen(MNTTAB, "r");
413 	if (fp == NULL) {
414 		err_print("Unable to open mount table.\n");
415 		fullabort();
416 	}
417 	/*
418 	 * Loop through the mount table until we run out of entries.
419 	 */
420 	while ((getmntent(fp, mp)) != -1) {
421 		if ((part = getpartition(mp->mnt_special)) != -1)
422 			bm_mounted |= (1 << part);
423 	}
424 	/*
425 	 * Close down the mount table.
426 	 */
427 	(void) fclose(fp);
428 	exit_critical();
429 
430 	return (checkpartitions(bm_mounted));
431 
432 }
433 
434 /*
435  * This Routine checks if any partitions specified by the
436  * bit-map of mounted/swap partitions are affected by
437  * writing the new label
438  */
439 static int
440 checkpartitions(bm_mounted)
441 int bm_mounted;
442 {
443 	struct dk_map32		*n;
444 	struct dk_map		*o;
445 	struct dk_allmap	old_map;
446 	int			i, found = 0;
447 
448 	/*
449 	 * Now we need to check that the current partition list and the
450 	 * previous partition list (which there must be if we actually
451 	 * have partitions mounted) overlap  in any way on the mounted
452 	 * partitions
453 	 */
454 
455 	/*
456 	 * Get the "real" (on-disk) version of the partition table
457 	 */
458 	if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) {
459 		err_print("Unable to get current partition map.\n");
460 		return (-1);
461 	}
462 	for (i = 0; i < NDKMAP; i++) {
463 		if (bm_mounted & (1 << i)) {
464 			/*
465 			 * This partition is mounted
466 			 */
467 			o = &old_map.dka_map[i];
468 			n = &cur_parts->pinfo_map[i];
469 #ifdef DEBUG
470 			fmt_print(
471 "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE);
472 #endif
473 			/*
474 			 * If partition is identical, we're fine.
475 			 * If the partition grows, we're also fine, because
476 			 * the routines in partition.c check for overflow.
477 			 * It will (ultimately) be up to the routines in
478 			 * partition.c to warn about creation of overlapping
479 			 * partitions
480 			 */
481 			if (o->dkl_cylno == n->dkl_cylno &&
482 					o->dkl_nblk <= n->dkl_nblk) {
483 #ifdef	DEBUG
484 				if (o->dkl_nblk < n->dkl_nblk) {
485 					fmt_print(
486 "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk);
487 				}
488 				fmt_print("\n");
489 #endif
490 				continue;
491 			}
492 #ifdef DEBUG
493 			fmt_print("- changes; old (%d,%d)->new (%d,%d)\n",
494 				o->dkl_cylno, o->dkl_nblk, n->dkl_cylno,
495 				n->dkl_nblk);
496 #endif
497 			found = -1;
498 		}
499 		if (found)
500 			break;
501 	}
502 
503 	/*
504 	 * If we found trouble and we're running from a command file,
505 	 * quit before doing something we really regret.
506 	 */
507 
508 	if (found && option_f) {
509 		err_print("Operation on mounted disks or \
510 disks currently being used for swapping must be interactive.\n");
511 		cmdabort(SIGINT);
512 	}
513 	/*
514 	 * Return the result.
515 	 */
516 	return (found);
517 }
518