157 lines · 4.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *  fs/partitions/mac.c * *  Code extracted from drivers/block/genhd.c *  Copyright (C) 1991-1998  Linus Torvalds *  Re-organised Feb 1998 Russell King */ #include <linux/ctype.h>#include "check.h"#include "mac.h" #ifdef CONFIG_PPC_PMAC#include <asm/machdep.h>extern void note_bootable_part(dev_t dev, int part, int goodness);#endif /* * Code to understand MacOS partition tables. */ #ifdef CONFIG_PPC_PMACstatic inline void mac_fix_string(char *stg, int len){	int i; 	for (i = len - 1; i >= 0 && stg[i] == ' '; i--)		stg[i] = 0;}#endif int mac_partition(struct parsed_partitions *state){	Sector sect;	unsigned char *data;	int slot, blocks_in_map;	unsigned secsize, datasize, partoffset;#ifdef CONFIG_PPC_PMAC	int found_root = 0;	int found_root_goodness = 0;#endif	struct mac_partition *part;	struct mac_driver_desc *md; 	/* Get 0th block and look at the first partition map entry. */	md = read_part_sector(state, 0, &sect);	if (!md)		return -1;	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {		put_dev_sector(sect);		return 0;	}	secsize = be16_to_cpu(md->block_size);	put_dev_sector(sect); 	/*	 * If the "block size" is not a power of 2, things get weird - we might	 * end up with a partition straddling a sector boundary, so we wouldn't	 * be able to read a partition entry with read_part_sector().	 * Real block sizes are probably (?) powers of two, so just require	 * that.	 */	if (!is_power_of_2(secsize))		return -1;	datasize = round_down(secsize, 512);	data = read_part_sector(state, datasize / 512, &sect);	if (!data)		return -1;	partoffset = secsize % 512;	if (partoffset + sizeof(*part) > datasize) {		put_dev_sector(sect);		return -1;	}	part = (struct mac_partition *) (data + partoffset);	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {		put_dev_sector(sect);		return 0;		/* not a MacOS disk */	}	blocks_in_map = be32_to_cpu(part->map_count);	if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {		put_dev_sector(sect);		return 0;	} 	if (blocks_in_map >= state->limit)		blocks_in_map = state->limit - 1; 	seq_buf_puts(&state->pp_buf, " [mac]");	for (slot = 1; slot <= blocks_in_map; ++slot) {		int pos = slot * secsize;		put_dev_sector(sect);		data = read_part_sector(state, pos/512, &sect);		if (!data)			return -1;		part = (struct mac_partition *) (data + pos%512);		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)			break;		put_partition(state, slot,			be32_to_cpu(part->start_block) * (secsize/512),			be32_to_cpu(part->block_count) * (secsize/512)); 		if (!strncasecmp(part->type, "Linux_RAID", 10))			state->parts[slot].flags = ADDPART_FLAG_RAID;#ifdef CONFIG_PPC_PMAC		/*		 * If this is the first bootable partition, tell the		 * setup code, in case it wants to make this the root.		 */		if (machine_is(powermac)) {			int goodness = 0; 			mac_fix_string(part->processor, 16);			mac_fix_string(part->name, 32);			mac_fix_string(part->type, 32);							    			if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)			    && strcasecmp(part->processor, "powerpc") == 0)				goodness++; 			if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0			    || (strncasecmp(part->type, "Linux", 5) == 0			        && strcasecmp(part->type, "Linux_swap") != 0)) {				int i, l; 				goodness++;				l = strnlen(part->name, sizeof(part->name));				if (strncmp(part->name, "/", sizeof(part->name)) == 0)					goodness++;				for (i = 0; i <= l - 4; ++i) {					if (strncasecmp(part->name + i, "root",						     4) == 0) {						goodness += 2;						break;					}				}				if (strncasecmp(part->name, "swap", 4) == 0)					goodness--;			} 			if (goodness > found_root_goodness) {				found_root = slot;				found_root_goodness = goodness;			}		}#endif /* CONFIG_PPC_PMAC */	}#ifdef CONFIG_PPC_PMAC	if (found_root_goodness)		note_bootable_part(state->disk->part0->bd_dev, found_root,				   found_root_goodness);#endif 	put_dev_sector(sect);	seq_buf_puts(&state->pp_buf, "\n");	return 1;}