Explicitly specify `all' as the default target(as it used to be), so as
[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.4 2005/03/13 15:10:03 swildner 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 <sys/diskmbr.h>
27 #include <paths.h>
28 #include "libdisk.h"
29
30 #define DOSPTYP_EXTENDED        5
31 #define DOSPTYP_ONTRACK         84
32
33 const char *chunk_n[] = {
34         "whole",
35         "unknown",
36         "fat",
37         "freebsd",
38         "extended",
39         "part",
40         "unused",
41         NULL
42 };
43
44 struct disk *
45 Open_Disk(const char *name)
46 {
47         return Int_Open_Disk(name, 0);
48 }
49
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
57 struct disk *
58 Int_Open_Disk(const char *name, u_long size)
59 {
60         int i,fd;
61         struct diskslices ds;
62         struct disklabel dl;
63         char device[64], *buf;
64         struct disk *d;
65         u_long sector_size;
66         struct dos_partition *dp;
67         void *p;
68         u_long offset = 0;
69
70         strcpy(device, _PATH_DEV);
71         strcat(device, name);
72
73         d = (struct disk *)malloc(sizeof *d);
74         if(!d) return NULL;
75         memset(d, 0, sizeof *d);
76
77         fd = open(device, O_RDONLY);
78         if (fd < 0) {
79 #ifdef DEBUG
80                 warn("open(%s) failed", device);
81 #endif
82                 return 0;
83         }
84
85         memset(&dl, 0, sizeof dl);
86         ioctl(fd, DIOCGDINFO, &dl);
87         i = ioctl(fd, DIOCGSLICEINFO, &ds);
88         if (i < 0) {
89 #ifdef DEBUG
90                 warn("DIOCGSLICEINFO(%s) failed", device);
91 #endif
92                 close(fd);
93                 return 0;
94         }
95
96 #ifdef DEBUG
97         for(i = 0; i < ds.dss_nslices; i++)
98                 if(ds.dss_slices[i].ds_openmask)
99                         printf("  open(%d)=0x%2x",
100                                 i, ds.dss_slices[i].ds_openmask);
101         printf("\n");
102 #endif
103
104 /* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
105         if (!size)
106                 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
107
108         /* determine media sector size */
109         if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
110                 return NULL;
111         for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
112                 if (read(fd, buf, sector_size) == sector_size) {
113                         d->sector_size = sector_size;
114                         break;
115                 }
116         }
117         free (buf);
118         if (sector_size > MAX_SEC_SIZE)
119                 return NULL; /* could not determine sector size */
120
121         p = read_block(fd, 0, sector_size);
122         dp = (struct dos_partition*)(p + DOSPARTOFF);
123         for (i = 0; i < NDOSPART; i++) {
124                 if (Read_Int32(&dp->dp_start) >= size)
125                     continue;
126                 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
127                     continue;
128                 if (!Read_Int32(&dp->dp_size))
129                     continue;
130
131                 if (dp->dp_typ == DOSPTYP_ONTRACK) {
132                         d->flags |= DISK_ON_TRACK;
133                         offset = 63;
134                 }
135
136         }
137         free(p);
138
139         d->bios_sect = dl.d_nsectors;
140         d->bios_hd = dl.d_ntracks;
141
142         d->name = strdup(name);
143
144
145         if (dl.d_ntracks && dl.d_nsectors)
146                 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
147
148         if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
149 #ifdef DEBUG
150                 warn("Failed to add 'whole' chunk");
151 #else
152                 {}
153 #endif
154
155 #ifdef __i386__
156         for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
157                 char sname[20];
158                 chunk_e ce;
159                 u_long flags=0;
160                 int subtype=0;
161
162                 if (! ds.dss_slices[i].ds_size)
163                         continue;
164                 ds.dss_slices[i].ds_offset -= offset;
165                 sprintf(sname, "%ss%d", name, i - 1);
166                 subtype = ds.dss_slices[i].ds_type;
167                 switch (ds.dss_slices[i].ds_type) {
168                         case 0xa5:
169                                 ce = freebsd;
170                                 break;
171                         case 0x1:
172                         case 0x6:
173                         case 0x4:
174                         case 0xb:
175                         case 0xc:
176                         case 0xe:
177                                 ce = fat;
178                                 break;
179                         case DOSPTYP_EXTENDED:
180                         case 0xf:
181                                 ce = extended;
182                                 break;
183                         default:
184                                 ce = unknown;
185                                 break;
186                 }
187                 if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
188                         ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
189 #ifdef DEBUG
190                         warn("failed to add chunk for slice %d", i - 1);
191 #else
192                         {}
193 #endif
194
195                 if (ds.dss_slices[i].ds_type != 0xa5)
196                         continue;
197                 {
198                 struct disklabel dl;
199                 char pname[20];
200                 int j, k;
201
202                 strcpy(pname, _PATH_DEV);
203                 strcat(pname, sname);
204                 j = open(pname, O_RDONLY);
205                 if (j < 0) {
206 #ifdef DEBUG
207                         warn("open(%s)", pname);
208 #endif
209                         continue;
210                 }
211                 k = ioctl(j, DIOCGDINFO, &dl);
212                 if (k < 0) {
213 #ifdef DEBUG
214                         warn("ioctl(%s, DIOCGDINFO)", pname);
215 #endif
216                         close(j);
217                         continue;
218                 }
219                 close(j);
220
221                 for(j = 0; j <= dl.d_npartitions; j++) {
222                         if (j == RAW_PART)
223                                 continue;
224                         if (j == 3)
225                                 continue;
226                         if (j == dl.d_npartitions) {
227                                 j = 3;
228                                 dl.d_npartitions = 0;
229                         }
230                         if (!dl.d_partitions[j].p_size)
231                                 continue;
232                         if (dl.d_partitions[j].p_size +
233                             dl.d_partitions[j].p_offset >
234                             ds.dss_slices[i].ds_size)
235                                 continue;
236                         sprintf(pname, "%s%c", sname, j + 'a');
237                         if (Add_Chunk(d,
238                                 dl.d_partitions[j].p_offset +
239                                 ds.dss_slices[i].ds_offset,
240                                 dl.d_partitions[j].p_size,
241                                 pname,part,
242                                 dl.d_partitions[j].p_fstype,
243                                 0) && j != 3)
244 #ifdef DEBUG
245                                 warn(
246                         "Failed to add chunk for partition %c [%lu,%lu]",
247                         j + 'a', dl.d_partitions[j].p_offset,
248                         dl.d_partitions[j].p_size);
249 #else
250                                 {}
251 #endif
252                 }
253                 }
254         }
255 #endif /* __i386__ */
256         close(fd);
257         Fixup_Names(d);
258         return d;
259 }
260
261 void
262 Debug_Disk(struct disk *d)
263 {
264         printf("Debug_Disk(%s)", d->name);
265         printf("  flags=%lx", d->flags);
266 #if 0
267         printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
268 #endif
269         printf("  bios_geom=%lu/%lu/%lu = %lu\n",
270                 d->bios_cyl, d->bios_hd, d->bios_sect,
271                 d->bios_cyl * d->bios_hd * d->bios_sect);
272 #if defined(__i386__)
273         printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
274                 d->boot1, d->boot2, d->bootmgr);
275 #endif
276         Debug_Chunk(d->chunks);
277 }
278
279 void
280 Free_Disk(struct disk *d)
281 {
282         if(d->chunks) Free_Chunk(d->chunks);
283         if(d->name) free(d->name);
284         if(d->bootmgr) free(d->bootmgr);
285         if(d->boot1) free(d->boot1);
286 #if defined(__i386__)
287         if(d->boot2) free(d->boot2);
288 #endif
289         free(d);
290 }
291
292 struct disk *
293 Clone_Disk(struct disk *d)
294 {
295         struct disk *d2;
296
297         d2 = (struct disk*) malloc(sizeof *d2);
298         if(!d2) return NULL;
299         *d2 = *d;
300         d2->name = strdup(d2->name);
301         d2->chunks = Clone_Chunk(d2->chunks);
302         if(d2->bootmgr) {
303                 d2->bootmgr = malloc(d2->bootmgr_size);
304                 memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
305         }
306 #if defined(__i386__)
307         if(d2->boot1) {
308                 d2->boot1 = malloc(512);
309                 memcpy(d2->boot1, d->boot1, 512);
310         }
311         if(d2->boot2) {
312                 d2->boot2 = malloc(512 * 15);
313                 memcpy(d2->boot2, d->boot2, 512 * 15);
314         }
315 #endif
316         return d2;
317 }
318
319 #if 0
320 void
321 Collapse_Disk(struct disk *d)
322 {
323
324         while(Collapse_Chunk(d, d->chunks))
325                 ;
326 }
327 #endif
328
329 static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
330
331 int qstrcmp(const void* a, const void* b) {
332
333         char *str1 = *(char**)a;
334         char *str2 = *(char**)b;
335         return strcmp(str1, str2);
336
337 }
338
339 char **
340 Disk_Names()
341 {
342     int i,j,disk_cnt;
343     char disk[25];
344     char diskname[25];
345     struct stat st;
346     struct diskslices ds;
347     int fd;
348     static char **disks;
349     int error;
350     size_t listsize;
351     char *disklist, **dp;
352
353     disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
354     memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
355 #if !defined(KERN_DISKS_BROKEN)
356     error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
357     if (!error) {
358             disklist = (char *)malloc(listsize);
359             error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
360             if (error) 
361                     return NULL;
362             disk_cnt = 0;
363             for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) && 
364                          disk_cnt < MAX_NO_DISKS; disk_cnt++, dp++);
365     } else {
366     warn("kern.disks sysctl not available");
367 #endif
368     disk_cnt = 0;
369         for (j = 0; device_list[j]; j++) {
370                 if(disk_cnt >= MAX_NO_DISKS)
371                         break;
372                 for (i = 0; i < MAX_NO_DISKS; i++) {
373                         sprintf(diskname, "%s%d", device_list[j], i);
374                         sprintf(disk, _PATH_DEV"%s", diskname);
375                         if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
376                                 continue;
377                         if ((fd = open(disk, O_RDWR)) == -1)
378                                 continue;
379                         if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
380 #ifdef DEBUG
381                                 warn("DIOCGSLICEINFO %s", disk);
382 #endif
383                                 close(fd);
384                                 continue;
385                         }
386                         close(fd);
387                         disks[disk_cnt++] = strdup(diskname);
388                         if(disk_cnt >= MAX_NO_DISKS)
389                                 break;
390                 }
391         }
392 #if !defined(KERN_DISKS_BROKEN)
393     }
394 #endif
395     qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
396     
397     return disks;
398 }
399
400 void
401 Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
402 {
403         if (s % d->sector_size != 0)
404                 return;
405         if (d->bootmgr)
406                 free(d->bootmgr);
407         if (!b) {
408                 d->bootmgr = NULL;
409         } else {
410                 d->bootmgr_size = s;
411                 d->bootmgr = malloc(s);
412                 if(!d->bootmgr) return;
413                 memcpy(d->bootmgr, b, s);
414         }
415 }
416
417 int
418 Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
419 {
420 #if defined(__i386__)
421         if (d->boot1) free(d->boot1);
422         d->boot1 = malloc(512);
423         if(!d->boot1) return -1;
424         memcpy(d->boot1, b1, 512);
425         if (d->boot2) free(d->boot2);
426         d->boot2 = malloc(15 * 512);
427         if(!d->boot2) return -1;
428         memcpy(d->boot2, b2, 15 * 512);
429 #endif
430         return 0;
431 }
432
433 const char *
434 slice_type_name( int type, int subtype )
435 {
436         switch (type) {
437                 case 0:         return "whole";
438                 case 1:         switch (subtype) {
439                                         case 1:         return "fat (12-bit)";
440                                         case 2:         return "XENIX /";
441                                         case 3:         return "XENIX /usr";
442                                         case 4:         return "fat (16-bit,<=32Mb)";
443                                         case 5:         return "extended DOS";
444                                         case 6:         return "fat (16-bit,>32Mb)";
445                                         case 7:         return "NTFS/HPFS/QNX";
446                                         case 8:         return "AIX bootable";
447                                         case 9:         return "AIX data";
448                                         case 10:        return "OS/2 bootmgr";
449                                         case 11:        return "fat (32-bit)";
450                                         case 12:        return "fat (32-bit,LBA)";
451                                         case 14:        return "fat (16-bit,>32Mb,LBA)";
452                                         case 15:        return "extended DOS, LBA";
453                                         case 18:        return "Compaq Diagnostic";
454                                         case 84:        return "OnTrack diskmgr";
455                                         case 100:       return "Netware 2.x";
456                                         case 101:       return "Netware 3.x";
457                                         case 115:       return "SCO UnixWare";
458                                         case 128:       return "Minix 1.1";
459                                         case 129:       return "Minix 1.5";
460                                         case 130:       return "linux_swap";
461                                         case 131:       return "ext2fs";
462                                         case 166:       return "OpenBSD FFS";   /* 0xA6 */
463                                         case 169:       return "NetBSD FFS";    /* 0xA9 */
464                                         case 182:       return "OpenBSD";               /* dedicated */
465                                         case 183:       return "bsd/os";
466                                         case 184:       return "bsd/os swap";
467                                         default:        return "unknown";
468                                 }
469                 case 2:         return "fat";
470                 case 3:         switch (subtype) {
471                                         case 165:       return "freebsd";
472                                         default:        return "unknown";
473                                 }
474                 case 4:         return "extended";
475                 case 5:         return "part";
476                 case 6:         return "unused";
477                 default:        return "unknown";
478         }
479 }