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