--- gpt.c.sav 2018-11-18 09:12:44.192447000 +0100 +++ gpt.c 2019-01-25 19:43:16.186589000 +0100 @@ -312,6 +312,47 @@ return (0); } +static uint64_t +gpt_recover(struct dsk *dskp, struct gpt_hdr *hdr_prim, + const struct gpt_hdr *hdr_back) +{ + printf("%s: trying to recover GPT...\n", BOOTPROG); + const int head_prim_lba = 1; + const int table_prim_lba = 2; + + /* Copy partition table backup -> primary */ + int n_sect = DEV_BSIZE / hdr_back->hdr_entsz; + n_sect = hdr_back->hdr_entries / n_sect; + + /* Copy sector by sector because no assumption is + * made about n_sect value and secbuf size */ + for (int i = 0; i < n_sect; i++) { + if (drvread(dskp, secbuf, hdr_back->hdr_lba_table + i, 1)) + goto recover_failed; + if (drvwrite(dskp, secbuf, table_prim_lba + i, 1)) + goto recover_failed; + } + + /* Set GPT primary header with backup header */ + *hdr_prim = *hdr_back; + hdr_prim->hdr_crc_self = 0; + hdr_prim->hdr_lba_self = head_prim_lba; + hdr_prim->hdr_lba_alt = hdr_back->hdr_lba_self; + hdr_prim->hdr_lba_table = table_prim_lba; + hdr_prim->hdr_crc_self = crc32(hdr_prim, hdr_prim->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcopy(hdr_prim, secbuf, hdr_prim->hdr_size); + if (drvwrite(dskp, secbuf, hdr_prim->hdr_lba_self, 1)) + goto recover_failed; + + printf("%s: GPT recovering -> SUCCESS\n", BOOTPROG); + return (hdr_prim->hdr_lba_self); + +recover_failed: + printf("%s: GPT recovering -> FAILED\n", BOOTPROG); + return (0); +} + int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf) { @@ -352,10 +393,23 @@ gptread_table("backup", uuid, dskp, &hdr_backup, table_backup) == 0) { hdr_backup_lba = hdr_backup.hdr_lba_self; + + /* If primary GPT is dammaged but backup GPT is ok + * we try to recover primary GPT */ if (hdr_primary_lba == 0) { gpthdr = &hdr_backup; gpttable = table_backup; - printf("%s: using backup GPT\n", BOOTPROG); + hdr_primary_lba = gpt_recover(dskp, &hdr_primary, + &hdr_backup); + if (hdr_primary_lba == 0) { + printf("%s: using backup GPT\n", BOOTPROG); + } else { + if (!gptread_table("primary", uuid, dskp, + &hdr_primary, table_primary)) { + gpthdr = &hdr_primary; + gpttable = table_primary; + } + } } }