Remove DEC Alpha and PC98 support.
[dragonfly.git] / lib / libdisk / create_chunk.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD: src/lib/libdisk/create_chunk.c,v 1.46.2.8 2001/05/13 21:01:37 jkh Exp $
10  * $DragonFly: src/lib/libdisk/Attic/create_chunk.c,v 1.4 2005/03/13 15:10:03 swildner Exp $
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <fcntl.h>
20 #include <stdarg.h>
21 #include <sys/types.h>
22 #include <sys/disklabel.h>
23 #include <sys/diskslice.h>
24 #include <sys/diskmbr.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <grp.h>
28 #include <paths.h>
29 #include <pwd.h>
30 #include "libdisk.h"
31
32 /* Clone these two from sysinstall because we need our own copies
33  * due to link order problems with `crunch'.  Feh!
34  */
35 static int
36 isDebug()
37 {
38     static int debug = 0;       /* Allow debugger to tweak it */
39
40     return debug;
41 }
42
43 /* Write something to the debugging port */
44 static void
45 msgDebug(char *fmt, ...)
46 {
47     va_list args;
48     char *dbg;
49     static int DebugFD = -1;
50
51     if (DebugFD == -1)
52         DebugFD = open(_PATH_DEV"ttyv1", O_RDWR);
53     dbg = (char *)alloca(FILENAME_MAX);
54     strcpy(dbg, "DEBUG: ");
55     va_start(args, fmt);
56     vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args);
57     va_end(args);
58     write(DebugFD, dbg, strlen(dbg));
59 }
60
61 int
62 Fixup_FreeBSD_Names(struct disk *d, struct chunk *c)
63 {
64     struct chunk *c1, *c3;
65     int j;
66     
67     if (!strcmp(c->name, "X")) return 0;
68     
69     /* reset all names to "X" */
70     for (c1 = c->part; c1; c1 = c1->next) {
71         c1->oname = c1->name;
72         c1->name = malloc(12);
73         if(!c1->name) return -1;
74         strcpy(c1->name,"X");
75     }
76     
77     /* Allocate the first swap-partition we find */
78     for (c1 = c->part; c1; c1 = c1->next) {
79         if (c1->type == unused) continue;
80         if (c1->subtype != FS_SWAP) continue;
81         sprintf(c1->name, "%s%c", c->name, SWAP_PART + 'a');
82         break;
83     }
84     
85     /* Allocate the first root-partition we find */
86     for (c1 = c->part; c1; c1 = c1->next) {
87         if (c1->type == unused) continue;
88         if (!(c1->flags & CHUNK_IS_ROOT)) continue;
89         sprintf(c1->name, "%s%c", c->name, 0 + 'a');
90         break;
91     }
92     
93     /* Try to give them the same as they had before */
94     for (c1 = c->part; c1; c1 = c1->next) {
95         if (strcmp(c1->name, "X")) continue;
96         for(c3 = c->part; c3 ; c3 = c3->next)
97             if (c1 != c3 && !strcmp(c3->name, c1->oname)) {
98                 goto newname;
99             }
100         strcpy(c1->name, c1->oname);
101     newname: ;
102     }
103     
104     
105     /* Allocate the rest sequentially */
106     for (c1 = c->part; c1; c1 = c1->next) {
107         const char order[] = "efghabd";
108         if (c1->type == unused) continue;
109         if (strcmp("X", c1->name)) continue;
110         
111         for(j = 0; j < strlen(order); j++) {
112             sprintf(c1->name, "%s%c", c->name, order[j]);
113             for(c3 = c->part; c3 ; c3 = c3->next)
114                 if (c1 != c3 && !strcmp(c3->name, c1->name))
115                     goto match;
116             break;
117         match:
118             strcpy(c1->name, "X");
119             continue;
120         }
121     }
122     for (c1 = c->part; c1; c1 = c1->next) {
123         free(c1->oname);
124         c1->oname = 0;
125     }
126     return 0;
127 }
128
129 int
130 Fixup_Extended_Names(struct disk *d, struct chunk *c)
131 {
132     struct chunk *c1;
133     int j=5;
134     
135     for (c1 = c->part; c1; c1 = c1->next) {
136         if (c1->type == unused) continue;
137         free(c1->name);
138         c1->name = malloc(12);
139         if(!c1->name) return -1;
140         sprintf(c1->name, "%ss%d", d->chunks->name, j++);
141         if (c1->type == freebsd)
142             if (Fixup_FreeBSD_Names(d, c1) != 0)
143                 return -1;
144     }
145     return 0;
146 }
147
148 int
149 Fixup_Names(struct disk *d)
150 {
151     struct chunk *c1, *c2;
152     int i;
153 #ifdef __i386__
154     struct chunk *c3;
155     int j;
156 #endif
157     
158     c1 = d->chunks;
159     for(i=1,c2 = c1->part; c2 ; c2 = c2->next) {
160         c2->flags &= ~CHUNK_BSD_COMPAT;
161         if (c2->type == unused)
162             continue;
163         if (strcmp(c2->name, "X"))
164             continue;
165 #ifdef __i386__
166         c2->oname = malloc(12);
167         if(!c2->oname) return -1;
168         for(j = 1; j <= NDOSPART; j++) {
169             sprintf(c2->oname, "%ss%d", c1->name, j);
170             for(c3 = c1->part; c3; c3 = c3->next)
171                 if (c3 != c2 && !strcmp(c3->name, c2->oname))
172                     goto match;
173             free(c2->name);
174             c2->name = c2->oname;
175             c2->oname = 0;
176             break;
177         match:
178             continue;
179         }
180         if (c2->oname)
181             free(c2->oname);
182 #else
183         free(c2->name);
184         c2->name = strdup(c1->name);
185 #endif /*__i386__*/
186     }
187     for(c2 = c1->part; c2; c2 = c2->next) {
188         if (c2->type == freebsd) {
189             c2->flags |= CHUNK_BSD_COMPAT;
190             break;
191         }
192     }
193     for(c2 = c1->part; c2; c2 = c2->next) {
194         if (c2->type == freebsd)
195             Fixup_FreeBSD_Names(d, c2);
196         if (c2->type == extended)
197             Fixup_Extended_Names(d, c2);
198     }
199     return 0;
200 }
201
202 int
203 Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags)
204 {
205     int i;
206     u_long l;
207     
208     if(!(flags & CHUNK_FORCE_ALL))
209     {
210         /* Never use the first track */
211         if (!offset) {
212             offset += d->bios_sect;
213             size -= d->bios_sect;
214         }
215         
216         /* Always end on cylinder boundary */
217         l = (offset+size) % (d->bios_sect * d->bios_hd);
218         size -= l;
219     }
220     
221     i = Add_Chunk(d, offset, size, "X", type, subtype, flags);
222     Fixup_Names(d);
223     return i;
224 }
225
226 struct chunk *
227 Create_Chunk_DWIM(struct disk *d, struct chunk *parent , u_long size, chunk_e type, int subtype, u_long flags)
228 {
229     int i;
230     struct chunk *c1;
231     u_long offset;
232     
233     if (!parent)
234         parent = d->chunks;
235     for (c1=parent->part; c1; c1 = c1->next) {
236         if (c1->type != unused) continue;
237         if (c1->size < size) continue;
238         offset = c1->offset;
239         goto found;
240     }
241     return 0;
242  found:
243     i = Add_Chunk(d, offset, size, "X", type, subtype, flags);
244     if (i)
245         return 0;
246     Fixup_Names(d);
247     for (c1=parent->part; c1; c1 = c1->next)
248         if (c1->offset == offset)
249             return c1;
250     /* barfout(1, "Serious internal trouble"); */
251     return 0;
252 }
253
254 int
255 MakeDev(struct chunk *c1, const char *path)
256 {
257     char *p = c1->name;
258     u_long cmaj, min, unit, part, slice;
259     char buf[BUFSIZ], buf2[BUFSIZ];
260     struct group *grp;
261     struct passwd *pwd;
262     uid_t owner;
263     gid_t group;
264
265     *buf2 = '\0';
266     if (isDebug())
267         msgDebug("MakeDev: Called with %s on path %s\n", p, path);
268     if (!strcmp(p, "X"))
269         return 0;
270
271     if (!strncmp(p, "ad", 2))
272         cmaj = 116, p += 2;
273     else if (!strncmp(p, "wfd", 3))
274         cmaj = 87, p += 3;
275     else if (!strncmp(p, "afd", 3))
276         cmaj = 118, p += 3;
277     else if (!strncmp(p, "fla", 3))
278         cmaj = 102, p += 3;
279     else if (!strncmp(p, "idad", 4))
280         cmaj = 109, p += 4;
281     else if (!strncmp(p, "mlxd", 4))
282         cmaj = 131, p += 4;
283     else if (!strncmp(p, "amrd", 4))
284         cmaj = 133, p += 4;
285     else if (!strncmp(p, "twed", 4))
286         cmaj = 147, p += 4;
287     else if (!strncmp(p, "aacd", 4))
288         cmaj = 151, p += 4;
289     else if (!strncmp(p, "ar", 2))      /* ATA RAID */
290         cmaj = 157, p += 2;
291     else if (!strncmp(p, "da", 2))      /* CAM support */
292         cmaj = 13, p += 2;
293     else {
294         msgDebug("MakeDev: Unknown major/minor for devtype %s\n", p);
295         return 0;
296     }
297     if (!isdigit(*p)) {
298         msgDebug("MakeDev: Invalid disk unit passed: %s\n", p);
299         return 0;
300     }
301     unit = *p - '0';
302     p++;
303     if (!*p) {
304         slice = 1;
305         part = 2;
306         goto done;
307     }
308     else if (isdigit(*p)) {
309         unit *= 10;
310         unit += (*p - '0');
311         p++;
312     }
313     if (*p != 's') {
314         msgDebug("MakeDev: `%s' is not a valid slice delimiter\n", p);
315         return 0;
316     }
317     p++;
318     if (!isdigit(*p)) {
319         msgDebug("MakeDev: `%s' is an invalid slice number\n", p);
320         return 0;
321     }
322     slice = *p - '0';
323     p++;
324     if (isdigit(*p)) {
325         slice *= 10;
326         slice += (*p - '0');
327         p++;
328     }
329     slice = slice + 1;
330     if (!*p) {
331         part = 2;
332         if(c1->type == freebsd)
333             sprintf(buf2, "%sc", c1->name);
334         goto done;
335     }
336     if (*p < 'a' || *p > 'h') {
337         msgDebug("MakeDev: `%s' is not a valid partition name.\n", p);
338         return 0;
339     }
340     part = *p - 'a';
341  done:
342     if (isDebug())
343         msgDebug("MakeDev: Unit %d, Slice %d, Part %d\n", unit, slice, part);
344     if (unit > 32)
345         return 0;
346     if (slice > 32)
347         return 0;
348     if ((pwd = getpwnam("root")) == NULL) {
349         if (isDebug())
350             msgDebug("MakeDev: Unable to lookup user \"root\", using 0.\n");
351         owner = 0;
352     } else {
353         owner = pwd->pw_uid;
354     }
355     if ((grp = getgrnam("operator")) == NULL) {
356         if (isDebug())
357             msgDebug("MakeDev: Unable to lookup group \"operator\", using 5.\n");
358         group = 5;
359     } else {
360         group = grp->gr_gid;
361     }
362     min = unit * 8 + 65536 * slice + part;
363     sprintf(buf, "%s/r%s", path, c1->name);
364     unlink(buf);
365     if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
366         msgDebug("mknod of %s returned failure status!\n", buf);
367         return 0;
368     }
369     if (chown(buf, owner, group) == -1) {
370         msgDebug("chown of %s returned failure status!\n", buf);
371         return 0;
372     }
373     if (*buf2) {
374         sprintf(buf, "%s/r%s", path, buf2);
375         unlink(buf);
376         if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
377             msgDebug("mknod of %s returned failure status!\n", buf);
378             return 0;
379         }
380         if (chown(buf, owner, group) == -1) {
381             msgDebug("chown of %s returned failure status!\n", buf);
382             return 0;
383         }
384     }
385     sprintf(buf, "%s/%s", path, c1->name);
386     unlink(buf);
387     if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
388         msgDebug("mknod of %s returned failure status!\n", buf);
389         return 0;
390     }
391     if (chown(buf, owner, group) == -1) {
392         msgDebug("chown of %s returned failure status!\n", buf);
393         return 0;
394     }
395     return 1;
396 }
397
398 int
399 MakeDevChunk(struct chunk *c1, const char *path)
400 {
401     int i;
402
403     i = MakeDev(c1, path);
404     if (c1->next)
405         MakeDevChunk(c1->next, path);
406     if (c1->part)
407         MakeDevChunk(c1->part, path);
408     return i;
409 }
410
411 int
412 MakeDevDisk(struct disk *d, const char *path)
413 {
414     return MakeDevChunk(d->chunks, path);
415 }