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