1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  fs/partitions/check.c
4  *
5  *  Code extracted from drivers/block/genhd.c
6  *  Copyright (C) 1991-1998  Linus Torvalds
7  *  Re-organised Feb 1998 Russell King
8  *
9  *  We now have independent partition support from the
10  *  block drivers, which allows all the partition code to
11  *  be grouped in one location, and it to be mostly self
12  *  contained.
13  *
14  *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
15  */
16 
17 #include <linux/slab.h>
18 #include <linux/vmalloc.h>
19 #include <linux/ctype.h>
20 #include <linux/genhd.h>
21 
22 #include "check.h"
23 
24 #include "acorn.h"
25 #include "amiga.h"
26 #include "atari.h"
27 #include "ldm.h"
28 #include "mac.h"
29 #include "msdos.h"
30 #include "osf.h"
31 #include "sgi.h"
32 #include "sun.h"
33 #include "ibm.h"
34 #include "ultrix.h"
35 #include "efi.h"
36 #include "karma.h"
37 #include "sysv68.h"
38 #include "cmdline.h"
39 
40 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
41 
42 static int (*check_part[])(struct parsed_partitions *) = {
43 	/*
44 	 * Probe partition formats with tables at disk address 0
45 	 * that also have an ADFS boot block at 0xdc0.
46 	 */
47 #ifdef CONFIG_ACORN_PARTITION_ICS
48 	adfspart_check_ICS,
49 #endif
50 #ifdef CONFIG_ACORN_PARTITION_POWERTEC
51 	adfspart_check_POWERTEC,
52 #endif
53 #ifdef CONFIG_ACORN_PARTITION_EESOX
54 	adfspart_check_EESOX,
55 #endif
56 
57 	/*
58 	 * Now move on to formats that only have partition info at
59 	 * disk address 0xdc0.  Since these may also have stale
60 	 * PC/BIOS partition tables, they need to come before
61 	 * the msdos entry.
62 	 */
63 #ifdef CONFIG_ACORN_PARTITION_CUMANA
64 	adfspart_check_CUMANA,
65 #endif
66 #ifdef CONFIG_ACORN_PARTITION_ADFS
67 	adfspart_check_ADFS,
68 #endif
69 
70 #ifdef CONFIG_CMDLINE_PARTITION
71 	cmdline_partition,
72 #endif
73 #ifdef CONFIG_EFI_PARTITION
74 	efi_partition,		/* this must come before msdos */
75 #endif
76 #ifdef CONFIG_SGI_PARTITION
77 	sgi_partition,
78 #endif
79 #ifdef CONFIG_LDM_PARTITION
80 	ldm_partition,		/* this must come before msdos */
81 #endif
82 #ifdef CONFIG_MSDOS_PARTITION
83 	msdos_partition,
84 #endif
85 #ifdef CONFIG_OSF_PARTITION
86 	osf_partition,
87 #endif
88 #ifdef CONFIG_SUN_PARTITION
89 	sun_partition,
90 #endif
91 #ifdef CONFIG_AMIGA_PARTITION
92 	amiga_partition,
93 #endif
94 #ifdef CONFIG_ATARI_PARTITION
95 	atari_partition,
96 #endif
97 #ifdef CONFIG_MAC_PARTITION
98 	mac_partition,
99 #endif
100 #ifdef CONFIG_ULTRIX_PARTITION
101 	ultrix_partition,
102 #endif
103 #ifdef CONFIG_IBM_PARTITION
104 	ibm_partition,
105 #endif
106 #ifdef CONFIG_KARMA_PARTITION
107 	karma_partition,
108 #endif
109 #ifdef CONFIG_SYSV68_PARTITION
110 	sysv68_partition,
111 #endif
112 	NULL
113 };
114 
allocate_partitions(struct gendisk * hd)115 static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
116 {
117 	struct parsed_partitions *state;
118 	int nr;
119 
120 	state = kzalloc(sizeof(*state), GFP_KERNEL);
121 	if (!state)
122 		return NULL;
123 
124 	nr = disk_max_parts(hd);
125 	state->parts = vzalloc(array_size(nr, sizeof(state->parts[0])));
126 	if (!state->parts) {
127 		kfree(state);
128 		return NULL;
129 	}
130 
131 	state->limit = nr;
132 
133 	return state;
134 }
135 
free_partitions(struct parsed_partitions * state)136 void free_partitions(struct parsed_partitions *state)
137 {
138 	vfree(state->parts);
139 	kfree(state);
140 }
141 
142 struct parsed_partitions *
check_partition(struct gendisk * hd,struct block_device * bdev)143 check_partition(struct gendisk *hd, struct block_device *bdev)
144 {
145 	struct parsed_partitions *state;
146 	int i, res, err;
147 
148 	state = allocate_partitions(hd);
149 	if (!state)
150 		return NULL;
151 	state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
152 	if (!state->pp_buf) {
153 		free_partitions(state);
154 		return NULL;
155 	}
156 	state->pp_buf[0] = '\0';
157 
158 	state->bdev = bdev;
159 	disk_name(hd, 0, state->name);
160 	snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
161 	if (isdigit(state->name[strlen(state->name)-1]))
162 		sprintf(state->name, "p");
163 
164 	i = res = err = 0;
165 	while (!res && check_part[i]) {
166 		memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
167 		res = check_part[i++](state);
168 		if (res < 0) {
169 			/* We have hit an I/O error which we don't report now.
170 		 	* But record it, and let the others do their job.
171 		 	*/
172 			err = res;
173 			res = 0;
174 		}
175 
176 	}
177 	if (res > 0) {
178 		printk(KERN_INFO "%s", state->pp_buf);
179 
180 		free_page((unsigned long)state->pp_buf);
181 		return state;
182 	}
183 	if (state->access_beyond_eod)
184 		err = -ENOSPC;
185 	if (err)
186 	/* The partition is unrecognized. So report I/O errors if there were any */
187 		res = err;
188 	if (res) {
189 		if (warn_no_part)
190 			strlcat(state->pp_buf,
191 				" unable to read partition table\n", PAGE_SIZE);
192 		printk(KERN_INFO "%s", state->pp_buf);
193 	}
194 
195 	free_page((unsigned long)state->pp_buf);
196 	free_partitions(state);
197 	return ERR_PTR(res);
198 }
199