]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libdisk/create_chunk.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.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$
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 <err.h>
26 #include <grp.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("/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 void
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;
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) err(1,"Malloc failed");
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 }
125
126 void
127 Fixup_Extended_Names(struct disk *d, struct chunk *c)
128 {
129     struct chunk *c1;
130     int j=5;
131     
132     for (c1 = c->part; c1 ; c1 = c1->next) {
133         if (c1->type == unused) continue;
134         free(c1->name);
135         c1->name = malloc(12);
136         if(!c1->name) err(1,"malloc failed");
137         sprintf(c1->name,"%ss%d",d->chunks->name,j++);
138         if (c1->type == freebsd)
139             Fixup_FreeBSD_Names(d,c1);
140     }
141 }
142
143 void
144 Fixup_Names(struct disk *d)
145 {
146     struct chunk *c1, *c2, *c3;
147     int i,j;
148     
149     c1 = d->chunks;
150     for(i=1,c2 = c1->part; c2 ; c2 = c2->next) {
151         c2->flags &= ~CHUNK_BSD_COMPAT;
152         if (c2->type == unused)
153             continue;
154         if (strcmp(c2->name,"X"))
155             continue;
156 #ifndef __alpha__
157         c2->oname = malloc(12);
158         if(!c2->oname) err(1,"malloc failed");
159         for(j=1;j<=NDOSPART;j++) {
160             sprintf(c2->oname,"%ss%d",c1->name,j);
161             for(c3 = c1->part; c3 ; c3 = c3->next)
162                 if (c3 != c2 && !strcmp(c3->name, c2->oname))
163                     goto match;
164             free(c2->name);
165             c2->name = c2->oname;
166             c2->oname = 0;
167             break;
168         match:
169             continue;
170         }
171         if (c2->oname)
172             free(c2->oname);
173 #else
174         free(c2->name);
175         c2->name = strdup(c1->name);
176 #endif
177     }
178     for(c2 = c1->part; c2 ; c2 = c2->next) {
179         if (c2->type == freebsd) {
180             c2->flags |= CHUNK_BSD_COMPAT;
181             break;
182         }
183     }
184     for(c2 = c1->part; c2 ; c2 = c2->next) {
185         if (c2->type == freebsd)
186             Fixup_FreeBSD_Names(d,c2);
187 #ifndef PC98
188         if (c2->type == extended)
189             Fixup_Extended_Names(d,c2);
190 #endif
191     }
192 }
193
194 int
195 #ifdef PC98
196 Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags, const char *sname)
197 #else
198 Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags)
199 #endif
200 {
201     int i;
202     u_long l;
203     
204     if(!(flags & CHUNK_FORCE_ALL))
205     {
206 #ifdef PC98
207         /* Never use the first cylinder */
208         if (!offset) {
209             offset += (d->bios_sect * d->bios_hd);
210             size -= (d->bios_sect * d->bios_hd);
211         }
212 #else
213         /* Never use the first track */
214         if (!offset) {
215             offset += d->bios_sect;
216             size -= d->bios_sect;
217         }
218 #endif
219         
220         /* Always end on cylinder boundary */
221         l = (offset+size) % (d->bios_sect * d->bios_hd);
222         size -= l;
223     }
224     
225 #ifdef PC98
226     i = Add_Chunk(d,offset,size,"X",type,subtype,flags,sname);
227 #else
228     i = Add_Chunk(d,offset,size,"X",type,subtype,flags);
229 #endif
230     Fixup_Names(d);
231     return i;
232 }
233
234 struct chunk *
235 Create_Chunk_DWIM(struct disk *d, struct chunk *parent , u_long size, chunk_e type, int subtype, u_long flags)
236 {
237     int i;
238     struct chunk *c1;
239     u_long offset;
240     
241     if (!parent)
242         parent = d->chunks;
243     for (c1=parent->part; c1 ; c1 = c1->next) {
244         if (c1->type != unused) continue;
245         if (c1->size < size) continue;
246         offset = c1->offset;
247         goto found;
248     }
249     return 0;
250  found:
251 #ifdef PC98
252     i = Add_Chunk(d,offset,size,"X",type,subtype,flags,"-");
253 #else
254     i = Add_Chunk(d,offset,size,"X",type,subtype,flags);
255 #endif
256     if (i)
257         return 0;
258     Fixup_Names(d);
259     for (c1=parent->part; c1 ; c1 = c1->next)
260         if (c1->offset == offset)
261             return c1;
262     err(1,"Serious internal trouble");
263 }
264
265 int
266 MakeDev(struct chunk *c1, const char *path)
267 {
268     char *p = c1->name;
269     u_long cmaj, min, unit, part, slice;
270     char buf[BUFSIZ], buf2[BUFSIZ];
271     struct group *grp;
272     struct passwd *pwd;
273     uid_t owner;
274     gid_t group;
275
276     *buf2 = '\0';
277     if (isDebug())
278         msgDebug("MakeDev: Called with %s on path %s\n", p, path);
279     if (!strcmp(p, "X"))
280         return 0;
281     
282     if (!strncmp(p, "wd", 2))
283         cmaj = 3, p += 2;
284     else if (!strncmp(p, "ad", 2))
285         cmaj = 116, p += 2;
286     else if (!strncmp(p, "wfd", 3))
287         cmaj = 87, p += 3;
288     else if (!strncmp(p, "afd", 3))
289         cmaj = 118, p += 3;
290     else if (!strncmp(p, "fla", 3))
291         cmaj = 102, p += 3;
292     else if (!strncmp(p, "idad", 4))
293         cmaj = 109, p += 4;
294     else if (!strncmp(p, "mlxd", 4))
295         cmaj = 131, p += 4;
296     else if (!strncmp(p, "amrd", 4))
297         cmaj = 133, p += 4;
298     else if (!strncmp(p, "da", 2))      /* CAM support */
299         cmaj = 13, p += 2;
300     else {
301         msgDebug("MakeDev: Unknown major/minor for devtype %s\n", p);
302         return 0;
303     }
304     if (!isdigit(*p)) {
305         msgDebug("MakeDev: Invalid disk unit passed: %s\n", p);
306         return 0;
307     }
308     unit = *p - '0';
309     p++;
310     if (!*p) {
311         slice = 1;
312         part = 2;
313         goto done;
314     }
315     else if (isdigit(*p)) {
316         unit *= 10;
317         unit += (*p - '0');
318         p++;
319     }
320 #ifndef __alpha__
321     if (*p != 's') {
322         msgDebug("MakeDev: `%s' is not a valid slice delimiter\n", p);
323         return 0;
324     }
325     p++;
326     if (!isdigit(*p)) {
327         msgDebug("MakeDev: `%s' is an invalid slice number\n", p);
328         return 0;
329     }
330     slice = *p - '0';
331     p++;
332     if (isdigit(*p)) {
333         slice *= 10;
334         slice += (*p - '0');
335         p++;
336     }
337     slice = slice + 1;
338 #else
339     slice = 0;
340 #endif
341     if (!*p) {
342         part = 2;
343         if(c1->type == freebsd)
344             sprintf(buf2, "%sc", c1->name);
345         goto done;
346     }
347     if (*p < 'a' || *p > 'h') {
348         msgDebug("MakeDev: `%s' is not a valid partition name.\n", p);
349         return 0;
350     }
351     part = *p - 'a';
352  done:
353     if (isDebug())
354         msgDebug("MakeDev: Unit %d, Slice %d, Part %d\n", unit, slice, part);
355     if (unit > 32)
356         return 0;
357     if (slice > 32)
358         return 0;
359     if ((pwd = getpwnam("root")) == NULL) {
360         if (isDebug())
361             msgDebug("MakeDev: Unable to lookup user \"root\", using 0.\n");
362         owner = 0;
363     } else {
364         owner = pwd->pw_uid;
365     }
366     if ((grp = getgrnam("operator")) == NULL) {
367         if (isDebug())
368             msgDebug("MakeDev: Unable to lookup group \"operator\", using 5.\n");
369         group = 5;
370     } else {
371         group = grp->gr_gid;
372     }
373     min = unit * 8 + 65536 * slice + part;
374     sprintf(buf, "%s/r%s", path, c1->name);
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     if (*buf2) {
385         sprintf(buf, "%s/r%s", path, buf2);
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     }
396     sprintf(buf, "%s/%s", path, c1->name);
397     unlink(buf);
398     if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) {
399         msgDebug("mknod of %s returned failure status!\n", buf);
400         return 0;
401     }
402     if (chown(buf, owner, group) == -1) {
403         msgDebug("chown of %s returned failure status!\n", buf);
404         return 0;
405     }
406     return 1;
407 }
408
409 int
410 MakeDevChunk(struct chunk *c1, const char *path)
411 {
412     int i;
413
414     i = MakeDev(c1, path);
415     if (c1->next)
416         MakeDevChunk(c1->next, path);
417     if (c1->part)
418         MakeDevChunk(c1->part, path);
419     return i;
420 }
421
422 int
423 MakeDevDisk(struct disk *d, const char *path)
424 {
425     return MakeDevChunk(d->chunks, path);
426 }