<sys/ioccom.h>, <sys/ioctl.h>
[minix3.git] / commands / repartition / repartition.c
blobace391b60e29458e8bd563a993ac43674fcc686c
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 #define MINOR_d0p0s0 128
49 void partsort(struct part_entry *pe)
50 /* DOS has the misguided idea that partition tables must be sorted. */
52 int i,j;
53 struct part_entry tmp;
55 for (i = 0; i < NR_PARTITIONS; i++)
56 for (j = 0; j < NR_PARTITIONS-1; j++)
57 if ((pe[j].sysind == NO_PART && pe[j+1].sysind != NO_PART) ||
58 (pe[j].lowsec > pe[j+1].lowsec && pe[j+1].sysind != NO_PART)) {
59 tmp = pe[j];
60 pe[j] = pe[j+1];
61 pe[j+1] = tmp;
65 char *finddev(dev_t device)
66 /* Find the device next to dev_file with the given device number. */
68 DIR *dp;
69 struct dirent *de;
70 static char name[PATH_MAX];
71 char *np;
72 size_t nlen;
73 struct stat st;
75 if ((np= strrchr(dev_file, '/')) == nil) np= dev_file; else np++;
76 nlen= np - dev_file;
77 if (nlen > PATH_MAX - NAME_MAX - 1) {
78 fprintf(stderr, "%s: %s: Name is way too long\n",
79 arg0, dev_file);
80 exit(1);
82 memcpy(name, dev_file, nlen);
84 if ((dp= opendir("/dev")) == nil) fatal("/dev");
85 while ((de= readdir(dp)) != nil) {
86 strcpy(name+nlen, de->d_name);
87 if (lstat(name, &st) == 0
88 && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
89 && st.st_rdev == device
90 ) {
91 closedir(dp);
92 return name;
95 fprintf(stderr, "%s: Can't find partition devices associated with %s\n",
96 arg0, dev_file);
97 exit(1);
100 #define DSETP 0
101 #define DGETP 1
103 int diocntl(dev_t device, int request, struct part_geom *entry)
104 /* Get or set the geometry of a device. */
106 char *name;
107 int r, f, err;
109 name= finddev(device);
110 if ((f= open(name, O_RDONLY)) < 0) return -1;
111 r= ioctl(f, request == DSETP ? DIOCSETP : DIOCGETP, (void *) entry);
112 err= errno;
113 (void) close(f);
114 errno= err;
115 return r;
118 struct part_geom geometry; /* Geometry of the device. */
120 void print_chs(unsigned long sector)
122 unsigned secspcyl = geometry.heads * geometry.sectors;
123 int delta= 0;
125 if (sector == -1) { sector= 0; delta= -1; }
127 printf(" %5d/%03d/%02d",
128 (int) (sector / secspcyl),
129 (int) (sector % secspcyl) / geometry.sectors,
130 (int) (sector % geometry.sectors) + delta);
133 void show_part(char *name, unsigned long base, unsigned long size)
135 int i;
136 static int len= 0;
138 if (len == 0) {
139 len= strlen(name) + 3;
140 printf("device");
141 for (i = 6; i < len; i++) fputc(' ', stdout);
142 printf(
143 " first last base size kb\n");
146 printf("%s", name);
147 for (i = strlen(name); i < len; i++) fputc(' ', stdout);
149 print_chs(base);
150 print_chs(base + size - 1);
151 printf(" %9lu %9lu %9lu\n", base, size, size / (1024/SECTOR_SIZE));
154 int main(int argc, char **argv)
156 struct stat hdst;
157 struct part_geom whole, entry;
158 struct part_entry table[4], *pe;
159 int drive, par = 0, device, incr;
160 int partf;
161 char *table_file;
162 int hd_major, hd_minor;
163 int needsort;
164 int shrink; /* True if partitions are shrinked to fit. */
165 unsigned long base, size, limit;
167 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
169 if (argc < 2 || argc > 3) {
170 fprintf(stderr,
171 "Usage: %s device [partition-file]\n", arg0);
172 exit(1);
174 dev_file= argv[1];
175 table_file= argv[argc - 1];
176 shrink= (argc == 2);
178 if (stat(dev_file, &hdst) < 0) fatal(dev_file);
180 /* Geometry (to print nice numbers.) */
181 if (diocntl(hdst.st_rdev, DGETP, &geometry) < 0) fatal(dev_file);
183 if (!S_ISBLK(hdst.st_mode)) {
184 fprintf(stderr, "%s: %s is not a device\n", arg0, dev_file);
185 exit(1);
187 hd_major= major(hdst.st_rdev);
188 hd_minor= minor(hdst.st_rdev);
190 if (hd_minor >= MINOR_d0p0s0) {
191 errno= EINVAL;
192 fatal(dev_file);
195 if (hd_major == major(DEV_FD0)) {
196 /* HD is actually a floppy. */
197 if (hd_minor >= 4) {
198 errno= EINVAL;
199 fatal(dev_file);
201 device= hd_minor + (28 << 2);
202 incr= 4;
203 needsort= 0;
204 } else
205 if (hd_minor % (1 + NR_PARTITIONS) == 0) {
206 /* Partitioning hd0, hd5, ... */
207 device= hd_minor + 1;
208 incr= 1;
209 needsort= 1;
210 } else {
211 /* Subpartitioning hd[1-4], hd[6-9], ... */
212 drive= hd_minor / (1 + NR_PARTITIONS);
213 par= hd_minor % (1 + NR_PARTITIONS) - 1;
215 device= MINOR_d0p0s0
216 + (drive * NR_PARTITIONS + par) * NR_PARTITIONS;
217 if (device + NR_PARTITIONS - 1 > BYTE) {
218 errno= EINVAL;
219 fatal(dev_file);
221 incr= 1;
222 needsort= 0;
224 /* Device is now the first of the minor devices to be repartitioned. */
226 /* Read the partition table from the boot block. */
227 if ((partf= open(table_file, O_RDONLY)) < 0
228 || lseek(partf, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
229 || (par= read(partf, (char *) table, (int) sizeof(table))) < 0
230 ) fatal(table_file);
232 if (par < sizeof(table)) {
233 fprintf(stderr, "%s: %s does not contain a partition table\n",
234 arg0, table_file);
235 exit(1);
237 if (needsort) partsort(table);
239 /* Show the geometry of the affected drive or partition. */
240 if (diocntl(hdst.st_rdev, DGETP, &whole) < 0) fatal(dev_file);
242 /* Use sector numbers. */
243 base = whole.base / SECTOR_SIZE;
244 size = whole.size / SECTOR_SIZE;
245 limit = base + size;
247 show_part(dev_file, base, size);
249 /* Send the partition table entries to the device driver. */
250 for (par= 0; par < NR_PARTITIONS; par++, device+= incr) {
251 pe = &table[par];
252 if (shrink && pe->size != 0) {
253 /* Shrink the partition entry to fit within the
254 * enclosing device just like the driver does.
256 unsigned long part_limit= pe->lowsec + pe->size;
258 if (part_limit < pe->lowsec) part_limit= limit;
259 if (part_limit > limit) part_limit= limit;
260 if (pe->lowsec < base) pe->lowsec= base;
261 if (part_limit < pe->lowsec) part_limit= pe->lowsec;
262 pe->size= part_limit - pe->lowsec;
265 entry.base= pe->lowsec * SECTOR_SIZE;
266 entry.size= pe->size * SECTOR_SIZE;
267 if (diocntl(makedev(hd_major, device), DSETP, &entry) < 0)
268 fatal(dev_file);
270 show_part(finddev(makedev(hd_major, device)),
271 pe->lowsec, pe->size);
273 exit(0);