From patchwork Sun May 23 06:11:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 1482462 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2607:f8b0:4864:20::93e; helo=mail-ua1-x93e.google.com; envelope-from=swupdate+bncbcl4hcw73qcbbnpeu6cqmgqeypvzqyy@googlegroups.com; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20161025 header.b=HTw477tC; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=Ahsky7EX; dkim-atps=neutral Received: from mail-ua1-x93e.google.com (mail-ua1-x93e.google.com [IPv6:2607:f8b0:4864:20::93e]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FnqkL4h3Nz9s24 for ; Sun, 23 May 2021 16:12:08 +1000 (AEST) Received: by mail-ua1-x93e.google.com with SMTP id m11-20020a9f3fcb0000b029021dec910e95sf2220191uaj.13 for ; Sat, 22 May 2021 23:12:08 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1621750325; cv=pass; d=google.com; s=arc-20160816; b=S/f2B1BXED482zMTIzf11az2felL6tP+H4KrM3OHFjjwAxUH2AhzqZM6n3WkNUn5VV lsMlBX1kKZs1ndAx6Q+LTdq3YbwgrPpwjD9/6W1pLUGp4fsiGUDy1VOUJqEY5/STHwJE PdxfMUroVosHaGt59Go5nK1lSMB/Nn7fQrnWTzZPYoxbANd7malh1AHkWGGUP4qChx/I 7WaA+V1Yzrzp4uIamjdFWNssz4CJIF16ETIZz+ZSVRxBJ/zfAKzn/B09MHi+V/ZUfN91 IvLpmTV2sIy9nAj350E+5+Ld2siMSxuTtg4tVUx+oSoKWxY3Uk7VuI9VGXBzc1a7GVR9 b0Jg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:message-id:date :subject:cc:to:from:sender:dkim-signature:dkim-signature; bh=Wq09Fs5JPNUU9ztWqCJdBBX22RAbKaaz1fYEKAjnA8I=; b=bgG9u2JJ6DpwuzZB0Am3UGI8GKrNZ1r2mw7+5ANyRqnFjDSRUeyYWlhzGoufu0Yw6g dlQRi3eJWXJQGAaliDuz4G0hInAStL7kMde5PeGNA/UAy3Jt8xLgEaL+GPRHlYjGZxLQ Xx3yrqrXQrT9zrKjjmRWEQm4DefAQ3xrIA9i6qhM+Stw6naWLiIJpiMp3FO2vb4ZXFk6 zx0FUbNT8+qM9ZwRR9uqEY3928WpkFBccGuQgQ1pYTkCmGUx3lqXyRH8uvXyFl2yEckN LhrJmShG251/cT6XCZDd2mIQM7zHXDbYmE3fCJnZp1kRPzkQMji57SFanai/3V6OdC8u UYrg== ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=TdNknotU; spf=pass (google.com: domain of james.hilliard1@gmail.com designates 2607:f8b0:4864:20::d35 as permitted sender) smtp.mailfrom=james.hilliard1@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:mime-version :x-original-sender:x-original-authentication-results:precedence :mailing-list:list-id:list-post:list-help:list-archive :list-subscribe:list-unsubscribe; bh=Wq09Fs5JPNUU9ztWqCJdBBX22RAbKaaz1fYEKAjnA8I=; b=HTw477tCZESsMTMASwtIW26L80K9GhPLNUjnnbuCyOSJxsFiRFWBW1ZJih7lxjMLDi l7RLP8c1jvZ2xDJJNsq/MrCBVN8aCrC9Ivg0aoH620/Ml21ovzJqKa5bzG5FGycevpin iln+HcQivjBIJn6wtjdx7Z3TxEph/yDopogvFCdKi1+o+2TXKDYaIHeBBXAuowpFbtCL ygspvjoJY57ZSUpDyeZnCjJvNhSmCr0V7FUXlJ5986lwS2NsC6DSCRV6pVE74fqp/l+1 Kpr7pFB8u0A7F8YJMNUTb8zKQwxo0vO6YH8+RdDWGH/4is6ddRS3Ebut4MtuuCBntnuw O3Mw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-subscribe:list-unsubscribe; bh=Wq09Fs5JPNUU9ztWqCJdBBX22RAbKaaz1fYEKAjnA8I=; b=Ahsky7EXxisoxe7c0LCKLqZ/b/CoCszh/aM5q8xkcGazWMrMwxYzPEFehoY9uDP/ZI iAMNcROYjToe/2WmZw9Ml++9exuivpktF6Kj8+4QAAexnlF4F+kHIfqrqQ5nGmv5WmWa UUIXBp+BD2mXjwAKks0cSjxWZMZdOhMv8xCKHIlSpS7UX9yFxm1jtgr5afp7oYXkXpSJ rs0Gu52FzVKKXuaEjPzbPNZkLyQEOQ6Thl8ror8tdEHJCxFB0zdHqglE6PcxiU3t90pm WSj2qDExM5LbdygrHCFFwWM/N7tjn3yhMBSWGCbgOllcARYEGd5yq7RBOolaD86jbh0S FPcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=sender:x-gm-message-state:from:to:cc:subject:date:message-id :mime-version:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post :list-help:list-archive:list-subscribe:list-unsubscribe; bh=Wq09Fs5JPNUU9ztWqCJdBBX22RAbKaaz1fYEKAjnA8I=; b=BNNcXH7IyFQDaM/Dy9D1rZRnZjDvcnCgi7E7jizNNd/6ghKfgjHXVF+8eyNnLwkQOi B3kY9KwIUP0XM9lPDUelWyF6WA/jd8pYJdpW11eBndhuKLPn3eOcK05HR3sVyjJoiEB2 TcsTlgMFNhgOL/cV/ruVUfIHehVbsbo3LyJHvCh6K9oiof1+iM7CIP2qgfeUNwNxMw2f jSAuhtrcr5jeLmChWb6zIZ1ef1BBMowae5i53xyuO2wqc7OE7druiU0KgB/Lp4gMguKn fkKY6Kc+NxEfU8uIOU4F5j+w8tcNwCOkUPz+m+32CeJa96RU3fZagZWWMaykX9t2qZvF IRdA== Sender: swupdate@googlegroups.com X-Gm-Message-State: AOAM530zedMQR1S0Nzrw/k/gNSRHUma5gDFluJmf7b+GH4EIoCLMJPyO m+Sb95gab0Ac8sJuQUYANHU= X-Google-Smtp-Source: ABdhPJx2ABiQmEL8PiY/YT3xkYDgin5J0XdudBUJpQDjDgQD8xr2ACByozjgkyHjY/pZaP1o6VCEAQ== X-Received: by 2002:a9f:234e:: with SMTP id 72mr16841829uae.45.1621750325259; Sat, 22 May 2021 23:12:05 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:ab0:2642:: with SMTP id q2ls557851uao.8.gmail; Sat, 22 May 2021 23:12:04 -0700 (PDT) X-Received: by 2002:ab0:36d7:: with SMTP id v23mr18302105uau.92.1621750324815; Sat, 22 May 2021 23:12:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1621750324; cv=none; d=google.com; s=arc-20160816; b=od4o6+ijTjiaZKp/r4+pgDIFoYSLNXFTnQsIOvgABAxyNyV21sOzLi0vCUyCNeMFAA iBuP09+2OqUBl/0AnwueWeImJK/cYwoqHwAmgE4cywU91OT/xJ+kHHvdyYxsqJk8gqth QmfP/DNZzz5OyImtaVJewARNT9Ut8Ok8oSGDA5LPa+mrCwEBi3AIrJXmf1jIqnHuhgsD KULFpTgt7K43j1L2S46KiyDRf+0u/xa/PZ7E+SiFc074UiXrvi/FgzskTRqHV1E7trua izF1TzPSo1uCU/A+s7vAgKff/KXgyeN0qaKUWgIHANHCU31codz9Wd61wo8RMMT+WUeF GlUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature; bh=6zbBTyX5kIUnRoXaqlAd73PTxX6LZIn4boCqCy/ZCzE=; b=KsOo/4hbEys2ZVsqFMKabEKGrRePxmFCoqEEGi3HJFImT5yQU14TsgmiFaTv5IugM0 bILqyUPuqXjrHdkVP4ZaXkrAW0PqZ2juKCWqbAgwgs1LCKSGPvxhSBjJDskifM3yKmm1 xkorY4hLlp3XQ9H9cdAHga1/PeaUafuiQnqxbneKLx2XY61ULHrUsuCYDjai+JV7emrU FW33UVnvwvv2AnK9rQk4WHUcsGJzYif0U8S2bn/399mPpjM67qpIza8U8j72oWdMWigg 8afB59hiOZ7BqI8YErM/g2xoRMJjsBOkjAHQTGnu5uugPuAn98FufmOODxP3B0onrc/m toZA== ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=TdNknotU; spf=pass (google.com: domain of james.hilliard1@gmail.com designates 2607:f8b0:4864:20::d35 as permitted sender) smtp.mailfrom=james.hilliard1@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-io1-xd35.google.com (mail-io1-xd35.google.com. [2607:f8b0:4864:20::d35]) by gmr-mx.google.com with ESMTPS id f5si358966vsg.0.2021.05.22.23.12.04 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 22 May 2021 23:12:04 -0700 (PDT) Received-SPF: pass (google.com: domain of james.hilliard1@gmail.com designates 2607:f8b0:4864:20::d35 as permitted sender) client-ip=2607:f8b0:4864:20::d35; Received: by mail-io1-xd35.google.com with SMTP id p8so24404752iol.11 for ; Sat, 22 May 2021 23:12:04 -0700 (PDT) X-Received: by 2002:a05:6638:134c:: with SMTP id u12mr16679214jad.67.1621750323866; Sat, 22 May 2021 23:12:03 -0700 (PDT) Received: from MacBook-Pro.localdomain (71-33-146-119.hlrn.qwest.net. [71.33.146.119]) by smtp.gmail.com with ESMTPSA id e1sm918420ilm.7.2021.05.22.23.12.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 22 May 2021 23:12:03 -0700 (PDT) From: James Hilliard To: swupdate@googlegroups.com Cc: James Hilliard Subject: [swupdate] [RFC PATCH v2 1/1] Add support for setting hybrid dos partition entries. Date: Sun, 23 May 2021 00:11:57 -0600 Message-Id: <20210523061157.22626-1-james.hilliard1@gmail.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 X-Original-Sender: james.hilliard1@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=TdNknotU; spf=pass (google.com: domain of james.hilliard1@gmail.com designates 2607:f8b0:4864:20::d35 as permitted sender) smtp.mailfrom=james.hilliard1@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , This adds the ability to set dos partition entries for gpt disks. This is mostly useful for booting on GPT disks from boards that don't natively support GPT. Config example: partition-1 = [ "size=550M", "start=2048", "name=boot", "type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "fstype=vfat", "dostype=0x0C" ]; This approach uses hybrid aware wrapper functions and structures to encapsulate the hybrid partition handling differences better. Signed-off-by: James Hilliard --- handlers/diskpart_handler.c | 544 ++++++++++++++++++++++++++++-------- 1 file changed, 425 insertions(+), 119 deletions(-) diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c index 62a45df..c7196e1 100644 --- a/handlers/diskpart_handler.c +++ b/handlers/diskpart_handler.c @@ -60,7 +60,8 @@ enum partfield { PART_START, PART_TYPE, PART_NAME, - PART_FSTYPE + PART_FSTYPE, + PART_DOSTYPE }; const char *fields[] = { @@ -68,7 +69,8 @@ const char *fields[] = { [PART_START] = "start", [PART_TYPE] = "type", [PART_NAME] = "name", - [PART_FSTYPE] = "fstype" + [PART_FSTYPE] = "fstype", + [PART_DOSTYPE] = "dostype" }; struct partition_data { @@ -78,6 +80,7 @@ struct partition_data { char type[SWUPDATE_GENERAL_STRING_SIZE]; char name[SWUPDATE_GENERAL_STRING_SIZE]; char fstype[SWUPDATE_GENERAL_STRING_SIZE]; + char dostype[SWUPDATE_GENERAL_STRING_SIZE]; LIST_ENTRY(partition_data) next; }; LIST_HEAD(listparts, partition_data); @@ -90,6 +93,178 @@ struct hnd_priv { struct listparts listparts; /* list of partitions */ }; +struct create_table { + bool parent; + bool child; +}; + +struct diskpart_table { + struct fdisk_table *parent; + struct fdisk_table *child; +}; + +static char *diskpart_get_lbtype(struct img_type *img) +{ + return dict_get_value(&img->properties, "labeltype"); +} + +static int diskpart_assign_label(struct fdisk_context *cxt, struct img_type *img, + struct hnd_priv priv, struct create_table *createtable) +{ + char *lbtype = diskpart_get_lbtype(img); + int ret = 0; + + /* + * Check partition table + */ + if (!fdisk_has_label(cxt)) { + WARN("%s does not contain a recognized partition table", + img->device); + ret = fdisk_create_disklabel(cxt, lbtype); + if (ret) { + ERROR("Failed to create disk label"); + return ret; + } + createtable->parent = true; + createtable->child = true; + } else if (lbtype) { + if (!strcmp(lbtype, "gpt")) { + priv.labeltype = FDISK_DISKLABEL_GPT; + } else { + priv.labeltype = FDISK_DISKLABEL_DOS; + } + + if (!fdisk_is_labeltype(cxt, priv.labeltype)) { + WARN("Partition table of different type, setting to %s, all data lost !", + lbtype); + ret = fdisk_create_disklabel(cxt, lbtype); + if (ret) { + ERROR("Failed to create disk label"); + return ret; + } + createtable->parent = true; + createtable->child = true; + } + } + + return ret; +} + +static int diskpart_assign_context(struct fdisk_context **cxt,struct img_type *img, + struct hnd_priv priv, unsigned long hybrid, struct create_table *createtable) +{ + struct fdisk_context *parent; + int ret = 0; + + parent = fdisk_new_context(); + if (!parent) { + ERROR("Failed to allocate libfdisk context"); + return -ENOMEM; + } + + /* + * The library uses dialog driven partitioning by default. + * Disable as we don't support interactive dialogs. + */ + ret = fdisk_disable_dialogs(parent, 1); + if (ret) { + ERROR("Failed to disable dialogs"); + return ret; + } + + ret = fdisk_assign_device(parent, img->device, 0); + if (ret == -EACCES) { + ERROR("no access to %s", img->device); + return ret; + } + + ret = diskpart_assign_label(parent, img, priv, createtable); + if (ret) + return ret; + + if (hybrid) { + *cxt = fdisk_new_nested_context(parent, "dos"); + if (!cxt) { + ERROR("Failed to allocate libfdisk nested context"); + return -ENOMEM; + } + + /* + * The library uses dialog driven partitioning by default. + * Disable as we don't support interactive dialogs. + */ + ret = fdisk_disable_dialogs(*cxt, 1); + if (ret) { + ERROR("Failed to disable nested dialogs"); + return ret; + } + } else { + *cxt = parent; + } + + return ret; +} + +static struct diskpart_table *diskpart_new_table(struct fdisk_context *cxt) +{ + struct diskpart_table *tb = NULL; + + tb = calloc(1, sizeof(*tb)); + if (!tb) + return NULL; + + tb->parent = fdisk_new_table(); + if (!tb->parent) { + free(tb); + return NULL; + } + + if (fdisk_get_parent(cxt)) { + tb->child = fdisk_new_table(); + if (!tb->child) { + fdisk_unref_table(tb->parent); + free(tb); + return NULL; + } + } + + return tb; +} + +static void diskpart_unref_table(struct diskpart_table *tb) +{ + if (!tb) + return; + + if (tb->child) + fdisk_unref_table(tb->child); + + if (tb->parent) + fdisk_unref_table(tb->parent); + + free(tb); +} + +static int diskpart_get_partitions(struct fdisk_context *cxt, struct diskpart_table *tb, + struct create_table *createtable) +{ + struct fdisk_context *parent; + int ret = 0; + + if (fdisk_get_parent(cxt)) + parent = fdisk_get_parent(cxt); + else + parent = cxt; + + if (fdisk_get_partitions(parent, &tb->parent)) + createtable->parent = true; + + if (fdisk_get_parent(cxt) && fdisk_get_partitions(cxt, &tb->child)) + createtable->child = true; + + return ret; +} + /** * diskpart_set_partition - set values in a fdisk_partition * @cxt: libfdisk context @@ -105,8 +280,6 @@ static int diskpart_set_partition(struct fdisk_partition *pa, { int ret = 0; - if (!sector_size) - sector_size = 1; fdisk_partition_unset_partno(pa); fdisk_partition_unset_size(pa); fdisk_partition_unset_start(pa); @@ -117,7 +290,7 @@ static int diskpart_set_partition(struct fdisk_partition *pa, if (part->partno != LIBFDISK_INIT_UNDEF(part->partno)) ret |= fdisk_partition_set_partno(pa, part->partno); else - ret |= fdisk_partition_partno_follow_default(pa, 1); + ret |= -EINVAL; if (strlen(part->name)) ret |= fdisk_partition_set_name(pa, part->name); if (part->size != LIBFDISK_INIT_UNDEF(part->size)) @@ -131,6 +304,69 @@ static int diskpart_set_partition(struct fdisk_partition *pa, return ret; } +static int diskpart_set_hybrid_partition(struct fdisk_partition *pa, + struct partition_data *part, + struct fdisk_parttype *parttype, + struct fdisk_table *tb) +{ + struct fdisk_partition *parent = fdisk_table_get_partition_by_partno(tb, part->partno); + int ret = 0; + + if (!parent) { + ERROR("I cannot find parent for hybrid partition %zu(%s)", part->partno, part->name); + return -EINVAL; + }; + + fdisk_partition_unset_partno(pa); + fdisk_partition_unset_size(pa); + fdisk_partition_unset_start(pa); + fdisk_partition_size_explicit(pa, 1); + if (fdisk_partition_has_start(parent)) + ret = fdisk_partition_set_start(pa, fdisk_partition_get_start(parent)); + else + ret = -EINVAL; + ret |= fdisk_partition_partno_follow_default(pa, 1); + if (strlen(part->name)) + ret |= fdisk_partition_set_name(pa, part->name); + if (fdisk_partition_has_size(parent)) + ret |= fdisk_partition_set_size(pa, fdisk_partition_get_size(parent)); + else + ret |= -EINVAL; + + if (parttype) + ret |= fdisk_partition_set_type(pa, parttype); + + return ret; +} + +static int diskpart_append_hybrid_pmbr(struct fdisk_label *lb, struct fdisk_table *tb) +{ + struct fdisk_partition *pa; + struct fdisk_parttype *parttype; + int ret = 0; + + pa = fdisk_new_partition(); + fdisk_partition_unset_partno(pa); + fdisk_partition_unset_size(pa); + fdisk_partition_unset_start(pa); + fdisk_partition_size_explicit(pa, 1); + parttype = fdisk_label_get_parttype_from_code(lb, 0xee); + + ret = fdisk_partition_set_start(pa, 1); + ret |= fdisk_partition_set_size(pa, 33); + ret |= fdisk_partition_set_type(pa, parttype); + ret |= fdisk_partition_partno_follow_default(pa, 1); + if (ret) + return ret; + + if ((ret = fdisk_table_add_partition(tb, pa)) < 0) { + ERROR("Failed to append hybrid PMBR to table"); + } + fdisk_unref_partition(pa); + + return ret; +} + /* * Return true if partition differs */ @@ -173,21 +409,52 @@ static bool diskpart_partition_cmp(struct fdisk_partition *firstpa, struct fdisk return false; } -static int diskpart_fill_table(struct fdisk_context *cxt, struct fdisk_table *tb, +static int diskpart_reload_table(struct fdisk_context *cxt, struct fdisk_table *tb) +{ + int ret = 0; + + ret = fdisk_delete_all_partitions(cxt); + if (ret) { + ERROR("Partition table cannot be deleted: %d", ret); + return ret; + } + ret = fdisk_apply_table(cxt, tb); + if (ret) { + ERROR("Partition table cannot be applied: %d", ret); + return ret; + } + fdisk_reset_table(tb); + ret = fdisk_get_partitions(cxt, &tb); + if (ret) { + ERROR("Error loading applied table %d:", ret); + return ret; + } + return ret; +} + +static int diskpart_fill_table(struct fdisk_context *cxt, struct diskpart_table *tb, struct partition_data *part, struct hnd_priv priv) { + struct fdisk_context *parent; struct fdisk_parttype *parttype; struct fdisk_label *lb; unsigned long sector_size; int ret = 0; - lb = fdisk_get_label(cxt, NULL); + if (fdisk_get_parent(cxt)) + parent = fdisk_get_parent(cxt); + else + parent = cxt; + + lb = fdisk_get_label(parent, NULL); if (!lb) { ERROR("Failed to load label"); return -EINVAL; } - sector_size = fdisk_get_sector_size(cxt); + sector_size = fdisk_get_sector_size(parent); + if (!sector_size) + sector_size = 1; LIST_FOREACH(part, &priv.listparts, next) { struct fdisk_partition *newpa; @@ -196,7 +463,7 @@ static int diskpart_fill_table(struct fdisk_context *cxt, struct fdisk_table *tb /* * GPT uses strings instead of hex code for partition type */ - if (fdisk_is_label(cxt, GPT)) { + if (fdisk_is_label(parent, GPT)) { parttype = fdisk_label_get_parttype_from_string(lb, part->type); if (!parttype) parttype = fdisk_label_get_parttype_from_string(lb, GPT_DEFAULT_ENTRY_TYPE); @@ -207,13 +474,55 @@ static int diskpart_fill_table(struct fdisk_context *cxt, struct fdisk_table *tb if (ret) { WARN("I cannot set all partition's parameters"); } - if ((ret = fdisk_table_add_partition(tb, newpa)) < 0) { + if ((ret = fdisk_table_add_partition(tb->parent, newpa)) < 0) { ERROR("I cannot add partition %zu(%s): %d", part->partno, part->name, ret); } fdisk_unref_partition(newpa); if (ret) return ret; } + + /* + * Reload parent table against the context to populate default values. + */ + ret = diskpart_reload_table(parent, tb->parent); + if (ret) + return ret; + + if (fdisk_get_parent(cxt)) { + lb = fdisk_get_label(cxt, "dos"); + if (!lb) { + ERROR("Failed to load label"); + return -EINVAL; + } + + LIST_FOREACH(part, &priv.listparts, next) { + if (strlen(part->dostype)) { + struct fdisk_partition *newpa; + + newpa = fdisk_new_partition(); + + parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->type, 16)); + ret = diskpart_set_hybrid_partition(newpa, part, parttype, tb->parent); + if (ret) { + WARN("I cannot set all partition's parameters"); + } + if ((ret = fdisk_table_add_partition(tb->child, newpa)) < 0) { + ERROR("I cannot add partition %zu(%s): %d", part->partno, part->name, ret); + } + fdisk_unref_partition(newpa); + if (ret) + return ret; + } + } + diskpart_append_hybrid_pmbr(lb, tb->child); + /* + * Reload child table against the context to populate default values. + */ + ret = diskpart_reload_table(cxt, tb->child); + if (ret) + return ret; + } return ret; } @@ -258,44 +567,100 @@ static int diskpart_table_cmp(struct fdisk_table *tb, struct fdisk_table *oldtb) return ret; } -static int diskpart_reload_table(struct fdisk_context *cxt, struct fdisk_table *tb) +static int diskpart_compare_tables(struct diskpart_table *tb, struct diskpart_table *oldtb, + struct create_table *createtable) { int ret = 0; - ret = fdisk_delete_all_partitions(cxt); - if (ret) { - ERROR("Partition table cannot be deleted: %d", ret); - return ret; + /* + * A partiton table was found on disk, now compares the two tables + * to check if they differ. + */ + if (!createtable->parent) { + ret = diskpart_table_cmp(tb->parent, oldtb->parent); + if (ret < 0) + return ret; + else if (ret) + createtable->parent = true; } - ret = fdisk_apply_table(cxt, tb); - if (ret) { - ERROR("Partition table cannot be applied: %d", ret); - return ret; + + if (tb->child && !createtable->child) { + ret = diskpart_table_cmp(tb->child, oldtb->child); + if (ret < 0) + return ret; + else if (ret) + createtable->child = true; } - fdisk_reset_table(tb); - ret = fdisk_get_partitions(cxt, &tb); - if (ret) { - ERROR("Error loading applied table %d:", ret); - return ret; + + ret = 0; + + return ret; +} + +static int diskpart_write_table(struct fdisk_context *cxt, struct create_table *createtable) +{ + struct fdisk_context *parent; + int ret = 0; + + if (fdisk_get_parent(cxt)) + parent = fdisk_get_parent(cxt); + else + parent = cxt; + + if (createtable->parent || createtable->child) + TRACE("Partitions on disk differ, write to disk;"); + else + TRACE("Same partition table on disk, do not touch partition table !"); + + if (createtable->parent) { + /* + * Everything done, write into disk + */ + ret = fdisk_write_disklabel(parent); + if (ret) + ERROR("Partition table cannot be written on disk"); + if (fdisk_reread_partition_table(parent)) + WARN("Table cannot be reread from the disk, be careful !"); + if (ret) + return ret; + } else { + ret = 0; + } + + if (createtable->child) { + /* + * Everything done, write into disk + */ + ret = fdisk_write_disklabel(cxt); + if (ret) + ERROR("Hybrid partition table cannot be written on disk"); + if (fdisk_reread_partition_table(cxt)) + WARN("Hybrid table cannot be reread from the disk, be careful !"); + if (ret) + return ret; + } else { + ret = 0; } + return ret; } static int diskpart(struct img_type *img, void __attribute__ ((__unused__)) *data) { - char *lbtype = dict_get_value(&img->properties, "labeltype"); + char *lbtype = diskpart_get_lbtype(img); struct dict_list *parts; struct dict_list_elem *elem; struct fdisk_context *cxt; struct partition_data *part; struct partition_data *tmp; - struct fdisk_table *tb = NULL; - struct fdisk_table *oldtb = NULL; + struct diskpart_table *tb = NULL; + struct diskpart_table *oldtb = NULL; int ret = 0; unsigned long i; + unsigned long hybrid = 0; struct hnd_priv priv = {FDISK_DISKLABEL_DOS}; - bool createtable = false; + struct create_table *createtable = (struct create_table *)calloc(1, sizeof(struct create_table)); if (!lbtype || (strcmp(lbtype, "gpt") && strcmp(lbtype, "dos"))) { ERROR("Just GPT or DOS partition table are supported"); @@ -307,28 +672,6 @@ static int diskpart(struct img_type *img, return -EINVAL; } - cxt = fdisk_new_context(); - if (!cxt) { - ERROR("Failed to allocate libfdisk context"); - return -ENOMEM; - } - - /* - * The library uses dialog driven partitioning by default. - * Disable as we don't support interactive dialogs. - */ - ret = fdisk_disable_dialogs(cxt, 1); - if (ret) { - ERROR("Failed to disable dialogs"); - goto handler_release; - } - - ret = fdisk_assign_device(cxt, img->device, 0); - if (ret == -EACCES) { - ERROR("no access to %s", img->device); - goto handler_release; - } - struct dict_entry *entry; LIST_FOREACH(entry, &img->properties, next) { parts = &entry->list; @@ -376,12 +719,23 @@ static int diskpart(struct img_type *img, case PART_FSTYPE: strncpy(part->fstype, equal, sizeof(part->fstype)); break; + case PART_DOSTYPE: + strncpy(part->dostype, equal, sizeof(part->dostype)); + hybrid++; + break; } } } elem = LIST_NEXT(elem, next); } + if (hybrid > 3) { + ERROR("I cannot add hybrid partition %zu(%s): hybrid dos partition limit of 3 exceeded", + part->partno, strlen(part->name) ? part->name : "UNDEF NAME"); + ret = -EINVAL; + goto handler_exit; + } + TRACE("partition-%zu:%s size %" PRIu64 " start %zu type %s", part->partno != LIBFDISK_INIT_UNDEF(part->partno) ? part->partno : 0, strlen(part->name) ? part->name : "UNDEF NAME", @@ -410,51 +764,33 @@ static int diskpart(struct img_type *img, } } - /* - * Check partition table - */ - if (!fdisk_has_label(cxt)) { - WARN("%s does not contain a recognized partition table", - img->device); - ret = fdisk_create_disklabel(cxt, lbtype); - if (ret) { - ERROR("Failed to create disk label"); - goto handler_release; - } - createtable = true; - } else if (lbtype) { - if (!strcmp(lbtype, "gpt")) - priv.labeltype = FDISK_DISKLABEL_GPT; - else - priv.labeltype = FDISK_DISKLABEL_DOS; - - if (!fdisk_is_labeltype(cxt, priv.labeltype)) { - WARN("Partition table of different type, setting to %s, all data lost !", - lbtype); - ret = fdisk_create_disklabel(cxt, lbtype); - if (ret) { - ERROR("Failed to create disk label"); - goto handler_release; - } - createtable = true; - } - } + ret = diskpart_assign_context(&cxt, img, priv, hybrid, createtable); + if (ret == -EACCES) + goto handler_release; + else if (ret) + goto handler_exit; /* * Create a new in-memory partition table to be compared * with the table on the disk, and applied if differs */ - tb = fdisk_new_table(); - - if (fdisk_get_partitions(cxt, &oldtb)) - createtable = true; - + tb = diskpart_new_table(cxt); if (!tb) { ERROR("OOM creating new table !"); ret = -ENOMEM; goto handler_exit; } + oldtb = calloc(1, sizeof(*oldtb)); + if (!oldtb) { + ERROR("OOM loading partitions !"); + return -ENOMEM; + } + + ret = diskpart_get_partitions(cxt, oldtb, createtable); + if (ret) + goto handler_exit; + /* * Fill the new in-memory partition table from the partition list. */ @@ -462,47 +798,17 @@ static int diskpart(struct img_type *img, if (ret) goto handler_exit; - /* - * Reload new table against the context to populate default values - * so that we can compare partitions properly. - */ - ret = diskpart_reload_table(cxt, tb); + ret = diskpart_compare_tables(tb, oldtb, createtable); if (ret) goto handler_exit; - /* - * A partiton table was found on disk, now compares the two tables - * to check if they differ. - */ - if (!createtable) { - ret = diskpart_table_cmp(tb, oldtb); - if (ret < 0) - goto handler_exit; - else if (ret) - createtable = true; - } - - if (createtable) { - TRACE("Partitions on disk differ, write to disk;"); - - /* - * Everything done, write into disk - */ - ret = fdisk_write_disklabel(cxt); - if (ret) - ERROR("Partition table cannot be written on disk"); - if (fdisk_reread_partition_table(cxt)) - WARN("Table cannot be reread from the disk, be careful !"); - } else { - ret = 0; - TRACE("Same partition table on disk, do not touch partition table !"); - } + ret = diskpart_write_table(cxt, createtable); handler_exit: if (tb) - fdisk_unref_table(tb); + diskpart_unref_table(tb); if (oldtb) - fdisk_unref_table(oldtb); + diskpart_unref_table(oldtb); if (fdisk_deassign_device(cxt, 0)) WARN("Error deassign device %s", img->device); @@ -519,7 +825,7 @@ handler_release: #ifdef CONFIG_DISKFORMAT /* Create filesystems */ - if (!ret && createtable) { + if (!ret && createtable->parent) { LIST_FOREACH(part, &priv.listparts, next) { int index; /*