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