mkfs, mkproto: minor improvements
[minix.git] / commands / repartition / repartition.c
blob0e536d937dc37661f25250082b46c48d48c802b7
1 /* repartition 1.18 - Load a partition table Author: Kees J. Bot
2 * 30 Nov 1991
3 */
4 #define nil 0
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/ioctl.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <minix/config.h>
12 #include <minix/const.h>
13 #include <minix/partition.h>
14 #include <machine/partition.h>
15 #include <sys/stat.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <dirent.h>
19 #include <limits.h>
21 #define DEV_FD0 0x200
23 #define SECTOR_SIZE 512
25 #define arraysize(a) (sizeof(a)/sizeof((a)[0]))
26 #define arraylimit(a) ((a) + arraysize(a))
28 char *arg0;
29 char *dev_file; /* Device to repartition. */
31 #ifndef S_ISLNK
32 /* There were no symlinks in medieval times. */
33 #define lstat stat
34 #endif
36 void report(const char *label)
38 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
41 void fatal(const char *label)
43 report(label);
44 exit(1);
47 #ifndef makedev
48 #define minor(dev) (((dev) >> MINOR) & BYTE)
49 #define major(dev) (((dev) >> MAJOR) & BYTE)
50 #define makedev(major, minor) \
51 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
52 #endif
54 #define MINOR_d0p0s0 128
56 void partsort(struct part_entry *pe)
57 /* DOS has the misguided idea that partition tables must be sorted. */
59 int i,j;
60 struct part_entry tmp;
62 for (i = 0; i < NR_PARTITIONS; i++)
63 for (j = 0; j < NR_PARTITIONS-1; j++)
64 if ((pe[j].sysind == NO_PART && pe[j+1].sysind != NO_PART) ||
65 (pe[j].lowsec > pe[j+1].lowsec && pe[j+1].sysind != NO_PART)) {
66 tmp = pe[j];
67 pe[j] = pe[j+1];
68 pe[j+1] = tmp;
72 char *finddev(dev_t device)
73 /* Find the device next to dev_file with the given device number. */
75 DIR *dp;
76 struct dirent *de;
77 static char name[PATH_MAX];
78 char *np;
79 size_t nlen;
80 struct stat st;
82 if ((np= strrchr(dev_file, '/')) == nil) np= dev_file; else np++;
83 nlen= np - dev_file;
84 if (nlen > PATH_MAX - NAME_MAX - 1) {
85 fprintf(stderr, "%s: %s: Name is way too long\n",
86 arg0, dev_file);
87 exit(1);
89 memcpy(name, dev_file, nlen);
91 if ((dp= opendir("/dev")) == nil) fatal("/dev");
92 while ((de= readdir(dp)) != nil) {
93 strcpy(name+nlen, de->d_name);
94 if (lstat(name, &st) == 0
95 && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
96 && st.st_rdev == device
97 ) {
98 closedir(dp);
99 return name;
102 fprintf(stderr, "%s: Can't find partition devices associated with %s\n",
103 arg0, dev_file);
104 exit(1);
107 #define DSETP 0
108 #define DGETP 1
110 int diocntl(dev_t device, int request, struct partition *entry)
111 /* Get or set the geometry of a device. */
113 char *name;
114 int r, f, err;
115 struct partition geometry;
117 name= finddev(device);
118 if ((f= open(name, O_RDONLY)) < 0) return -1;
119 r= ioctl(f, request == DSETP ? DIOCSETP : DIOCGETP, (void *) entry);
120 err= errno;
121 (void) close(f);
122 errno= err;
123 return r;
126 struct partition geometry; /* Geometry of the device. */
128 void print_chs(unsigned long sector)
130 unsigned secspcyl = geometry.heads * geometry.sectors;
131 int delta= 0;
133 if (sector == -1) { sector= 0; delta= -1; }
135 printf(" %5d/%03d/%02d",
136 (int) (sector / secspcyl),
137 (int) (sector % secspcyl) / geometry.sectors,
138 (int) (sector % geometry.sectors) + delta);
141 void show_part(char *name, unsigned long base, unsigned long size)
143 int i;
144 static int len= 0;
146 if (len == 0) {
147 len= strlen(name) + 3;
148 printf("device");
149 for (i = 6; i < len; i++) fputc(' ', stdout);
150 printf(
151 " first last base size kb\n");
154 printf("%s", name);
155 for (i = strlen(name); i < len; i++) fputc(' ', stdout);
157 print_chs(base);
158 print_chs(base + size - 1);
159 printf(" %9lu %9lu %9lu\n", base, size, size / (1024/SECTOR_SIZE));
162 int main(int argc, char **argv)
164 struct stat hdst;
165 struct partition whole, entry;
166 struct part_entry table[4], *pe;
167 int drive, par, device, incr;
168 int partf;
169 char *table_file;
170 int hd_major, hd_minor;
171 int needsort;
172 int shrink; /* True if partitions are shrinked to fit. */
173 unsigned long base, size, limit;
175 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
177 if (argc < 2 || argc > 3) {
178 fprintf(stderr,
179 "Usage: %s device [partition-file]\n", arg0);
180 exit(1);
182 dev_file= argv[1];
183 table_file= argv[argc - 1];
184 shrink= (argc == 2);
186 if (stat(dev_file, &hdst) < 0) fatal(dev_file);
188 /* Geometry (to print nice numbers.) */
189 if (diocntl(hdst.st_rdev, DGETP, &geometry) < 0) fatal(dev_file);
191 if (!S_ISBLK(hdst.st_mode)) {
192 fprintf(stderr, "%s: %s is not a device\n", arg0, dev_file);
193 exit(1);
195 hd_major= major(hdst.st_rdev);
196 hd_minor= minor(hdst.st_rdev);
198 if (hd_minor >= MINOR_d0p0s0) {
199 errno= EINVAL;
200 fatal(dev_file);
203 if (hd_major == major(DEV_FD0)) {
204 /* HD is actually a floppy. */
205 if (hd_minor >= 4) {
206 errno= EINVAL;
207 fatal(dev_file);
209 device= hd_minor + (28 << 2);
210 incr= 4;
211 needsort= 0;
212 } else
213 if (hd_minor % (1 + NR_PARTITIONS) == 0) {
214 /* Partitioning hd0, hd5, ... */
215 device= hd_minor + 1;
216 incr= 1;
217 needsort= 1;
218 } else {
219 /* Subpartitioning hd[1-4], hd[6-9], ... */
220 drive= hd_minor / (1 + NR_PARTITIONS);
221 par= hd_minor % (1 + NR_PARTITIONS) - 1;
223 device= MINOR_d0p0s0
224 + (drive * NR_PARTITIONS + par) * NR_PARTITIONS;
225 if (device + NR_PARTITIONS - 1 > BYTE) {
226 errno= EINVAL;
227 fatal(dev_file);
229 incr= 1;
230 needsort= 0;
232 /* Device is now the first of the minor devices to be repartitioned. */
234 /* Read the partition table from the boot block. */
235 if ((partf= open(table_file, O_RDONLY)) < 0
236 || lseek(partf, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
237 || (par= read(partf, (char *) table, (int) sizeof(table))) < 0
238 ) fatal(table_file);
240 if (par < sizeof(table)) {
241 fprintf(stderr, "%s: %s does not contain a partition table\n",
242 arg0, table_file);
243 exit(1);
245 if (needsort) partsort(table);
247 /* Show the geometry of the affected drive or partition. */
248 if (diocntl(hdst.st_rdev, DGETP, &whole) < 0) fatal(dev_file);
250 /* Use sector numbers. */
251 base = whole.base / SECTOR_SIZE;
252 size = whole.size / SECTOR_SIZE;
253 limit = base + size;
255 show_part(dev_file, base, size);
257 /* Send the partition table entries to the device driver. */
258 for (par= 0; par < NR_PARTITIONS; par++, device+= incr) {
259 pe = &table[par];
260 if (shrink && pe->size != 0) {
261 /* Shrink the partition entry to fit within the
262 * enclosing device just like the driver does.
264 unsigned long part_limit= pe->lowsec + pe->size;
266 if (part_limit < pe->lowsec) part_limit= limit;
267 if (part_limit > limit) part_limit= limit;
268 if (pe->lowsec < base) pe->lowsec= base;
269 if (part_limit < pe->lowsec) part_limit= pe->lowsec;
270 pe->size= part_limit - pe->lowsec;
273 entry.base= pe->lowsec * SECTOR_SIZE;
274 entry.size= pe->size * SECTOR_SIZE;
275 if (diocntl(makedev(hd_major, device), DSETP, &entry) < 0)
276 fatal(dev_file);
278 show_part(finddev(makedev(hd_major, device)),
279 pe->lowsec, pe->size);
281 exit(0);