blob: aedf4e83bb2bc187a5ee26361353ef654c3af1a3 [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001
2#include <ctype.h>
3
4#include "nls.h"
5#include "fdiskP.h"
6
7/**
8 * SECTION: parttype
9 * @title: Partition types
10 * @short_description: abstraction to partition types
11 *
12 * There are two basic types of parttypes, string based (e.g. GPT)
13 * and code/hex based (e.g. MBR).
14 */
15
16/**
17 * fdisk_new_parttype:
18 *
19 * It's recommended to use fdisk_label_get_parttype_from_code() or
20 * fdisk_label_get_parttype_from_string() for well known types rather
21 * than allocate a new instance.
22 *
23 * Returns: new instance.
24 */
25struct fdisk_parttype *fdisk_new_parttype(void)
26{
27 struct fdisk_parttype *t = calloc(1, sizeof(*t));
28
29 t->refcount = 1;
30 t->flags = FDISK_PARTTYPE_ALLOCATED;
31 DBG(PARTTYPE, ul_debugobj(t, "alloc"));
32 return t;
33}
34
35/**
36 * fdisk_ref_parttype:
37 * @t: partition type
38 *
39 * Incremparts reference counter for allocated types
40 */
41void fdisk_ref_parttype(struct fdisk_parttype *t)
42{
43 if (fdisk_parttype_is_allocated(t))
44 t->refcount++;
45}
46
47/**
48 * fdisk_unref_parttype
49 * @t: partition pointer
50 *
51 * De-incremparts reference counter, on zero the @t is automatically
52 * deallocated.
53 */
54void fdisk_unref_parttype(struct fdisk_parttype *t)
55{
56 if (!fdisk_parttype_is_allocated(t))
57 return;
58
59 t->refcount--;
60 if (t->refcount <= 0) {
61 DBG(PARTTYPE, ul_debugobj(t, "free"));
62 free(t->typestr);
63 free(t->name);
64 free(t);
65 }
66}
67
68/**
69 * fdisk_parttype_set_name:
70 * @t: partition type
71 * @str: type name
72 *
73 * Sets type name to allocated partition type, for static types
74 * it returns -EINVAL.
75 *
76 * Return: 0 on success, <0 on error
77 */
78int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str)
79{
80 char *p = NULL;
81
82 if (!t || !fdisk_parttype_is_allocated(t))
83 return -EINVAL;
84 if (str) {
85 p = strdup(str);
86 if (!p)
87 return -ENOMEM;
88 }
89
90 free(t->name);
91 t->name = p;
92 return 0;
93}
94
95/**
96 * fdisk_parttype_set_typestr:
97 * @t: partition type
98 * @str: type identificator (e.g. GUID for GPT)
99 *
100 * Sets type string to allocated partition type, for static types
101 * it returns -EINVAL. Don't use this function for MBR, see
102 * fdisk_parttype_set_code().
103 *
104 * Return: 0 on success, <0 on error
105 */
106int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str)
107{
108 char *p = NULL;
109
110 if (!t || !fdisk_parttype_is_allocated(t))
111 return -EINVAL;
112 if (str) {
113 p = strdup(str);
114 if (!p)
115 return -ENOMEM;
116 }
117
118 free(t->typestr);
119 t->typestr = p;
120 return 0;
121}
122
123/**
124 * fdisk_parttype_set_code:
125 * @t: partition type
126 * @code: type identificator (e.g. MBR type codes)
127 *
128 * Sets type code to allocated partition type, for static types it returns
129 * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr().
130 *
131 * Return: 0 on success, <0 on error
132 */
133int fdisk_parttype_set_code(struct fdisk_parttype *t, int code)
134{
135 if (!t || !fdisk_parttype_is_allocated(t))
136 return -EINVAL;
137 t->code = code;
138 return 0;
139}
140
141/**
142 * fdisk_label_get_nparttypes:
143 * @lb: label
144 *
145 * Returns: number of types supported by label.
146 */
147size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb)
148{
149 if (!lb)
150 return 0;
151 return lb->nparttypes;
152}
153
154/**
155 * fdisk_label_get_parttype:
156 * @lb: label
157 * @n: number
158 *
159 * Returns: return parttype
160 */
161struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n)
162{
163 if (!lb || n >= lb->nparttypes)
164 return NULL;
165 return &lb->parttypes[n];
166}
167
168/**
169 * fdisk_label_has_code_parttypes:
170 * @lb: label
171 *
172 * Returns: 1 if the label uses code as partition type
173 * identifiers (e.g. MBR) or 0.
174 */
175int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
176{
177 assert(lb);
178
179 if (lb->parttypes && lb->parttypes[0].typestr)
180 return 0;
181 return 1;
182}
183
184
185/**
186 * fdisk_label_get_parttype_from_code:
187 * @lb: label
188 * @code: code to search for
189 *
190 * Search for partition type in label-specific table. The result
191 * is pointer to static array of label types.
192 *
193 * Returns: partition type or NULL upon failure or invalid @code.
194 */
195struct fdisk_parttype *fdisk_label_get_parttype_from_code(
196 const struct fdisk_label *lb,
197 unsigned int code)
198{
199 size_t i;
200
201 assert(lb);
202
203 if (!lb->nparttypes)
204 return NULL;
205
206 for (i = 0; i < lb->nparttypes; i++)
207 if (lb->parttypes[i].code == code)
208 return &lb->parttypes[i];
209 return NULL;
210}
211
212/**
213 * fdisk_label_get_parttype_from_string:
214 * @lb: label
215 * @str: string to search for
216 *
217 * Search for partition type in label-specific table. The result
218 * is pointer to static array of label types.
219 *
220 * Returns: partition type or NULL upon failure or invalid @str.
221 */
222struct fdisk_parttype *fdisk_label_get_parttype_from_string(
223 const struct fdisk_label *lb,
224 const char *str)
225{
226 size_t i;
227
228 assert(lb);
229
230 if (!lb->nparttypes)
231 return NULL;
232
233 for (i = 0; i < lb->nparttypes; i++)
234 if (lb->parttypes[i].typestr
235 && strcasecmp(lb->parttypes[i].typestr, str) == 0)
236 return &lb->parttypes[i];
237
238 return NULL;
239}
240
241/**
242 * fdisk_new_unknown_parttype:
243 * @code: type as number
244 * @typestr: type as string
245
246 * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to
247 * deallocate.
248 *
249 * Returns: newly allocated partition type, or NULL upon failure.
250 */
251struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
252 const char *typestr)
253{
254 struct fdisk_parttype *t = fdisk_new_parttype();
255
256 if (!t)
257 return NULL;
258
259 fdisk_parttype_set_name(t, _("unknown"));
260 fdisk_parttype_set_code(t, code);
261 fdisk_parttype_set_typestr(t, typestr);
262 t->flags |= FDISK_PARTTYPE_UNKNOWN;
263
264 return t;
265}
266
267/**
268 * fdisk_copy_parttype:
269 * @type: type to copy
270 *
271 * Use fdisk_unref_parttype() to deallocate.
272 *
273 * Returns: newly allocated partition type, or NULL upon failure.
274 */
275struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
276{
277 struct fdisk_parttype *t = fdisk_new_parttype();
278
279 if (!t)
280 return NULL;
281
282 fdisk_parttype_set_name(t, type->name);
283 fdisk_parttype_set_code(t, type->code);
284 fdisk_parttype_set_typestr(t, type->typestr);
285
286 return t;
287}
288
289/**
290 * fdisk_label_parse_parttype:
291 * @lb: label
292 * @str: string to parse from
293 *
294 * Parses partition type from @str according to the label. Thefunction returns
295 * a pointer to static table of the partition types, or newly allocated
296 * partition type for unknown types (see fdisk_parttype_is_unknown(). It's
297 * safe to call fdisk_unref_parttype() for all results.
298 *
299 * Returns: pointer to type or NULL on error.
300 */
301struct fdisk_parttype *fdisk_label_parse_parttype(
302 const struct fdisk_label *lb,
303 const char *str)
304{
305 struct fdisk_parttype *types, *ret;
306 unsigned int code = 0;
307 char *typestr = NULL, *end = NULL;
308
309 assert(lb);
310
311 if (!lb->nparttypes)
312 return NULL;
313
314 DBG(LABEL, ul_debugobj((void *) lb, "parsing '%s' (%s) partition type",
315 str, lb->name));
316 types = lb->parttypes;
317
318 if (types[0].typestr == NULL && isxdigit(*str)) {
319
320 errno = 0;
321 code = strtol(str, &end, 16);
322
323 if (errno || *end != '\0') {
324 DBG(LABEL, ul_debugobj((void *) lb, "parsing failed: %m"));
325 return NULL;
326 }
327 ret = fdisk_label_get_parttype_from_code(lb, code);
328 if (ret)
329 goto done;
330 } else {
331 int i;
332
333 /* maybe specified by type string (e.g. UUID) */
334 ret = fdisk_label_get_parttype_from_string(lb, str);
335 if (ret)
336 goto done;
337
338 /* maybe specified by order number */
339 errno = 0;
340 i = strtol(str, &end, 0);
341 if (errno == 0 && *end == '\0' && i > 0
342 && i - 1 < (int) lb->nparttypes) {
343 ret = &types[i - 1];
344 goto done;
345 }
346 }
347
348 ret = fdisk_new_unknown_parttype(code, typestr);
349done:
350 DBG(PARTTYPE, ul_debugobj(ret, "returns parsed '%s' partition type", ret->name));
351 return ret;
352}
353
354/**
355 * fdisk_parttype_get_string:
356 * @t: type
357 *
358 * Returns: partition type string (e.g. GUID for GPT)
359 */
360const char *fdisk_parttype_get_string(const struct fdisk_parttype *t)
361{
362 assert(t);
363 return t->typestr && *t->typestr ? t->typestr : NULL;
364}
365
366/**
367 * fdisk_parttype_get_code:
368 * @t: type
369 *
370 * Returns: partition type code (e.g. for MBR)
371 */
372unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t)
373{
374 assert(t);
375 return t->code;
376}
377
378/**
379 * fdisk_parttype_get_name:
380 * @t: type
381 *
382 * Returns: partition type human readable name
383 */
384const char *fdisk_parttype_get_name(const struct fdisk_parttype *t)
385{
386 assert(t);
387 return t->name;
388}
389
390/**
391 * fdisk_parttype_is_unknown:
392 * @t: type
393 *
394 * Checks for example result from fdisk_label_parse_parttype().
395 *
396 * Returns: 1 is type is "unknonw" or 0.
397 */
398int fdisk_parttype_is_unknown(const struct fdisk_parttype *t)
399{
400 return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0;
401}