Fully synchronize sys/boot from FreeBSD-5.x, but add / to the module path
[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.3 2003/11/10 06:14:40 dillon 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 #ifndef PC98
197         if (c2->type == extended)
198             Fixup_Extended_Names(d, c2);
199 #endif
200     }
201     return 0;
202 }
203
204 int
205 #ifdef PC98
206 Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags, const char *sname)
207 #else
208 Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags)
209 #endif
210 {
211     int i;
212     u_long l;
213     
214     if(!(flags & CHUNK_FORCE_ALL))
215     {
216 #ifdef PC98
217         /* Never use the first cylinder */
218         if (!offset) {
219             offset += (d->bios_sect * d->bios_hd);
220             size -= (d->bios_sect * d->bios_hd);
221         }
222 #else
223         /* Never use the first track */
224         if (!offset) {
225             offset += d->bios_sect;
226             size -= d->bios_sect;
227         }
228 #endif /* PC98 */
229         
230         /* Always end on cylinder boundary */
231         l = (offset+size) % (d->bios_sect * d->bios_hd);
232         size -= l;
233     }
234     
235 #ifdef PC98
236     i = Add_Chunk(d, offset, size, "X", type, subtype, flags, sname);
237 #else
238     i = Add_Chunk(d, offset, size, "X", type, subtype, flags);
239 #endif
240     Fixup_Names(d);
241     return i;
242 }
243
244 struct chunk *
245 Create_Chunk_DWIM(struct disk *d, struct chunk *parent , u_long size, chunk_e type, int subtype, u_long flags)
246 {
247     int i;
248     struct chunk *c1;
249     u_long offset;
250     
251     if (!parent)
252         parent = d->chunks;
253     for (c1=parent->part; c1; c1 = c1->next) {
254         if (c1->type != unused) continue;
255         if (c1->size < size) continue;
256         offset = c1->offset;
257         goto found;
258     }
259     return 0;
260  found:
261 #ifdef PC98
262     i = Add_Chunk(d, offset, size, "X", type, subtype, flags, "-");
263 #else
264     i = Add_Chunk(d, offset, size, "X", type, subtype, flags);
265 #endif
266     if (i)
267         return 0;
268     Fixup_Names(d);
269     for (c1=parent->part; c1; c1 = c1->next)
270         if (c1->offset == offset)
271             return c1;
272     /* barfout(1, "Serious internal trouble"); */
273     return 0;
274 }
275
276 int
277 MakeDev(struct chunk *c1, const char *path)
278 {
279     char *p = c1->name;
280     u_long cmaj, min, unit, part, slice;
281     char buf[BUFSIZ], buf2[BUFSIZ];
282     struct group *grp;
283     struct passwd *pwd;
284     uid_t owner;
285     gid_t group;
286
287     *buf2 = '\0';
288     if (isDebug())
289         msgDebug("MakeDev: Called with %s on path %s\n", p, path);
290     if (!strcmp(p, "X"))
291         return 0;
292
293     if (!strncmp(p, "ad", 2))
294         cmaj = 116, p += 2;
295 #ifdef PC98
296     else if (!strncmp(p, "wd", 2))
297         cmaj = 3, p += 2;
298 #endif
299     else if (!strncmp(p, "wfd", 3))
300         cmaj = 87, p += 3;
301     else if (!strncmp(p, "afd", 3))
302         cmaj = 118, p += 3;
303     else if (!strncmp(p, "fla", 3))
304         cmaj = 102, p += 3;
305     else if (!strncmp(p, "idad", 4))
306         cmaj = 109, p += 4;
307     else if (!strncmp(p, "mlxd", 4))
308         cmaj = 131, p += 4;
309     else if (!strncmp(p, "amrd", 4))
310         cmaj = 133, p += 4;
311     else if (!strncmp(p, "twed", 4))
312         cmaj = 147, p += 4;
313     else if (!strncmp(p, "aacd", 4))
314         cmaj = 151, p += 4;
315     else if (!strncmp(p, "ar", 2))      /* ATA RAID */
316         cmaj = 157, p += 2;
317     else if (!strncmp(p, "da", 2))      /* CAM support */
318         cmaj = 13, p += 2;
319     else {
320         msgDebug("MakeDev: Unknown major/minor for devtype %s\n", p);
321         return 0;
322     }
323     if (!isdigit(*p)) {
324         msgDebug("MakeDev: Invalid disk unit passed: %s\n", p);
325         return 0;
326     }
327     unit = *p - '0';
328     p++;
329     if (!*p) {
330         slice = 1;
331         part = 2;
332         goto done;
333     }
334     else if (isdigit(*p)) {
335         unit *= 10;
336         unit += (*p - '0');
337         p++;
338     }
339 #ifndef __alpha__
340     if (*p != 's') {
341         msgDebug("MakeDev: `%s' is not a valid slice delimiter\n", p);
342         return 0;
343     }
344     p++;
345     if (!isdigit(*p)) {
346         msgDebug("MakeDev: `%s' is an invalid slice number\n", p);
347         return 0;
348     }
349     slice = *p - '0';
350     p++;
351     if (isdigit(*p)) {
352         slice *= 10;
353         slice += (*p - '0');
354         p++;
355     }
356     slice = slice + 1;
357 #else
358     slice = 0;
359 #endif
360     if (!*p) {
361         part = 2;
362         if(c1->type == freebsd)
363             sprintf(buf2, "%sc", c1->name);
364         goto done;
365     }
366     if (*p < 'a' || *p > 'h') {
367         msgDebug("MakeDev: `%s' is not a valid partition name.\n", p);
368         return 0;
369     }
370     part = *p - 'a';
371  done:
372     if (isDebug())
373         msgDebug("MakeDev: Unit %d, Slice %d, Part %d\n", unit, slice, part);
374     if (unit > 32)
375         return 0;
376     if (slice > 32)
377         return 0;
378     if ((pwd = getpwnam("root")) == NULL) {
379         if (isDebug())
380             msgDebug("MakeDev: Unable to lookup user \"root\", using 0.\n");
381         owner = 0;
382     } else {
383         owner = pwd->pw_uid;
384     }
385     if ((grp = getgrnam("operator")) == NULL) {
386         if (isDebug())
387             msgDebug("MakeDev: Unable to lookup group \"operator\", using 5.\n");
388         group = 5;
389     } else {
390         group = grp->gr_gid;
391     }
392     min = unit * 8 + 65536 * slice + part;
393     sprintf(buf, "%s/r%s", path, c1->name);
394     unlink(buf);
395     if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
396         msgDebug("mknod of %s returned failure status!\n", buf);
397         return 0;
398     }
399     if (chown(buf, owner, group) == -1) {
400         msgDebug("chown of %s returned failure status!\n", buf);
401         return 0;
402     }
403     if (*buf2) {
404         sprintf(buf, "%s/r%s", path, buf2);
405         unlink(buf);
406         if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
407             msgDebug("mknod of %s returned failure status!\n", buf);
408             return 0;
409         }
410         if (chown(buf, owner, group) == -1) {
411             msgDebug("chown of %s returned failure status!\n", buf);
412             return 0;
413         }
414     }
415     sprintf(buf, "%s/%s", path, c1->name);
416     unlink(buf);
417     if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
418         msgDebug("mknod of %s returned failure status!\n", buf);
419         return 0;
420     }
421     if (chown(buf, owner, group) == -1) {
422         msgDebug("chown of %s returned failure status!\n", buf);
423         return 0;
424     }
425     return 1;
426 }
427
428 int
429 MakeDevChunk(struct chunk *c1, const char *path)
430 {
431     int i;
432
433     i = MakeDev(c1, path);
434     if (c1->next)
435         MakeDevChunk(c1->next, path);
436     if (c1->part)
437         MakeDevChunk(c1->part, path);
438     return i;
439 }
440
441 int
442 MakeDevDisk(struct disk *d, const char *path)
443 {
444     return MakeDevChunk(d->chunks, path);
445 }