xref: /minix3/minix/commands/repartition/repartition.c (revision 6ddb33542af04356a66b658478494d3179562f63)
1433d6423SLionel Sambuc /*	repartition 1.18 - Load a partition table	Author: Kees J. Bot
2433d6423SLionel Sambuc  *								30 Nov 1991
3433d6423SLionel Sambuc  */
4433d6423SLionel Sambuc #define nil 0
5433d6423SLionel Sambuc #include <stdio.h>
6433d6423SLionel Sambuc #include <sys/types.h>
7433d6423SLionel Sambuc #include <sys/ioctl.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <unistd.h>
10433d6423SLionel Sambuc #include <fcntl.h>
11433d6423SLionel Sambuc #include <minix/config.h>
12433d6423SLionel Sambuc #include <minix/const.h>
13433d6423SLionel Sambuc #include <minix/partition.h>
14433d6423SLionel Sambuc #include <machine/partition.h>
15433d6423SLionel Sambuc #include <sys/stat.h>
16433d6423SLionel Sambuc #include <string.h>
17433d6423SLionel Sambuc #include <errno.h>
18433d6423SLionel Sambuc #include <dirent.h>
19433d6423SLionel Sambuc #include <limits.h>
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc #define DEV_FD0		0x200
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc #define SECTOR_SIZE	512
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc #define arraysize(a)	(sizeof(a)/sizeof((a)[0]))
26433d6423SLionel Sambuc #define arraylimit(a)	((a) + arraysize(a))
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc char *arg0;
29433d6423SLionel Sambuc char *dev_file;		/* Device to repartition. */
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc #ifndef S_ISLNK
32433d6423SLionel Sambuc /* There were no symlinks in medieval times. */
33433d6423SLionel Sambuc #define lstat		stat
34433d6423SLionel Sambuc #endif
35433d6423SLionel Sambuc 
report(const char * label)36433d6423SLionel Sambuc void report(const char *label)
37433d6423SLionel Sambuc {
38433d6423SLionel Sambuc 	fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
39433d6423SLionel Sambuc }
40433d6423SLionel Sambuc 
fatal(const char * label)41433d6423SLionel Sambuc void fatal(const char *label)
42433d6423SLionel Sambuc {
43433d6423SLionel Sambuc 	report(label);
44433d6423SLionel Sambuc 	exit(1);
45433d6423SLionel Sambuc }
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc #define MINOR_d0p0s0	128
48433d6423SLionel Sambuc 
partsort(struct part_entry * pe)49433d6423SLionel Sambuc void partsort(struct part_entry *pe)
50433d6423SLionel Sambuc /* DOS has the misguided idea that partition tables must be sorted. */
51433d6423SLionel Sambuc {
52433d6423SLionel Sambuc   int i,j;
53433d6423SLionel Sambuc   struct part_entry tmp;
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc   for (i = 0; i < NR_PARTITIONS; i++)
56433d6423SLionel Sambuc 	for (j = 0; j < NR_PARTITIONS-1; j++)
57433d6423SLionel Sambuc 		if ((pe[j].sysind == NO_PART && pe[j+1].sysind != NO_PART) ||
58433d6423SLionel Sambuc 		 (pe[j].lowsec > pe[j+1].lowsec && pe[j+1].sysind != NO_PART)) {
59433d6423SLionel Sambuc 			tmp = pe[j];
60433d6423SLionel Sambuc 			pe[j] = pe[j+1];
61433d6423SLionel Sambuc 			pe[j+1] = tmp;
62433d6423SLionel Sambuc 		}
63433d6423SLionel Sambuc }
64433d6423SLionel Sambuc 
finddev(dev_t device)65433d6423SLionel Sambuc char *finddev(dev_t device)
66433d6423SLionel Sambuc /* Find the device next to dev_file with the given device number. */
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc 	DIR *dp;
69433d6423SLionel Sambuc 	struct dirent *de;
70433d6423SLionel Sambuc 	static char name[PATH_MAX];
71433d6423SLionel Sambuc 	char *np;
72433d6423SLionel Sambuc 	size_t nlen;
73433d6423SLionel Sambuc 	struct stat st;
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc 	if ((np= strrchr(dev_file, '/')) == nil) np= dev_file; else np++;
76433d6423SLionel Sambuc 	nlen= np - dev_file;
77433d6423SLionel Sambuc 	if (nlen > PATH_MAX - NAME_MAX - 1) {
78433d6423SLionel Sambuc 		fprintf(stderr, "%s: %s: Name is way too long\n",
79433d6423SLionel Sambuc 			arg0, dev_file);
80433d6423SLionel Sambuc 		exit(1);
81433d6423SLionel Sambuc 	}
82433d6423SLionel Sambuc 	memcpy(name, dev_file, nlen);
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc 	if ((dp= opendir("/dev")) == nil) fatal("/dev");
85433d6423SLionel Sambuc 	while ((de= readdir(dp)) != nil) {
86433d6423SLionel Sambuc 		strcpy(name+nlen, de->d_name);
87433d6423SLionel Sambuc 		if (lstat(name, &st) == 0
88433d6423SLionel Sambuc 			&& (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
89433d6423SLionel Sambuc 			&& st.st_rdev == device
90433d6423SLionel Sambuc 		) {
91433d6423SLionel Sambuc 			closedir(dp);
92433d6423SLionel Sambuc 			return name;
93433d6423SLionel Sambuc 		}
94433d6423SLionel Sambuc 	}
95433d6423SLionel Sambuc 	fprintf(stderr, "%s: Can't find partition devices associated with %s\n",
96433d6423SLionel Sambuc 		arg0, dev_file);
97433d6423SLionel Sambuc 	exit(1);
98433d6423SLionel Sambuc }
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc #define DSETP	0
101433d6423SLionel Sambuc #define DGETP	1
102433d6423SLionel Sambuc 
diocntl(dev_t device,int request,struct part_geom * entry)103433d6423SLionel Sambuc int diocntl(dev_t device, int request, struct part_geom *entry)
104433d6423SLionel Sambuc /* Get or set the geometry of a device. */
105433d6423SLionel Sambuc {
106433d6423SLionel Sambuc 	char *name;
107433d6423SLionel Sambuc 	int r, f, err;
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 	name= finddev(device);
110433d6423SLionel Sambuc 	if ((f= open(name, O_RDONLY)) < 0) return -1;
111433d6423SLionel Sambuc 	r= ioctl(f, request == DSETP ? DIOCSETP : DIOCGETP, (void *) entry);
112433d6423SLionel Sambuc 	err= errno;
113433d6423SLionel Sambuc 	(void) close(f);
114433d6423SLionel Sambuc 	errno= err;
115433d6423SLionel Sambuc 	return r;
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc struct part_geom geometry;	/* Geometry of the device. */
119433d6423SLionel Sambuc 
print_chs(unsigned long sector)120433d6423SLionel Sambuc void print_chs(unsigned long sector)
121433d6423SLionel Sambuc {
122433d6423SLionel Sambuc 	unsigned secspcyl = geometry.heads * geometry.sectors;
123433d6423SLionel Sambuc 	int delta= 0;
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc 	if (sector == -1) { sector= 0; delta= -1; }
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 	printf(" %5d/%03d/%02d",
128433d6423SLionel Sambuc 		(int) (sector / secspcyl),
129433d6423SLionel Sambuc 		(int) (sector % secspcyl) / geometry.sectors,
130433d6423SLionel Sambuc 		(int) (sector % geometry.sectors) + delta);
131433d6423SLionel Sambuc }
132433d6423SLionel Sambuc 
show_part(char * name,unsigned long base,unsigned long size)133433d6423SLionel Sambuc void show_part(char *name, unsigned long base, unsigned long size)
134433d6423SLionel Sambuc {
135433d6423SLionel Sambuc 	int i;
136433d6423SLionel Sambuc 	static int len= 0;
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc 	if (len == 0) {
139433d6423SLionel Sambuc 		len= strlen(name) + 3;
140433d6423SLionel Sambuc 		printf("device");
141433d6423SLionel Sambuc 		for (i = 6; i < len; i++) fputc(' ', stdout);
142433d6423SLionel Sambuc 		printf(
143433d6423SLionel Sambuc 	"      first         last        base      size        kb\n");
144433d6423SLionel Sambuc 	}
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	printf("%s", name);
147433d6423SLionel Sambuc 	for (i = strlen(name); i < len; i++) fputc(' ', stdout);
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 	print_chs(base);
150433d6423SLionel Sambuc 	print_chs(base + size - 1);
151433d6423SLionel Sambuc 	printf(" %9lu %9lu %9lu\n", base, size, size / (1024/SECTOR_SIZE));
152433d6423SLionel Sambuc }
153433d6423SLionel Sambuc 
main(int argc,char ** argv)154433d6423SLionel Sambuc int main(int argc, char **argv)
155433d6423SLionel Sambuc {
156433d6423SLionel Sambuc 	struct stat hdst;
157433d6423SLionel Sambuc 	struct part_geom whole, entry;
158433d6423SLionel Sambuc 	struct part_entry table[4], *pe;
159433d6423SLionel Sambuc 	int drive, par = 0, device, incr;
160433d6423SLionel Sambuc 	int partf;
161433d6423SLionel Sambuc 	char *table_file;
162433d6423SLionel Sambuc 	int hd_major, hd_minor;
163433d6423SLionel Sambuc 	int needsort;
164433d6423SLionel Sambuc 	int shrink;		/* True if partitions are shrinked to fit. */
165433d6423SLionel Sambuc 	unsigned long base, size, limit;
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc 	if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	if (argc < 2 || argc > 3) {
170433d6423SLionel Sambuc 		fprintf(stderr,
171433d6423SLionel Sambuc 			"Usage: %s device [partition-file]\n", arg0);
172433d6423SLionel Sambuc 		exit(1);
173433d6423SLionel Sambuc 	}
174433d6423SLionel Sambuc 	dev_file= argv[1];
175433d6423SLionel Sambuc 	table_file= argv[argc - 1];
176433d6423SLionel Sambuc 	shrink= (argc == 2);
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc 	if (stat(dev_file, &hdst) < 0) fatal(dev_file);
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc 	/* Geometry (to print nice numbers.) */
181433d6423SLionel Sambuc 	if (diocntl(hdst.st_rdev, DGETP, &geometry) < 0) fatal(dev_file);
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc 	if (!S_ISBLK(hdst.st_mode)) {
184433d6423SLionel Sambuc 		fprintf(stderr, "%s: %s is not a device\n", arg0, dev_file);
185433d6423SLionel Sambuc 		exit(1);
186433d6423SLionel Sambuc 	}
187433d6423SLionel Sambuc 	hd_major= major(hdst.st_rdev);
188433d6423SLionel Sambuc 	hd_minor= minor(hdst.st_rdev);
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc 	if (hd_minor >= MINOR_d0p0s0) {
191433d6423SLionel Sambuc 		errno= EINVAL;
192433d6423SLionel Sambuc 		fatal(dev_file);
193433d6423SLionel Sambuc 	}
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc 	if (hd_major == major(DEV_FD0)) {
196433d6423SLionel Sambuc 		/* HD is actually a floppy. */
197433d6423SLionel Sambuc 		if (hd_minor >= 4) {
198433d6423SLionel Sambuc 			errno= EINVAL;
199433d6423SLionel Sambuc 			fatal(dev_file);
200433d6423SLionel Sambuc 		}
201433d6423SLionel Sambuc 		device= hd_minor + (28 << 2);
202433d6423SLionel Sambuc 		incr= 4;
203433d6423SLionel Sambuc 		needsort= 0;
204433d6423SLionel Sambuc 	} else
205433d6423SLionel Sambuc 	if (hd_minor % (1 + NR_PARTITIONS) == 0) {
206433d6423SLionel Sambuc 		/* Partitioning hd0, hd5, ... */
207433d6423SLionel Sambuc 		device= hd_minor + 1;
208433d6423SLionel Sambuc 		incr= 1;
209433d6423SLionel Sambuc 		needsort= 1;
210433d6423SLionel Sambuc 	} else {
211433d6423SLionel Sambuc 		/* Subpartitioning hd[1-4], hd[6-9], ... */
212433d6423SLionel Sambuc 		drive= hd_minor / (1 + NR_PARTITIONS);
213433d6423SLionel Sambuc 		par= hd_minor % (1 + NR_PARTITIONS) - 1;
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 		device= MINOR_d0p0s0
216433d6423SLionel Sambuc 				+ (drive * NR_PARTITIONS + par) * NR_PARTITIONS;
217433d6423SLionel Sambuc 		if (device + NR_PARTITIONS - 1 > BYTE) {
218433d6423SLionel Sambuc 			errno= EINVAL;
219433d6423SLionel Sambuc 			fatal(dev_file);
220433d6423SLionel Sambuc 		}
221433d6423SLionel Sambuc 		incr= 1;
222433d6423SLionel Sambuc 		needsort= 0;
223433d6423SLionel Sambuc 	}
224433d6423SLionel Sambuc 	/* Device is now the first of the minor devices to be repartitioned. */
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc 	/* Read the partition table from the boot block. */
227433d6423SLionel Sambuc 	if ((partf= open(table_file, O_RDONLY)) < 0
228433d6423SLionel Sambuc 		|| lseek(partf, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
229433d6423SLionel Sambuc 		|| (par= read(partf, (char *) table, (int) sizeof(table))) < 0
230433d6423SLionel Sambuc 	) fatal(table_file);
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc 	if (par < sizeof(table)) {
233433d6423SLionel Sambuc 		fprintf(stderr, "%s: %s does not contain a partition table\n",
234433d6423SLionel Sambuc 			arg0, table_file);
235433d6423SLionel Sambuc 		exit(1);
236433d6423SLionel Sambuc 	}
237433d6423SLionel Sambuc 	if (needsort) partsort(table);
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc 	/* Show the geometry of the affected drive or partition. */
240433d6423SLionel Sambuc 	if (diocntl(hdst.st_rdev, DGETP, &whole) < 0) fatal(dev_file);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 	/* Use sector numbers. */
243433d6423SLionel Sambuc 	base = whole.base / SECTOR_SIZE;
244433d6423SLionel Sambuc 	size = whole.size / SECTOR_SIZE;
245433d6423SLionel Sambuc 	limit = base + size;
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 	show_part(dev_file, base, size);
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc 	/* Send the partition table entries to the device driver. */
250433d6423SLionel Sambuc 	for (par= 0; par < NR_PARTITIONS; par++, device+= incr) {
251433d6423SLionel Sambuc 		pe = &table[par];
252433d6423SLionel Sambuc 		if (shrink && pe->size != 0) {
253433d6423SLionel Sambuc 			/* Shrink the partition entry to fit within the
254433d6423SLionel Sambuc 			 * enclosing device just like the driver does.
255433d6423SLionel Sambuc 			 */
256433d6423SLionel Sambuc 			unsigned long part_limit= pe->lowsec + pe->size;
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 			if (part_limit < pe->lowsec) part_limit= limit;
259433d6423SLionel Sambuc 			if (part_limit > limit) part_limit= limit;
260433d6423SLionel Sambuc 			if (pe->lowsec < base) pe->lowsec= base;
261433d6423SLionel Sambuc 			if (part_limit < pe->lowsec) part_limit= pe->lowsec;
262433d6423SLionel Sambuc 			pe->size= part_limit - pe->lowsec;
263433d6423SLionel Sambuc 		}
264433d6423SLionel Sambuc 
265*6ddb3354SAntoine Leca 		entry.base= (off_t)pe->lowsec * SECTOR_SIZE;
266*6ddb3354SAntoine Leca 		entry.size= (off_t)pe->size * SECTOR_SIZE;
267433d6423SLionel Sambuc 		if (diocntl(makedev(hd_major, device), DSETP, &entry) < 0)
268433d6423SLionel Sambuc 			fatal(dev_file);
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc 		show_part(finddev(makedev(hd_major, device)),
271433d6423SLionel Sambuc 							pe->lowsec, pe->size);
272433d6423SLionel Sambuc 	}
273433d6423SLionel Sambuc 	exit(0);
274433d6423SLionel Sambuc }
275