blob: 1e5fd99e551ba488ee3c740ec44938e252705409 [file] [log] [blame]
/*
* Copyright (C) 2017 Karel Zak <kzak@redhat.com>
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*
*
* Libfdisk sample to create partitions by specify size, for example:
*
* mkpart --label dos --device /dev/sdc 2M 2M 2M 10M 1M -
*
* creates 6 partitions:
* - 3 primary (3x 2M)
* - 1 extended (1x 10M)
* - 2 logical (1x 1M, 1x remaining-space-in-extended-partition)
*
* Notes:
* The sample specifies size and partno for MBR, and size only for another
* labels (e.g. GPT).
*
* The Ask-API does not use anything else than warning/info. The
* partitionning has to be done non-interactive.
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <getopt.h>
#include "c.h"
#include "nls.h"
#include "strutils.h"
#include "xalloc.h"
#include "libfdisk.h"
static int ask_callback(struct fdisk_context *cxt __attribute__((__unused__)),
struct fdisk_ask *ask,
void *data)
{
switch(fdisk_ask_get_type(ask)) {
case FDISK_ASKTYPE_INFO:
fputs(fdisk_ask_print_get_mesg(ask), stdout);
fputc('\n', stdout);
break;
case FDISK_ASKTYPE_WARNX:
fflush(stdout);
fputs(fdisk_ask_print_get_mesg(ask), stderr);
fputc('\n', stderr);
break;
case FDISK_ASKTYPE_WARN:
fflush(stdout);
fputs(fdisk_ask_print_get_mesg(ask), stderr);
errno = fdisk_ask_print_get_errno(ask);
fprintf(stderr, ": %m\n");
break;
default:
break;
}
return 0;
}
int main(int argc, char *argv[])
{
struct fdisk_context *cxt;
struct fdisk_partition *pa;
const char *label = NULL, *device = NULL;
int n = 0, c, nopartno = 0;
unsigned int sectorsize;
uint64_t grain = 0;
static const struct option longopts[] = {
{ "label", required_argument, NULL, 'x' },
{ "device", required_argument, NULL, 'd' },
{ "nopartno", no_argument, NULL, 'p' },
{ "grain", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
fdisk_init_debug(0);
while((c = getopt_long(argc, argv, "g:x:d:h", longopts, NULL)) != -1) {
switch(c) {
case 'x':
label = optarg;
break;
case 'd':
device = optarg;
break;
case 'p':
nopartno = 1;
break;
case 'g':
grain = strtosize_or_err(optarg, "failed to parse grain");
break;
case 'h':
printf("%s [options] <size> ...", program_invocation_short_name);
fputs(USAGE_SEPARATOR, stdout);
fputs("Make disklabel and partitions.\n", stdout);
fputs(USAGE_OPTIONS, stdout);
fputs(" -x, --label <dos,gpt,...> disk label type\n", stdout);
fputs(" -d, --device <path> block device\n", stdout);
fputs(" -p, --nopartno don't set partno (use default)\n", stdout);
fputs(" -h, --help this help\n", stdout);
fputs(USAGE_SEPARATOR, stdout);
return EXIT_SUCCESS;
}
}
if (!device)
errx(EXIT_FAILURE, "no device specified");
if (!label)
label = "dos";
cxt = fdisk_new_context();
if (!cxt)
err_oom();
fdisk_set_ask(cxt, ask_callback, NULL);
if (grain)
fdisk_save_user_grain(cxt, grain);
pa = fdisk_new_partition();
if (!pa)
err_oom();
if (fdisk_assign_device(cxt, device, 0))
err(EXIT_FAILURE, "failed to assign device");
if (fdisk_create_disklabel(cxt, label))
err(EXIT_FAILURE, "failed to create disk label");
sectorsize = fdisk_get_sector_size(cxt);
fdisk_disable_dialogs(cxt, 1);
while (optind < argc) {
int rc;
uint64_t size;
const char *str = argv[optind];
/* defaults */
fdisk_partition_start_follow_default(pa, 1);
fdisk_partition_end_follow_default(pa, 1);
fdisk_partition_partno_follow_default(pa, 1);
/* set size */
if (isdigit(*str)) {
size = strtosize_or_err(argv[optind], "failed to parse partition size");
fdisk_partition_set_size(pa, size / sectorsize);
fdisk_partition_end_follow_default(pa, 0);
} else if (*str == '-') {
fdisk_partition_end_follow_default(pa, 1);
}
if (fdisk_is_label(cxt, DOS)) {
/* For MBR we want to avoid primary/logical dialog.
* This is possible by explicitly specified partition
* number, <4 means primary, >=4 means logical.
*/
if (!nopartno) {
fdisk_partition_partno_follow_default(pa, 0);
fdisk_partition_set_partno(pa, n);
}
/* Make sure last primary partition is extended if user
* wants more than 4 partitions.
*/
if (n == 3 && optind + 1 < argc) {
struct fdisk_parttype *type =
fdisk_label_parse_parttype(
fdisk_get_label(cxt, NULL), "05");
if (!type)
err_oom();
fdisk_partition_set_type(pa, type);
fdisk_unref_parttype(type);
}
}
rc = fdisk_add_partition(cxt, pa, NULL);
if (rc) {
errno = -rc;
errx(EXIT_FAILURE, "failed to add #%d partition", n + 1);
}
fdisk_reset_partition(pa);
optind++;
n++;
}
if (fdisk_write_disklabel(cxt))
err(EXIT_FAILURE, "failed to write disk label");
fdisk_deassign_device(cxt, 1);
fdisk_unref_context(cxt);
fdisk_unref_partition(pa);
return EXIT_SUCCESS;
}