]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/parttype.c
libfdisk: add partition type aliases and shortcuts
[thirdparty/util-linux.git] / libfdisk / src / parttype.c
1
2 #include <ctype.h>
3
4 #include "fdiskP.h"
5 #include "strutils.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 */
25 struct 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 * Increments reference counter for allocated types
40 */
41 void 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 * Decrements reference counter, on zero the @t is automatically
52 * deallocated.
53 */
54 void 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 */
78 int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str)
79 {
80 if (!t || !fdisk_parttype_is_allocated(t))
81 return -EINVAL;
82 return strdup_to_struct_member(t, name, str);
83 }
84
85 /**
86 * fdisk_parttype_set_typestr:
87 * @t: partition type
88 * @str: type identifier (e.g. GUID for GPT)
89 *
90 * Sets type string to allocated partition type, for static types
91 * it returns -EINVAL. Don't use this function for MBR, see
92 * fdisk_parttype_set_code().
93 *
94 * Return: 0 on success, <0 on error
95 */
96 int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str)
97 {
98 if (!t || !fdisk_parttype_is_allocated(t))
99 return -EINVAL;
100 return strdup_to_struct_member(t, typestr, str);
101 }
102
103 /**
104 * fdisk_parttype_set_code:
105 * @t: partition type
106 * @code: type identifier (e.g. MBR type codes)
107 *
108 * Sets type code to allocated partition type, for static types it returns
109 * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr().
110 *
111 * Return: 0 on success, <0 on error
112 */
113 int fdisk_parttype_set_code(struct fdisk_parttype *t, int code)
114 {
115 if (!t || !fdisk_parttype_is_allocated(t))
116 return -EINVAL;
117 t->code = code;
118 return 0;
119 }
120
121 /**
122 * fdisk_label_get_nparttypes:
123 * @lb: label
124 *
125 * Returns: number of types supported by label.
126 */
127 size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb)
128 {
129 if (!lb)
130 return 0;
131 return lb->nparttypes;
132 }
133
134 /**
135 * fdisk_label_get_parttype:
136 * @lb: label
137 * @n: number
138 *
139 * Returns: return parttype
140 */
141 struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n)
142 {
143 if (!lb || n >= lb->nparttypes)
144 return NULL;
145 return &lb->parttypes[n];
146 }
147
148 /**
149 * fdisk_label_get_parttype_shortcut:
150 * @lb: label
151 * @n: number
152 * @typestr: returns type as string
153 * @shortcut: returns type shortcut string
154 * @alias: returns type alias string
155 *
156 * Returns: return 0 on success, <0 on error, 2 for deprecated alias, 1 for @n out of range
157 *
158 * Since: v2.36
159 */
160 int fdisk_label_get_parttype_shortcut(const struct fdisk_label *lb, size_t n,
161 const char **typestr, const char **shortcut, const char **alias)
162 {
163 const struct fdisk_shortcut *sc;
164
165 if (!lb)
166 return -EINVAL;
167 if (n >= lb->nparttype_cuts)
168 return 1;
169
170 sc = &lb->parttype_cuts[n];
171 if (typestr)
172 *typestr = sc->data;
173 if (shortcut)
174 *shortcut = sc->shortcut;
175 if (alias)
176 *alias = sc->alias;
177
178 return sc->deprecated == 1 ? 2 : 0;
179
180 }
181
182
183 /**
184 * fdisk_label_has_code_parttypes:
185 * @lb: label
186 *
187 * Returns: 1 if the label uses code as partition type
188 * identifiers (e.g. MBR) or 0.
189 */
190 int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
191 {
192 assert(lb);
193
194 if (lb->parttypes && lb->parttypes[0].typestr)
195 return 0;
196 return 1;
197 }
198
199 /**
200 * fdisk_label_has_parttypes_shortcuts
201 * @lb: label
202 *
203 * Returns: 1 if the label support shortuts/aliases for partition types or 0.
204 *
205 * Since: 2.36
206 */
207 int fdisk_label_has_parttypes_shortcuts(const struct fdisk_label *lb)
208 {
209 assert(lb);
210 return lb->nparttype_cuts ? 1 : 0;
211 }
212
213
214 /**
215 * fdisk_label_get_parttype_from_code:
216 * @lb: label
217 * @code: code to search for
218 *
219 * Search for partition type in label-specific table. The result
220 * is pointer to static array of label types.
221 *
222 * Returns: partition type or NULL upon failure or invalid @code.
223 */
224 struct fdisk_parttype *fdisk_label_get_parttype_from_code(
225 const struct fdisk_label *lb,
226 unsigned int code)
227 {
228 size_t i;
229
230 assert(lb);
231
232 if (!lb->nparttypes)
233 return NULL;
234
235 for (i = 0; i < lb->nparttypes; i++)
236 if (lb->parttypes[i].code == code)
237 return &lb->parttypes[i];
238 return NULL;
239 }
240
241 /**
242 * fdisk_label_get_parttype_from_string:
243 * @lb: label
244 * @str: string to search for
245 *
246 * Search for partition type in label-specific table. The result
247 * is pointer to static array of label types.
248 *
249 * Returns: partition type or NULL upon failure or invalid @str.
250 */
251 struct fdisk_parttype *fdisk_label_get_parttype_from_string(
252 const struct fdisk_label *lb,
253 const char *str)
254 {
255 size_t i;
256
257 assert(lb);
258
259 if (!lb->nparttypes)
260 return NULL;
261
262 for (i = 0; i < lb->nparttypes; i++)
263 if (lb->parttypes[i].typestr
264 && strcasecmp(lb->parttypes[i].typestr, str) == 0)
265 return &lb->parttypes[i];
266
267 return NULL;
268 }
269
270 /**
271 * fdisk_new_unknown_parttype:
272 * @code: type as number
273 * @typestr: type as string
274
275 * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to
276 * deallocate.
277 *
278 * Returns: newly allocated partition type, or NULL upon failure.
279 */
280 struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
281 const char *typestr)
282 {
283 struct fdisk_parttype *t = fdisk_new_parttype();
284
285 if (!t)
286 return NULL;
287
288 fdisk_parttype_set_name(t, _("unknown"));
289 fdisk_parttype_set_code(t, code);
290 fdisk_parttype_set_typestr(t, typestr);
291 t->flags |= FDISK_PARTTYPE_UNKNOWN;
292
293 return t;
294 }
295
296 /**
297 * fdisk_copy_parttype:
298 * @type: type to copy
299 *
300 * Use fdisk_unref_parttype() to deallocate.
301 *
302 * Returns: newly allocated partition type, or NULL upon failure.
303 */
304 struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
305 {
306 struct fdisk_parttype *t = fdisk_new_parttype();
307
308 if (!t)
309 return NULL;
310
311 fdisk_parttype_set_name(t, type->name);
312 fdisk_parttype_set_code(t, type->code);
313 fdisk_parttype_set_typestr(t, type->typestr);
314
315 return t;
316 }
317
318 static struct fdisk_parttype *parttype_from_data(
319 const struct fdisk_label *lb,
320 const char *str,
321 unsigned int *xcode,
322 int use_seqnum)
323 {
324 struct fdisk_parttype *types, *ret = NULL;
325 char *end = NULL;
326
327 assert(lb);
328 assert(str);
329
330 if (xcode)
331 *xcode = 0;
332 if (!lb->nparttypes)
333 return NULL;
334
335 DBG(LABEL, ul_debugobj(lb, " parsing '%s' data", str));
336 types = lb->parttypes;
337
338 if (types[0].typestr == NULL) {
339 unsigned int code;
340
341 DBG(LABEL, ul_debugobj(lb, " +hex"));
342
343 errno = 0;
344 code = strtol(str, &end, 16);
345
346 if (errno || *end != '\0') {
347 DBG(LABEL, ul_debugobj(lb, " failed: %m"));
348 return NULL;
349 }
350 if (xcode)
351 *xcode = code;
352 ret = fdisk_label_get_parttype_from_code(lb, code);
353 } else {
354 DBG(LABEL, ul_debugobj(lb, " +string"));
355
356 /* maybe specified by type string (e.g. UUID) */
357 ret = fdisk_label_get_parttype_from_string(lb, str);
358
359 if (!ret) {
360 /* maybe specified by order number */
361 int i;
362
363 errno = 0;
364 i = strtol(str, &end, 0);
365
366 if (use_seqnum && errno == 0
367 && *end == '\0' && i > 0
368 && i - 1 < (int) lb->nparttypes)
369 ret = &types[i - 1];
370 }
371 }
372
373 if (ret)
374 DBG(PARTTYPE, ul_debugobj(ret, " result '%s'", ret->name));
375 return ret;
376 }
377
378 static struct fdisk_parttype *parttype_from_shortcut(
379 const struct fdisk_label *lb,
380 const char *str, int deprecated)
381 {
382 size_t i;
383
384 DBG(LABEL, ul_debugobj(lb, " parsing '%s' shortcut", str));
385
386 for (i = 0; i < lb->nparttype_cuts; i++) {
387 const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
388
389 if (sc->deprecated && !deprecated)
390 continue;
391 if (sc->shortcut && strcmp(sc->shortcut, str) == 0)
392 return parttype_from_data(lb, sc->data, NULL, 0);
393 }
394 return NULL;
395 }
396
397 static struct fdisk_parttype *parttype_from_alias(
398 const struct fdisk_label *lb,
399 const char *str, int deprecated)
400 {
401 size_t i;
402
403 DBG(LABEL, ul_debugobj(lb, " parsing '%s' alias", str));
404
405 for (i = 0; i < lb->nparttype_cuts; i++) {
406 const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
407
408 if (sc->deprecated && !deprecated)
409 continue;
410 if (sc->alias && strcmp(sc->alias, str) == 0)
411 return parttype_from_data(lb, sc->data, NULL, 0);
412 }
413 return NULL;
414 }
415
416 /**
417 * fdisk_label_advparse_parttype:
418 * @lb: label
419 * @str: string to parse from
420 * @flags: FDISK_PARTTYPE_PARSE_*
421 *
422 * This function is advanced partition types parser. It parses partition type
423 * from @str according to the label. The function returns a pointer to static
424 * table of the partition types, or newly allocated partition type for unknown
425 * types (see fdisk_parttype_is_unknown(). It's safe to call fdisk_unref_parttype()
426 * for all results.
427 *
428 * The @str may be type data (hex code or UUID), alias or shortcut. For GPT
429 * also sequence number of the type in the list of the supported types.
430 *
431 * Returns: pointer to type or NULL on error.
432 */
433 struct fdisk_parttype *fdisk_label_advparse_parttype(
434 const struct fdisk_label *lb,
435 const char *str,
436 int flags)
437 {
438 struct fdisk_parttype *res = NULL;
439 unsigned int code = 0;
440
441 if (!lb->nparttypes)
442 return NULL;
443
444 DBG(LABEL, ul_debugobj(lb, "parsing '%s' (%s) type", str, lb->name));
445
446 if ((flags & FDISK_PARTTYPE_PARSE_DATA)
447 && !(flags & FDISK_PARTTYPE_PARSE_DATALAST))
448 res = parttype_from_data(lb, str, &code,
449 flags & FDISK_PARTTYPE_PARSE_SEQNUM);
450
451 if (!res && (flags & FDISK_PARTTYPE_PARSE_ALIAS))
452 res = parttype_from_alias(lb, str,
453 flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
454
455 if (!res && (flags & FDISK_PARTTYPE_PARSE_SHORTCUT))
456 res = parttype_from_shortcut(lb, str,
457 flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
458
459 if (!res && (flags & FDISK_PARTTYPE_PARSE_DATA)
460 && (flags & FDISK_PARTTYPE_PARSE_DATALAST))
461 res = parttype_from_data(lb, str, &code,
462 flags & FDISK_PARTTYPE_PARSE_SEQNUM);
463
464 if (!res && !(flags & FDISK_PARTTYPE_PARSE_NOUNKNOWN)) {
465 if (lb->parttypes[0].typestr)
466 res = fdisk_new_unknown_parttype(0, str);
467 else
468 res = fdisk_new_unknown_parttype(code, NULL);
469 }
470
471 if (res)
472 DBG(PARTTYPE, ul_debugobj(res, "returns parsed '%s' [%s] partition type",
473 res->name, res->typestr ? : ""));
474 return res;
475 }
476
477 /**
478 * fdisk_label_parse_parttype:
479 * @lb: label
480 * @str: string to parse from (type name, UUID, etc.)
481 *
482 * Parses partition type from @str according to the label. The function returns
483 * a pointer to static table of the partition types, or newly allocated
484 * partition type for unknown types (see fdisk_parttype_is_unknown(). It's
485 * safe to call fdisk_unref_parttype() for all results.
486 *
487 * Note that for GPT it accepts sequence number of UUID.
488 *
489 * Returns: pointer to type or NULL on error.
490 */
491 struct fdisk_parttype *fdisk_label_parse_parttype(
492 const struct fdisk_label *lb,
493 const char *str)
494 {
495 return fdisk_label_advparse_parttype(lb, str, FDISK_PARTTYPE_PARSE_DATA);
496 }
497
498 /**
499 * fdisk_parttype_get_string:
500 * @t: type
501 *
502 * Returns: partition type string (e.g. GUID for GPT)
503 */
504 const char *fdisk_parttype_get_string(const struct fdisk_parttype *t)
505 {
506 assert(t);
507 return t->typestr && *t->typestr ? t->typestr : NULL;
508 }
509
510 /**
511 * fdisk_parttype_get_code:
512 * @t: type
513 *
514 * Returns: partition type code (e.g. for MBR)
515 */
516 unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t)
517 {
518 assert(t);
519 return t->code;
520 }
521
522 /**
523 * fdisk_parttype_get_name:
524 * @t: type
525 *
526 * Returns: partition type human readable name
527 */
528 const char *fdisk_parttype_get_name(const struct fdisk_parttype *t)
529 {
530 assert(t);
531 return t->name;
532 }
533
534 /**
535 * fdisk_parttype_is_unknown:
536 * @t: type
537 *
538 * Checks for example result from fdisk_label_parse_parttype().
539 *
540 * Returns: 1 is type is "unknown" or 0.
541 */
542 int fdisk_parttype_is_unknown(const struct fdisk_parttype *t)
543 {
544 return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0;
545 }