Upload Tizen:Base source
[framework/base/util-linux-ng.git] / fdisk / gpt.c
1 /*
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16  *
17  *
18  * GPT (GUID Partition Table) signature detection. Based on libparted and
19  * util-linux/partx.
20  *
21  * Warning: this code doesn't do all GPT checks (CRC32, Protective MBR, ..).
22  *          It's really GPT signature detection only.
23  *
24  * Copyright (C) 2007 Karel Zak <kzak@redhat.com>
25  *
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <inttypes.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <sys/utsname.h>
35 #include <sys/types.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
39
40 #include "gpt.h"
41 #include "blkdev.h"
42 #include "bitops.h"
43
44 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
45 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1
46
47 typedef struct {
48         uint32_t time_low;
49         uint16_t time_mid;
50         uint16_t time_hi_and_version;
51         uint8_t  clock_seq_hi_and_reserved;
52         uint8_t  clock_seq_low;
53         uint8_t  node[6];
54 } /* __attribute__ ((packed)) */ efi_guid_t;
55 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
56  * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
57  * data.  It turns out we don't need it in this case, so it doesn't break
58  * anything :)
59  */
60
61 typedef struct _GuidPartitionTableHeader_t {
62         uint64_t Signature;
63         uint32_t Revision;
64         uint32_t HeaderSize;
65         uint32_t HeaderCRC32;
66         uint32_t Reserved1;
67         uint64_t MyLBA;
68         uint64_t AlternateLBA;
69         uint64_t FirstUsableLBA;
70         uint64_t LastUsableLBA;
71         efi_guid_t DiskGUID;
72         uint64_t PartitionEntryLBA;
73         uint32_t NumberOfPartitionEntries;
74         uint32_t SizeOfPartitionEntry;
75         uint32_t PartitionEntryArrayCRC32;
76         uint8_t Reserved2[512 - 92];
77 } __attribute__ ((packed)) GuidPartitionTableHeader_t;
78
79 static int
80 _get_sector_size (int fd)
81 {
82         int sector_size;
83
84         if (blkdev_get_sector_size(fd, &sector_size) == -1)
85                 return DEFAULT_SECTOR_SIZE;
86         return sector_size;
87 }
88
89 static uint64_t
90 _get_num_sectors(int fd)
91 {
92         unsigned long long bytes=0;
93
94         if (blkdev_get_size(fd, &bytes) == -1)
95                 return 0;
96         return bytes / _get_sector_size(fd);
97 }
98
99 static uint64_t
100 last_lba(int fd)
101 {
102         int rc;
103         uint64_t sectors = 0;
104         struct stat s;
105
106         memset(&s, 0, sizeof (s));
107         rc = fstat(fd, &s);
108         if (rc == -1)
109         {
110                 fprintf(stderr, "last_lba() could not stat: %s\n",
111                         strerror(errno));
112                 return 0;
113         }
114         if (S_ISBLK(s.st_mode))
115                 sectors = _get_num_sectors(fd);
116         else if (S_ISREG(s.st_mode))
117                 sectors = s.st_size >> _get_sector_size(fd);
118         else
119         {
120                 fprintf(stderr,
121                         "last_lba(): I don't know how to handle files with mode %o\n",
122                         s.st_mode);
123                 sectors = 1;
124         }
125         return sectors - 1;
126 }
127
128 static ssize_t
129 read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
130 {
131         int sector_size = _get_sector_size(fd);
132         off_t offset = lba * sector_size;
133
134         lseek(fd, offset, SEEK_SET);
135         return read(fd, buffer, bytes);
136 }
137
138 static GuidPartitionTableHeader_t *
139 alloc_read_gpt_header(int fd, uint64_t lba)
140 {
141         GuidPartitionTableHeader_t *gpt =
142                 (GuidPartitionTableHeader_t *) malloc(sizeof (GuidPartitionTableHeader_t));
143         if (!gpt)
144                 return NULL;
145         memset(gpt, 0, sizeof (*gpt));
146         if (!read_lba(fd, lba, gpt, sizeof (GuidPartitionTableHeader_t)))
147         {
148                 free(gpt);
149                 return NULL;
150         }
151         return gpt;
152 }
153
154 static int
155 gpt_check_signature(int fd, uint64_t lba)
156 {
157         GuidPartitionTableHeader_t *gpt;
158         int res=0;
159
160         if ((gpt = alloc_read_gpt_header(fd, lba)))
161         {
162                 if (gpt->Signature == cpu_to_le64(GPT_HEADER_SIGNATURE))
163                         res = 1;
164                 free(gpt);
165         }
166         return res;
167 }
168
169 /* returns:
170  *      0 not found GPT
171  *      1 for valid primary GPT header
172  *      2 for valid alternative GPT header
173  */
174 int
175 gpt_probe_signature_fd(int fd)
176 {
177         int res = 0;
178
179         /* check primary GPT header */
180         if (gpt_check_signature(fd, GPT_PRIMARY_PARTITION_TABLE_LBA))
181                 res = 1;
182         else
183         {
184                 /* check alternative GPT header */
185                 uint64_t lastlba = last_lba(fd);
186                 if (gpt_check_signature(fd, lastlba))
187                         res = 2;
188         }
189         return res;
190 }
191
192 int
193 gpt_probe_signature_devname(char *devname)
194 {
195         int res, fd;
196         if ((fd = open(devname, O_RDONLY)) < 0)
197                 return 0;
198         res = gpt_probe_signature_fd(fd);
199         close(fd);
200         return res;
201 }
202
203 #ifdef GPT_TEST_MAIN
204 int
205 main(int argc, char **argv)
206 {
207         if (argc!=2)
208         {
209                 fprintf(stderr, "usage: %s <dev>\n", argv[0]);
210                 exit(EXIT_FAILURE);
211         }
212         if (gpt_probe_signature_devname(argv[1]))
213                 printf("GPT (GUID Partition Table) detected on %s\n", argv[1]);
214         exit(EXIT_SUCCESS);
215 }
216 #endif