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