]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - lib/libdisk/open_ia64_disk.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / lib / libdisk / open_ia64_disk.c
1 /*
2  * Copyright (c) 2003 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/types.h>
31 #include <sys/disklabel.h>
32 #include <sys/diskmbr.h>
33 #include <sys/gpt.h>
34 #include <sys/uuid.h>
35
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <paths.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <uuid.h>
44
45 #include "libdisk.h"
46
47 static uuid_t _efi = GPT_ENT_TYPE_EFI;
48 static uuid_t _mbr = GPT_ENT_TYPE_MBR;
49 static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD;
50 static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP;
51 static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS;
52
53 static struct disk *
54 parse_disk(char *conftxt, const char *name)
55 {
56         char devname[64];
57         struct disk *disk;
58         struct dos_partition *part;
59         struct gpt_hdr *gpt;
60         char *buffer, *p, *q;
61         int fd, i;
62
63         disk = (struct disk *)calloc(sizeof *disk, 1);
64         if (disk == NULL)
65                 return (NULL);
66
67         disk->name = strdup(name);
68         p = strsep(&conftxt, " ");                      /* media size */
69         disk->media_size = strtoimax(p, &q, 0);
70         if (*q)
71                 goto fail;
72
73         p = strsep(&conftxt, " ");                      /* sector size */
74         disk->sector_size = strtoul(p, &q, 0);
75         if (*q)
76                 goto fail;
77
78         if (disk->sector_size == 0)
79                 disk->sector_size = 512;
80
81         if (disk->media_size % disk->sector_size)
82                 goto fail;
83
84         /*
85          * We need to read the disk to get GPT specific information.
86          */
87
88         snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, name);
89         fd = open(devname, O_RDONLY);
90         if (fd == -1)
91                 goto fail;
92         buffer = malloc(2 * disk->sector_size);
93         if (buffer == NULL) {
94                 close (fd);
95                 goto fail;
96         }
97         if (read(fd, buffer, 2 * disk->sector_size) == -1) {
98                 free(buffer);
99                 close(fd);
100                 goto fail;
101         }
102         close(fd);
103
104         gpt = (struct gpt_hdr *)(buffer + disk->sector_size);
105         if (memcmp(gpt->hdr_sig, GPT_HDR_SIG, sizeof(gpt->hdr_sig))) {
106                 /*
107                  * No GPT present. Check if the MBR is empty (if present)
108                  * or is a PMBR before declaring this disk as empty. If
109                  * the MBR isn't empty, bail out. Let's not risk nuking a
110                  * disk.
111                  */
112                 if (*(u_short *)(buffer + DOSMAGICOFFSET) == DOSMAGIC) {
113                         for (i = 0; i < 4; i++) {
114                                 part = (struct dos_partition *)
115                                     (buffer + DOSPARTOFF + i * DOSPARTSIZE);
116                                 if (part->dp_typ != 0 &&
117                                     part->dp_typ != DOSPTYP_PMBR)
118                                         break;
119                         }
120                         if (i < 4) {
121                                 free(buffer);
122                                 goto fail;
123                         }
124                 }
125                 disk->gpt_size = 128;
126                 disk->lba_start = (disk->gpt_size * sizeof(struct gpt_ent)) /
127                     disk->sector_size + 2;
128                 disk->lba_end = (disk->media_size / disk->sector_size) -
129                     disk->lba_start;
130         } else {
131                 disk->lba_start = gpt->hdr_lba_start;
132                 disk->lba_end = gpt->hdr_lba_end;
133                 disk->gpt_size = gpt->hdr_entries;
134         }
135         free(buffer);
136         Add_Chunk(disk, disk->lba_start, disk->lba_end - disk->lba_start + 1,
137             name, whole, 0, 0, "-");
138         return (disk);
139
140 fail:
141         free(disk->name);
142         free(disk);
143         return (NULL);
144 }
145
146 struct disk *
147 Int_Open_Disk(const char *name, char *conftxt)
148 {
149         struct chunk chunk;
150         uuid_t uuid;
151         struct disk *disk;
152         char *p, *q, *r, *s, *sd, *type;
153         u_long i;
154         uint32_t status;
155
156         p = conftxt;
157         while (p != NULL && *p != 0) {
158                 q = strsep(&p, " ");
159                 if (strcmp(q, "0") == 0) {
160                         q = strsep(&p, " ");
161                         if (strcmp(q, "DISK") == 0) {
162                                 q = strsep(&p, " ");
163                                 if (strcmp(q, name) == 0)
164                                         break;
165                         }
166                 }
167                 p = strchr(p, '\n');
168                 if (p != NULL && *p == '\n')
169                         p++;
170                 conftxt = p;
171         }
172         if (p == NULL || *p == 0)
173                 return (NULL);
174
175         conftxt = strchr(p, '\n');
176         if (conftxt != NULL)
177                 *conftxt++ = '\0';
178
179         disk = parse_disk(p, name);
180         if (disk == NULL)
181                 return (NULL);
182
183         while (conftxt != NULL && *conftxt != 0) {
184                 p = conftxt;
185                 conftxt = strchr(p, '\n');
186                 if (conftxt != NULL)
187                         *conftxt++ = '\0';
188
189                 sd = strsep(&p, " ");                   /* depth */
190                 if (strcmp(sd, "0") == 0)
191                         break;
192
193                 type = strsep(&p, " ");                 /* type */
194                 chunk.name = strsep(&p, " ");           /* name */
195                 q = strsep(&p, " ");                    /* length */
196                 i = strtoimax(q, &r, 0);
197                 if (*r)
198                         abort();
199                 chunk.end = i / disk->sector_size;
200                 q = strsep(&p, " ");                    /* sector size */
201
202                 for (;;) {
203                         q = strsep(&p, " ");
204                         if (q == NULL)
205                                 break;
206                         r = strsep(&p, " ");
207                         i = strtoimax(r, &s, 0);
208                         if (*s) {
209                                 status = uuid_s_ok;
210                                 if (!strcmp(r, "efi"))
211                                         uuid = _efi;
212                                 else if (!strcmp(r, "mbr"))
213                                         uuid = _mbr;
214                                 else if (!strcmp(r, "freebsd"))
215                                         uuid = _fbsd;
216                                 else if (!strcmp(r, "freebsd-swap"))
217                                         uuid = _swap;
218                                 else if (!strcmp(r, "freebsd-ufs"))
219                                         uuid = _ufs;
220                                 else {
221                                         if (!strcmp(type, "PART"))
222                                                 uuid_from_string(r + 1, &uuid,
223                                                     &status);
224                                         else
225                                                 uuid_from_string(r, &uuid,
226                                                     &status);
227                                 }
228                         } else
229                                 status = uuid_s_invalid_string_uuid;
230                         if (!strcmp(q, "o"))
231                                 chunk.offset = i / disk->sector_size;
232                         else if (!strcmp(q, "i"))
233                                 chunk.flags = CHUNK_ITOF(i) | CHUNK_HAS_INDEX;
234                         else if (!strcmp(q, "ty"))
235                                 chunk.subtype = i;
236                 }
237
238                 if (strncmp(type, "MBR", 3) == 0) {
239                         switch (chunk.subtype) {
240                         case 0xa5:
241                                 chunk.type = freebsd;
242                                 break;
243                         case 0x01:
244                         case 0x04:
245                         case 0x06:
246                         case 0x0b:
247                         case 0x0c:
248                         case 0x0e:
249                                 chunk.type = fat;
250                                 break;
251                         case 0xef:      /* EFI */
252                                 chunk.type = efi;
253                                 break;
254                         default:
255                                 chunk.type = mbr;
256                                 break;
257                         }
258                 } else if (strcmp(type, "BSD") == 0) {
259                         chunk.type = part;
260                 } else if (strcmp(type, "GPT") == 0 ||
261                     strcmp(type, "PART") == 0) {
262                         chunk.subtype = 0;
263                         if (status != uuid_s_ok)
264                                 abort();
265                         if (uuid_is_nil(&uuid, NULL))
266                                 chunk.type = unused;
267                         else if (uuid_equal(&uuid, &_efi, NULL))
268                                 chunk.type = efi;
269                         else if (uuid_equal(&uuid, &_mbr, NULL))
270                                 chunk.type = mbr;
271                         else if (uuid_equal(&uuid, &_fbsd, NULL)) {
272                                 chunk.type = freebsd;
273                                 chunk.subtype = 0xa5;
274                         } else if (uuid_equal(&uuid, &_swap, NULL)) {
275                                 chunk.type = part;
276                                 chunk.subtype = FS_SWAP;
277                         } else if (uuid_equal(&uuid, &_ufs, NULL)) {
278                                 chunk.type = part;
279                                 chunk.subtype = FS_BSDFFS;
280                         } else
281                                 chunk.type = part;
282                 } else
283                         abort();
284
285                 Add_Chunk(disk, chunk.offset, chunk.end, chunk.name,
286                     chunk.type, chunk.subtype, chunk.flags, 0);
287         }
288
289         return (disk);
290 }