Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / lib / libdisk / disk.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/disk.c,v 1.50.2.15 2001/12/30 09:56:12 phk Exp $
10  * $DragonFly: src/lib/libdisk/Attic/disk.c,v 1.2 2003/06/17 04:26:49 dillon Exp $
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <err.h>
20 #include <sys/sysctl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <sys/disklabel.h>
25 #include <sys/diskslice.h>
26 #include <paths.h>
27 #include "libdisk.h"
28
29 #define DOSPTYP_EXTENDED        5
30 #define DOSPTYP_ONTRACK         84
31
32 const char *chunk_n[] = {
33         "whole",
34         "unknown",
35         "fat",
36         "freebsd",
37         "extended",
38         "part",
39         "unused",
40         NULL
41 };
42
43 struct disk *
44 Open_Disk(const char *name)
45 {
46         return Int_Open_Disk(name, 0);
47 }
48
49 #ifndef PC98
50 static u_int32_t
51 Read_Int32(u_int32_t *p)
52 {
53     u_int8_t *bp = (u_int8_t *)p;
54     return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24);
55 }
56 #endif
57
58 struct disk *
59 Int_Open_Disk(const char *name, u_long size)
60 {
61         int i,fd;
62         struct diskslices ds;
63         struct disklabel dl;
64         char device[64], *buf;
65         struct disk *d;
66         u_long sector_size;
67 #ifdef PC98
68         unsigned char *p;
69 #else
70         struct dos_partition *dp;
71         void *p;
72 #endif
73         u_long offset = 0;
74
75         strcpy(device, _PATH_DEV);
76         strcat(device, name);
77
78         d = (struct disk *)malloc(sizeof *d);
79         if(!d) return NULL;
80         memset(d, 0, sizeof *d);
81
82         fd = open(device, O_RDONLY);
83         if (fd < 0) {
84 #ifdef DEBUG
85                 warn("open(%s) failed", device);
86 #endif
87                 return 0;
88         }
89
90         memset(&dl, 0, sizeof dl);
91         ioctl(fd, DIOCGDINFO, &dl);
92         i = ioctl(fd, DIOCGSLICEINFO, &ds);
93         if (i < 0) {
94 #ifdef DEBUG
95                 warn("DIOCGSLICEINFO(%s) failed", device);
96 #endif
97                 close(fd);
98                 return 0;
99         }
100
101 #ifdef DEBUG
102         for(i = 0; i < ds.dss_nslices; i++)
103                 if(ds.dss_slices[i].ds_openmask)
104                         printf("  open(%d)=0x%2x",
105                                 i, ds.dss_slices[i].ds_openmask);
106         printf("\n");
107 #endif
108
109 /* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
110 #ifdef PC98
111         if (!size)
112                 size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors;
113 #else
114         if (!size)
115                 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
116 #endif
117
118         /* determine media sector size */
119         if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
120                 return NULL;
121         for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
122                 if (read(fd, buf, sector_size) == sector_size) {
123                         d->sector_size = sector_size;
124                         break;
125                 }
126         }
127         free (buf);
128         if (sector_size > MAX_SEC_SIZE)
129                 return NULL; /* could not determine sector size */
130
131 #ifdef PC98
132         p = (unsigned char*)read_block(fd, 1, sector_size);
133 #else
134         p = read_block(fd, 0, sector_size);
135         dp = (struct dos_partition*)(p + DOSPARTOFF);
136         for (i = 0; i < NDOSPART; i++) {
137                 if (Read_Int32(&dp->dp_start) >= size)
138                     continue;
139                 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
140                     continue;
141                 if (!Read_Int32(&dp->dp_size))
142                     continue;
143
144                 if (dp->dp_typ == DOSPTYP_ONTRACK) {
145                         d->flags |= DISK_ON_TRACK;
146                         offset = 63;
147                 }
148
149         }
150         free(p);
151 #endif
152
153         d->bios_sect = dl.d_nsectors;
154         d->bios_hd = dl.d_ntracks;
155
156         d->name = strdup(name);
157
158
159         if (dl.d_ntracks && dl.d_nsectors)
160                 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
161
162 #ifdef PC98
163         if (Add_Chunk(d, -offset, size, name, whole, 0, 0, "-"))
164 #else
165         if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
166 #endif
167 #ifdef DEBUG
168                 warn("Failed to add 'whole' chunk");
169 #else
170                 {}
171 #endif
172
173 #ifdef __i386__
174 #ifdef PC98
175         /* XXX -- Quick Hack!
176          * Check MS-DOS MO
177          */
178         if ((*p == 0xf0 || *p == 0xf8) &&
179             (*(p+1) == 0xff) &&
180             (*(p+2) == 0xff)) {
181                 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
182             free(p);
183             goto pc98_mo_done;
184         }
185         free(p);
186 #endif /* PC98 */
187         for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
188                 char sname[20];
189                 chunk_e ce;
190                 u_long flags=0;
191                 int subtype=0;
192
193                 if (! ds.dss_slices[i].ds_size)
194                         continue;
195                 ds.dss_slices[i].ds_offset -= offset;
196                 sprintf(sname, "%ss%d", name, i - 1);
197 #ifdef PC98
198                 subtype = ds.dss_slices[i].ds_type |
199                         ds.dss_slices[i].ds_subtype << 8;
200                 switch (ds.dss_slices[i].ds_type & 0x7f) {
201                         case 0x14:
202                                 ce = freebsd;
203                                 break;
204                         case 0x20:
205                         case 0x21:
206                         case 0x22:
207                         case 0x23:
208                         case 0x24:
209                                 ce = fat;
210                                 break;
211 #else /* IBM-PC */
212                 subtype = ds.dss_slices[i].ds_type;
213                 switch (ds.dss_slices[i].ds_type) {
214                         case 0xa5:
215                                 ce = freebsd;
216                                 break;
217                         case 0x1:
218                         case 0x6:
219                         case 0x4:
220                         case 0xb:
221                         case 0xc:
222                         case 0xe:
223                                 ce = fat;
224                                 break;
225                         case DOSPTYP_EXTENDED:
226                         case 0xf:
227                                 ce = extended;
228                                 break;
229 #endif
230                         default:
231                                 ce = unknown;
232                                 break;
233                 }
234 #ifdef PC98
235                 if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
236                         ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
237                         ds.dss_slices[i].ds_name))
238 #else
239                 if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
240                         ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
241 #endif
242 #ifdef DEBUG
243                         warn("failed to add chunk for slice %d", i - 1);
244 #else
245                         {}
246 #endif
247
248 #ifdef PC98
249                 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
250 #else
251                 if (ds.dss_slices[i].ds_type != 0xa5)
252 #endif
253                         continue;
254                 {
255                 struct disklabel dl;
256                 char pname[20];
257                 int j, k;
258
259                 strcpy(pname, _PATH_DEV);
260                 strcat(pname, sname);
261                 j = open(pname, O_RDONLY);
262                 if (j < 0) {
263 #ifdef DEBUG
264                         warn("open(%s)", pname);
265 #endif
266                         continue;
267                 }
268                 k = ioctl(j, DIOCGDINFO, &dl);
269                 if (k < 0) {
270 #ifdef DEBUG
271                         warn("ioctl(%s, DIOCGDINFO)", pname);
272 #endif
273                         close(j);
274                         continue;
275                 }
276                 close(j);
277
278                 for(j = 0; j <= dl.d_npartitions; j++) {
279                         if (j == RAW_PART)
280                                 continue;
281                         if (j == 3)
282                                 continue;
283                         if (j == dl.d_npartitions) {
284                                 j = 3;
285                                 dl.d_npartitions = 0;
286                         }
287                         if (!dl.d_partitions[j].p_size)
288                                 continue;
289                         if (dl.d_partitions[j].p_size +
290                             dl.d_partitions[j].p_offset >
291                             ds.dss_slices[i].ds_size)
292                                 continue;
293                         sprintf(pname, "%s%c", sname, j + 'a');
294                         if (Add_Chunk(d,
295                                 dl.d_partitions[j].p_offset +
296                                 ds.dss_slices[i].ds_offset,
297                                 dl.d_partitions[j].p_size,
298                                 pname,part,
299                                 dl.d_partitions[j].p_fstype,
300 #ifdef PC98
301                                 0,
302                                 ds.dss_slices[i].ds_name) && j != 3)
303 #else
304                                 0) && j != 3)
305 #endif
306 #ifdef DEBUG
307                                 warn(
308                         "Failed to add chunk for partition %c [%lu,%lu]",
309                         j + 'a', dl.d_partitions[j].p_offset,
310                         dl.d_partitions[j].p_size);
311 #else
312                                 {}
313 #endif
314                 }
315                 }
316         }
317 #endif /* __i386__ */
318 #ifdef __alpha__
319         {
320                 struct disklabel dl;
321                 char pname[20];
322                 int j,k;
323
324                 strcpy(pname, _PATH_DEV);
325                 strcat(pname, name);
326                 j = open(pname, O_RDONLY);
327                 if (j < 0) {
328 #ifdef DEBUG
329                         warn("open(%s)", pname);
330 #endif
331                         goto nolabel;
332                 }
333                 k = ioctl(j, DIOCGDINFO, &dl);
334                 if (k < 0) {
335 #ifdef DEBUG
336                         warn("ioctl(%s, DIOCGDINFO)", pname);
337 #endif
338                         close(j);
339                         goto nolabel;
340                 }
341                 close(j);
342                 All_FreeBSD(d, 1);
343
344                 for(j = 0; j <= dl.d_npartitions; j++) {
345                         if (j == RAW_PART)
346                                 continue;
347                         if (j == 3)
348                                 continue;
349                         if (j == dl.d_npartitions) {
350                                 j = 3;
351                                 dl.d_npartitions = 0;
352                         }
353                         if (!dl.d_partitions[j].p_size)
354                                 continue;
355                         if (dl.d_partitions[j].p_size +
356                             dl.d_partitions[j].p_offset >
357                             ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
358                                 continue;
359                         sprintf(pname, "%s%c", name, j + 'a');
360                         if (Add_Chunk(d,
361                                       dl.d_partitions[j].p_offset,
362                                       dl.d_partitions[j].p_size,
363                                       pname,part,
364                                       dl.d_partitions[j].p_fstype,
365                                       0) && j != 3)
366 #ifdef DEBUG
367                                 warn(
368                                         "Failed to add chunk for partition %c [%lu,%lu]",
369                                         j + 'a', dl.d_partitions[j].p_offset,
370                                         dl.d_partitions[j].p_size);
371 #else
372                         {}
373 #endif
374                 }
375         nolabel:;
376         }
377 #endif /* __alpha__ */
378 #ifdef PC98
379 pc98_mo_done:
380 #endif
381         close(fd);
382         Fixup_Names(d);
383         return d;
384 }
385
386 void
387 Debug_Disk(struct disk *d)
388 {
389         printf("Debug_Disk(%s)", d->name);
390         printf("  flags=%lx", d->flags);
391 #if 0
392         printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
393 #endif
394         printf("  bios_geom=%lu/%lu/%lu = %lu\n",
395                 d->bios_cyl, d->bios_hd, d->bios_sect,
396                 d->bios_cyl * d->bios_hd * d->bios_sect);
397 #if defined(PC98)
398         printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
399                 d->boot1, d->boot2, d->bootipl, d->bootmenu);
400 #elif defined(__i386__)
401         printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
402                 d->boot1, d->boot2, d->bootmgr);
403 #elif defined(__alpha__)
404         printf("  boot1=%p, bootmgr=%p\n",
405                 d->boot1, d->bootmgr);
406 #endif
407         Debug_Chunk(d->chunks);
408 }
409
410 void
411 Free_Disk(struct disk *d)
412 {
413         if(d->chunks) Free_Chunk(d->chunks);
414         if(d->name) free(d->name);
415 #ifdef PC98
416         if(d->bootipl) free(d->bootipl);
417         if(d->bootmenu) free(d->bootmenu);
418 #else
419         if(d->bootmgr) free(d->bootmgr);
420 #endif
421         if(d->boot1) free(d->boot1);
422 #if defined(__i386__)
423         if(d->boot2) free(d->boot2);
424 #endif
425         free(d);
426 }
427
428 struct disk *
429 Clone_Disk(struct disk *d)
430 {
431         struct disk *d2;
432
433         d2 = (struct disk*) malloc(sizeof *d2);
434         if(!d2) return NULL;
435         *d2 = *d;
436         d2->name = strdup(d2->name);
437         d2->chunks = Clone_Chunk(d2->chunks);
438 #ifdef PC98
439         if(d2->bootipl) {
440                 d2->bootipl = malloc(d2->bootipl_size);
441                 memcpy(d2->bootipl, d->bootipl, d2->bootipl_size);
442         }
443         if(d2->bootmenu) {
444                 d2->bootmenu = malloc(d2->bootmenu_size);
445                 memcpy(d2->bootmenu, d->bootmenu, d2->bootmenu_size);
446         }
447 #else
448         if(d2->bootmgr) {
449                 d2->bootmgr = malloc(d2->bootmgr_size);
450                 memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
451         }
452 #endif
453 #if defined(__i386__)
454         if(d2->boot1) {
455                 d2->boot1 = malloc(512);
456                 memcpy(d2->boot1, d->boot1, 512);
457         }
458         if(d2->boot2) {
459                 d2->boot2 = malloc(512 * 15);
460                 memcpy(d2->boot2, d->boot2, 512 * 15);
461         }
462 #elif defined(__alpha__)
463         if(d2->boot1) {
464                 d2->boot1 = malloc(512 * 15);
465                 memcpy(d2->boot1, d->boot1, 512 * 15);
466         }
467 #endif
468         return d2;
469 }
470
471 #if 0
472 void
473 Collapse_Disk(struct disk *d)
474 {
475
476         while(Collapse_Chunk(d, d->chunks))
477                 ;
478 }
479 #endif
480
481 #ifdef PC98
482 static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
483 #else
484 static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
485 #endif
486
487 int qstrcmp(const void* a, const void* b) {
488
489         char *str1 = *(char**)a;
490         char *str2 = *(char**)b;
491         return strcmp(str1, str2);
492
493 }
494
495 char **
496 Disk_Names()
497 {
498     int i,j,disk_cnt;
499     char disk[25];
500     char diskname[25];
501     struct stat st;
502     struct diskslices ds;
503     int fd;
504     static char **disks;
505     int error;
506     size_t listsize;
507     char *disklist, **dp;
508
509     disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
510     memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
511 #if !defined(PC98) && !defined(KERN_DISKS_BROKEN)
512     error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
513     if (!error) {
514             disklist = (char *)malloc(listsize);
515             error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
516             if (error) 
517                     return NULL;
518             disk_cnt = 0;
519             for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) && 
520                          disk_cnt < MAX_NO_DISKS; disk_cnt++, dp++);
521     } else {
522     warn("kern.disks sysctl not available");
523 #endif
524     disk_cnt = 0;
525         for (j = 0; device_list[j]; j++) {
526                 if(disk_cnt >= MAX_NO_DISKS)
527                         break;
528                 for (i = 0; i < MAX_NO_DISKS; i++) {
529                         sprintf(diskname, "%s%d", device_list[j], i);
530                         sprintf(disk, _PATH_DEV"%s", diskname);
531                         if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
532                                 continue;
533                         if ((fd = open(disk, O_RDWR)) == -1)
534                                 continue;
535                         if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
536 #ifdef DEBUG
537                                 warn("DIOCGSLICEINFO %s", disk);
538 #endif
539                                 close(fd);
540                                 continue;
541                         }
542                         close(fd);
543                         disks[disk_cnt++] = strdup(diskname);
544                         if(disk_cnt >= MAX_NO_DISKS)
545                                 break;
546                 }
547         }
548 #if !defined(PC98) && !defined(KERN_DISKS_BROKEN)
549     }
550 #endif
551     qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
552     
553     return disks;
554 }
555
556 #ifdef PC98
557 void
558 Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
559              const u_char *bootmenu, const size_t bootmenu_size)
560 #else
561 void
562 Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
563 #endif
564 {
565 #ifdef PC98
566         if (bootipl_size % d->sector_size != 0)
567                 return;
568         if (d->bootipl)
569                 free(d->bootipl);
570         if (!bootipl) {
571                 d->bootipl = NULL;
572         } else {
573                 d->bootipl_size = bootipl_size;
574                 d->bootipl = malloc(bootipl_size);
575                 if(!d->bootipl) return;
576                 memcpy(d->bootipl, bootipl, bootipl_size);
577         }
578
579         if (bootmenu_size % d->sector_size != 0)
580                 return;
581         if (d->bootmenu)
582                 free(d->bootmenu);
583         if (!bootmenu) {
584                 d->bootmenu = NULL;
585         } else {
586                 d->bootmenu_size = bootmenu_size;
587                 d->bootmenu = malloc(bootmenu_size);
588                 if(!d->bootmenu) return;
589                 memcpy(d->bootmenu, bootmenu, bootmenu_size);
590         }
591 #else
592         if (s % d->sector_size != 0)
593                 return;
594         if (d->bootmgr)
595                 free(d->bootmgr);
596         if (!b) {
597                 d->bootmgr = NULL;
598         } else {
599                 d->bootmgr_size = s;
600                 d->bootmgr = malloc(s);
601                 if(!d->bootmgr) return;
602                 memcpy(d->bootmgr, b, s);
603         }
604 #endif
605 }
606
607 int
608 Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
609 {
610 #if defined(__i386__)
611         if (d->boot1) free(d->boot1);
612         d->boot1 = malloc(512);
613         if(!d->boot1) return -1;
614         memcpy(d->boot1, b1, 512);
615         if (d->boot2) free(d->boot2);
616         d->boot2 = malloc(15 * 512);
617         if(!d->boot2) return -1;
618         memcpy(d->boot2, b2, 15 * 512);
619 #elif defined(__alpha__)
620         if (d->boot1) free(d->boot1);
621         d->boot1 = malloc(15 * 512);
622         if(!d->boot1) return -1;
623         memcpy(d->boot1, b1, 15 * 512);
624 #endif
625         return 0;
626 }
627
628 const char *
629 slice_type_name( int type, int subtype )
630 {
631         switch (type) {
632                 case 0:         return "whole";
633 #ifndef PC98
634                 case 1:         switch (subtype) {
635                                         case 1:         return "fat (12-bit)";
636                                         case 2:         return "XENIX /";
637                                         case 3:         return "XENIX /usr";
638                                         case 4:         return "fat (16-bit,<=32Mb)";
639                                         case 5:         return "extended DOS";
640                                         case 6:         return "fat (16-bit,>32Mb)";
641                                         case 7:         return "NTFS/HPFS/QNX";
642                                         case 8:         return "AIX bootable";
643                                         case 9:         return "AIX data";
644                                         case 10:        return "OS/2 bootmgr";
645                                         case 11:        return "fat (32-bit)";
646                                         case 12:        return "fat (32-bit,LBA)";
647                                         case 14:        return "fat (16-bit,>32Mb,LBA)";
648                                         case 15:        return "extended DOS, LBA";
649                                         case 18:        return "Compaq Diagnostic";
650                                         case 84:        return "OnTrack diskmgr";
651                                         case 100:       return "Netware 2.x";
652                                         case 101:       return "Netware 3.x";
653                                         case 115:       return "SCO UnixWare";
654                                         case 128:       return "Minix 1.1";
655                                         case 129:       return "Minix 1.5";
656                                         case 130:       return "linux_swap";
657                                         case 131:       return "ext2fs";
658                                         case 166:       return "OpenBSD FFS";   /* 0xA6 */
659                                         case 169:       return "NetBSD FFS";    /* 0xA9 */
660                                         case 182:       return "OpenBSD";               /* dedicated */
661                                         case 183:       return "bsd/os";
662                                         case 184:       return "bsd/os swap";
663                                         default:        return "unknown";
664                                 }
665 #endif
666                 case 2:         return "fat";
667                 case 3:         switch (subtype) {
668 #ifdef  PC98
669                                         case 0xc494:    return "freebsd";
670 #else
671                                         case 165:       return "freebsd";
672 #endif
673                                         default:        return "unknown";
674                                 }
675 #ifndef PC98
676                 case 4:         return "extended";
677                 case 5:         return "part";
678                 case 6:         return "unused";
679 #endif
680                 default:        return "unknown";
681         }
682 }