// SPDX-License-Identifier: GPL-2.0
/*
* fs/partitions/check.c
*
* Code extracted from drivers/block/genhd.c
* Copyright (C) 1991-1998 Linus Torvalds
* Re-organised Feb 1998 Russell King
*
* We now have independent partition support from the
* block drivers, which allows all the partition code to
* be grouped in one location, and it to be mostly self
* contained.
*
* Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
*/
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/genhd.h>
#include "check.h"
#include "acorn.h"
#include "amiga.h"
#include "atari.h"
#include "ldm.h"
#include "mac.h"
#include "msdos.h"
#include "osf.h"
#include "sgi.h"
#include "sun.h"
#include "ibm.h"
#include "ultrix.h"
#include "efi.h"
#include "karma.h"
#include "sysv68.h"
#include "cmdline.h"
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
static int (*check_part[])(struct parsed_partitions *) = {
/*
* Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0.
*/
#ifdef [31mCONFIG_ACORN_PARTITION_ICS[0m
adfspart_check_ICS,
#endif
#ifdef [31mCONFIG_ACORN_PARTITION_POWERTEC[0m
adfspart_check_POWERTEC,
#endif
#ifdef [31mCONFIG_ACORN_PARTITION_EESOX[0m
adfspart_check_EESOX,
#endif
/*
* Now move on to formats that only have partition info at
* disk address 0xdc0. Since these may also have stale
* PC/BIOS partition tables, they need to come before
* the msdos entry.
*/
#ifdef [31mCONFIG_ACORN_PARTITION_CUMANA[0m
adfspart_check_CUMANA,
#endif
#ifdef [31mCONFIG_ACORN_PARTITION_ADFS[0m
adfspart_check_ADFS,
#endif
#ifdef [31mCONFIG_CMDLINE_PARTITION[0m
cmdline_partition,
#endif
#ifdef [31mCONFIG_EFI_PARTITION[0m
efi_partition, /* this must come before msdos */
#endif
#ifdef [31mCONFIG_SGI_PARTITION[0m
sgi_partition,
#endif
#ifdef [31mCONFIG_LDM_PARTITION[0m
ldm_partition, /* this must come before msdos */
#endif
#ifdef [31mCONFIG_MSDOS_PARTITION[0m
msdos_partition,
#endif
#ifdef [31mCONFIG_OSF_PARTITION[0m
osf_partition,
#endif
#ifdef [31mCONFIG_SUN_PARTITION[0m
sun_partition,
#endif
#ifdef [31mCONFIG_AMIGA_PARTITION[0m
amiga_partition,
#endif
#ifdef [31mCONFIG_ATARI_PARTITION[0m
atari_partition,
#endif
#ifdef [31mCONFIG_MAC_PARTITION[0m
mac_partition,
#endif
#ifdef [31mCONFIG_ULTRIX_PARTITION[0m
ultrix_partition,
#endif
#ifdef [31mCONFIG_IBM_PARTITION[0m
ibm_partition,
#endif
#ifdef [31mCONFIG_KARMA_PARTITION[0m
karma_partition,
#endif
#ifdef [31mCONFIG_SYSV68_PARTITION[0m
sysv68_partition,
#endif
NULL
};
static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
{
struct parsed_partitions *state;
int nr;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
nr = disk_max_parts(hd);
state->parts = vzalloc(array_size(nr, sizeof(state->parts[0])));
if (!state->parts) {
kfree(state);
return NULL;
}
state->limit = nr;
return state;
}
void free_partitions(struct parsed_partitions *state)
{
vfree(state->parts);
kfree(state);
}
struct parsed_partitions *
check_partition(struct gendisk *hd, struct block_device *bdev)
{
struct parsed_partitions *state;
int i, res, err;
state = allocate_partitions(hd);
if (!state)
return NULL;
state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
if (!state->pp_buf) {
free_partitions(state);
return NULL;
}
state->pp_buf[0] = '\0';
state->bdev = bdev;
disk_name(hd, 0, state->name);
snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
if (isdigit(state->name[strlen(state->name)-1]))
sprintf(state->name, "p");
i = res = err = 0;
while (!res && check_part[i]) {
memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
res = check_part[i++](state);
if (res < 0) {
/* We have hit an I/O error which we don't report now.
* But record it, and let the others do their job.
*/
err = res;
res = 0;
}
}
if (res > 0) {
printk(KERN_INFO "%s", state->pp_buf);
free_page((unsigned long)state->pp_buf);
return state;
}
if (state->access_beyond_eod)
err = -ENOSPC;
if (err)
/* The partition is unrecognized. So report I/O errors if there were any */
res = err;
if (res) {
if (warn_no_part)
strlcat(state->pp_buf,
" unable to read partition table\n", PAGE_SIZE);
printk(KERN_INFO "%s", state->pp_buf);
}
free_page((unsigned long)state->pp_buf);
free_partitions(state);
return ERR_PTR(res);
}