[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: debian-installer: disk partitioner



This is the code i have so far that works out a list of used and unused
partitions, the heirarchy thing is working but only to two levels.

I made a md0 array comprised of /dev/hdd1 /dev/hdd2 /dev/hdd3 /dev/hdd4
(silly i know), and it recognised that md0, hdd1 - hdd4 were taken, but
it didnt recognise that hdd was taken.

Once its working, this code could present a list that the user can
select from then depending on the operation they want to perform it can
be passed over to the apropriate tool. 

It is still rough and may need structural changes, i havent debconfiged
it yet either, it just spits out three lists seperated by getchar().


Glenn
/* partition filesystem (real or virtual) that can be mounted */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <linux/posix_types.h>
#undef dev_t
#define dev_t __kernel_dev_t
#include <linux/loop.h>
#undef dev_t


//#include "/usr/src/linux/include/linux/loop.h"

typedef struct partition_s {
	char *device_name;
	char *device_path;
	char *mount_point;
	char *fs_type;
	char *mode;
	short int device_number;
	unsigned long blocks;
	struct partition_s *next;
	struct partition_s **parent;
	int num_of_parents;
} partition_t;

partition_t *head;

char *readline(int fd)
{
	char ch[1];
	char *line = NULL;
	int length = 1;

	line = (char *) malloc(length);
	strcpy(line,"");	
	while (read(fd, ch, 1) > 0) {
		if ((ch[0] == '\n') || (ch[0] == '\0')) {
			break;
		}
		line = (char *) realloc(line, ++length);
		strncat(line, &ch[0], 1);
	}
	if (length==1) {
		return NULL;
	}
	else {
		return line;
	}
}

int parse_proc_partitions()
{
	int fd;
	partition_t *tail;
	char *device;
	int major, minor, blocks;
	char *line = NULL;
		
	device = (char *) malloc(80);
	memset(device, 0, 80);
	tail = (partition_t *) malloc(sizeof(partition_t));

	tail = head;

	if ((fd = open("/proc/partitions", O_RDONLY)) == -1) {
		printf("FIXME: need to mount /proc first\n");
		return EXIT_FAILURE;
	} 
	readline(fd);
	readline(fd);
	while ((line = readline(fd)) != NULL) {
		sscanf(line, "%d %d %d %79s", &major, &minor, &blocks, device);
		tail->device_name = (char *) malloc(strlen(device)+1);
		strcpy(tail->device_name, device);
		tail->device_number = (major << 8) + minor;
		tail->blocks = blocks;

		tail->next = (partition_t *) malloc(sizeof(partition_t));
		memset(tail->next, 0, sizeof(partition_t));
		tail = tail->next;
	}
	tail->next = NULL;
	close(fd);
	return EXIT_SUCCESS;
}

/* add nodev devices to partitions list */
int parse_proc_filesystems()
{
	char *line;
	char *fs_type;
	int fd;

	fs_type = (char *) malloc(21);
	if ((fd = open("/proc/filesystems", O_RDONLY)) == -1) {
		printf("FIXME: need to mount /proc first\n");
		return EXIT_FAILURE;
	} 

	/* consider nodev filesystems like partitions*/
	while ((line = readline(fd)) != NULL) {
		memset(fs_type, 0, 21);
		sscanf(line,"nodev %20s", fs_type);
		if (strlen(fs_type) > 0) {
			partition_t *new_part;

			new_part = (partition_t *) malloc(sizeof(partition_t));
			new_part->device_name = (char *) malloc(strlen(fs_type)+1);
			strcpy(new_part->device_name, fs_type);
			new_part->device_number = 0;
			new_part->blocks = 0;

			new_part->next = (partition_t *) malloc(sizeof(partition_t));
			memset(new_part->next, 0, sizeof(partition_t));
			*new_part->next = *head;
			*head = *new_part;
		}
	}
	close(fd);
	return EXIT_SUCCESS;
}

partition_t *seek_device_number(short int device_number)
{
	partition_t *part;
	part = (partition_t *) malloc(sizeof(partition_t));
	part = head; 

	while(part->next != NULL) {
		if (part->device_number == device_number) {
			return part;
		}
		part = part->next;
	}
	return NULL;
}

partition_t *seek_device_name(const char *name)
{
	partition_t *part;
	part = (partition_t *) malloc(sizeof(partition_t));
	part = head; 

	while(part->next != NULL) {
		if (strcmp(part->device_name, name) == 0) {
			return part;
		}
		part = part->next;
	}
	return NULL;
}

/* parse /proc/mounts and fill in struct info*/
int parse_proc_mounts()
{
	int fd = 0;
	char *device_path, *mount_point, *fs_type;
	partition_t *tmp_part;
	char *line = NULL;
	struct stat statbuf;
	
	tmp_part = (partition_t *) malloc(sizeof(partition_t));
	device_path = (char *) malloc(80);
	mount_point = (char *) malloc(80);
	fs_type = (char *) malloc(80);

	if ((fd = open("/proc/mounts", O_RDONLY)) == -1) {
		printf("FIXME: need to mount /proc first\n");
		return EXIT_FAILURE;
	} 

	while ((line = readline(fd)) != NULL) {
		sscanf(line, "%79s %79s %79s ", device_path, mount_point, fs_type);
		stat(mount_point, &statbuf);

		/* first try and match with details from /proc/partitions */
		if ((tmp_part = seek_device_number(statbuf.st_dev)) != NULL) {
			tmp_part->device_path = (char *) malloc(strlen(device_path)+1);
			strcpy(tmp_part->device_path, device_path);
			tmp_part->mount_point = (char *) malloc(strlen(mount_point)+1);
			strcpy(tmp_part->mount_point, mount_point);
			tmp_part->fs_type = (char *) malloc(strlen(fs_type)+1);
			strcpy(tmp_part->fs_type, fs_type);
			continue;
		}
		/* it might be a virtual mount that has no device number */
		if ((tmp_part = seek_device_name(fs_type)) != NULL) {
			tmp_part->device_path = (char *) malloc(6);
			strcpy(tmp_part->device_path, "nodev");
			tmp_part->mode = (char *) malloc(3);
			strcpy(tmp_part->mode, "sp"); /* special device, dunno if rw or ro*/
			tmp_part->mount_point = (char *) malloc(strlen(mount_point)+1);
			strcpy(tmp_part->mount_point, mount_point);
			tmp_part->fs_type = (char *) malloc(strlen(fs_type)+1);
			strcpy(tmp_part->fs_type, fs_type);
			continue;
		}
		/* We have to handle loop devices seperately 
		   and dont find them till they are mounted */
		if ((statbuf.st_dev >> 8) == 7) {
			int fd;
			struct loop_info loopinfo;

			tmp_part = (partition_t *) malloc(sizeof(partition_t));

			/* from /proc/mounts */
			tmp_part->device_path = (char *) malloc(strlen(device_path)+1);
			strcpy(tmp_part->device_path, device_path);
			tmp_part->mount_point = (char *) malloc(strlen(mount_point)+1);
			strcpy(tmp_part->mount_point, mount_point);
			tmp_part->fs_type = (char *) malloc(strlen(fs_type)+1);
			strcpy(tmp_part->fs_type, fs_type);
			tmp_part->device_number = statbuf.st_dev;

			/* fill in other stuff from ioctl */
			if ((fd = open(device_path, O_RDONLY)) == -1) {
				printf("Couldnt open loop device %s \n",device_path);
				perror("");
			}
			if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != -1) {
				tmp_part->device_name = (char *) malloc(strlen(loopinfo.lo_name)+1);
				strcpy(tmp_part->device_name, loopinfo.lo_name);
				stat(loopinfo.lo_name, &statbuf);
				tmp_part->blocks = statbuf.st_size/1024;
				tmp_part->next = (partition_t *) malloc(sizeof(partition_t));
				*tmp_part->next = *head;
				*head = *tmp_part;
			}
			close(fd);
			continue;
		}
		printf("FIXME: couldnt find device [%s] in the /proc/partitions\n",device_path);
	}
	close(fd);
	return EXIT_SUCCESS;
}


/* get parents of md devices, maybe used to get other info later */
int parse_proc_mdstat(partition_t *part)
{
	char *line = NULL;
	char *drives = NULL;
	char *onedrive = NULL;
	int fd;
	partition_t *parent;

	parent = (partition_t *) malloc(sizeof(partition_t));

	if ((fd = open("/proc/mdstat", O_RDONLY)) == -1) {
		printf("FIXME: need to mount /proc first\n");
		return EXIT_FAILURE;
	} 

	while ((line = readline(fd)) != NULL) {
		int tail_length = 0;
		int full_length = 0;

		if (strncmp(part->device_name, line, strlen(part->device_name)) != 0) {
			continue;
		}

		drives = realloc(drives, strlen(line));
		drives = strstr(line, " : active ");
		drives += 10;

//		part->num_of_parents = 0;
//		part->parent = NULL;
		full_length = strlen(drives);
		onedrive = realloc(onedrive, full_length);
		while ((onedrive = strrchr(drives, ' ')) != NULL ) {
			partition_t *parent_partition = NULL;

			/* fix things up ready for next iteration */
			tail_length = strlen(onedrive);
			drives[full_length - tail_length] = '\0'; /* in future ignore the tail */
			full_length = strlen(drives);

			/* extract the device name */
			/* jump past the space */
			onedrive++;
			/* strip trialing [x], x is a number */
			onedrive[strlen(strstr(onedrive, "["))+1] = '\0';

			/* add to list of parents */
			parent_partition = seek_device_name(onedrive);	
			part->num_of_parents++;
			part->parent = realloc(part->parent, part->num_of_parents);
			part->parent[part->num_of_parents-1] = parent_partition;
		}
	}
	return EXIT_FAILURE;
}

/* find parents of those who have them, e.g. hda is the parent of hda1
   also find partents of md, loop, lvm */
int find_parent_devices()
{
	struct stat statbuf;
	partition_t *part, *parents, *tmp_part;
	int i,j;

	part = head;	
	while(part->next != NULL) {
		part->num_of_parents = 0;
		part->parent = NULL;
		switch (part->device_number >> 8) {
			/* loop */
			case 7:
				stat(part->device_name, &statbuf);
				parents = seek_device_number(statbuf.st_dev);
				part->num_of_parents++;
				part->parent = realloc(part->parent, part->num_of_parents);
				part->parent[part->num_of_parents - 1] = parents;
				break;
			/* md */
			case 9: {
				parse_proc_mdstat(part);
				break;
			}
			/* lvm */
			case 58:
				break;
				/* normal partitions e.g. hda is hda1's parent*/
			default: {
				char parent_name[strlen(part->device_name)+1];
				int i=0;
				strcpy(parent_name, part->device_name);
				for (i = strlen(part->device_name)-1; i > 0; i++) {
					if (isdigit(parent_name[i])) {
						parent_name[i] = '\0';
					}
					else {
						break;
					}
				}
				if ((parents = seek_device_name(parent_name)) != NULL) {
					part->num_of_parents++;
					part->parent = realloc(part->parent, part->num_of_parents*sizeof(partition_t *));
					part->parent[part->num_of_parents - 1] = parents;
				}
			}
		}
		part = part->next;
	}

	/* find all grandparents as well */
	part = head;
	while(part->next != NULL) {
		i = 0;
		while (i < part->num_of_parents) {
			for(j = part->parent[i]->num_of_parents - 1; j > 0; j-- ) {
				part->num_of_parents++;
				tmp_part = (partition_t *) malloc(sizeof(partition_t *));
				part->parent = realloc((partition_t *)part->parent, part->num_of_parents*sizeof(partition_t));
				tmp_part = part->parent[i]->parent[j];
				part->parent[part->num_of_parents - 1] = tmp_part;
			}
			i++;			
		}
		part = part->next;
	}

	return EXIT_SUCCESS;
}

partition_t *mounted_partitions()
{
	partition_t *all_parts, *part, *tmp_part;

	all_parts = (partition_t *) malloc(sizeof(partition_t)); 
	part = (partition_t *) malloc(sizeof(partition_t)); 
	memset(part, 0, sizeof(partition_t));
	tmp_part = (partition_t *) malloc(sizeof(partition_t)); 

	all_parts = head;

	while(all_parts->next != NULL) {
		if (all_parts->mount_point != NULL) {
			*tmp_part = *all_parts;
			tmp_part->next = (partition_t *) malloc(sizeof(partition_t)); 
			memset(tmp_part->next, 0, sizeof(partition_t));
			*tmp_part->next = *part;
			*part = *tmp_part;
		}		
		all_parts = all_parts->next;
	}
	return part;
}

/* unused partitions are those that arent mounted, and dont have known children */
partition_t *unused_partitions()
{
	partition_t *part, *mounted_part, *unused_part, *tmp_part, *tmp_part2;
	int found = 0;

	part = (partition_t *) malloc(sizeof(partition_t)); 
	mounted_part = (partition_t *) malloc(sizeof(partition_t));
	unused_part = (partition_t *) malloc(sizeof(partition_t));

	mounted_part = mounted_partitions();

	tmp_part = head;
	while(tmp_part->next != NULL) {
		found = 0;
		tmp_part2 = mounted_part;
		while(tmp_part2->next != NULL) {
			int i=0;
			if (strcmp(tmp_part->device_name, tmp_part2->device_name) == 0) {
				found = 1;
				break;
			}
			for (i = tmp_part2->num_of_parents; i > 0; i--) {
				part = tmp_part2->parent[i-1];
				if (strcmp(tmp_part->device_name, part->device_name) == 0) {
					found = 1;
					break;
				}
			}

			if (found == 1) {
				break;
			}
			tmp_part2 = tmp_part2->next;
		}
		if (found == 0) {
			*part = *tmp_part;
			part->next = (partition_t *) malloc(sizeof(partition_t));
			*part->next = *unused_part;
			*unused_part = *part;
		}
		tmp_part = tmp_part->next;
	}
	return unused_part;
}

int main()
{
	partition_t *part, *tmp;
	head = (partition_t *) malloc(sizeof(partition_t));
	memset(head, 0, sizeof(partition_t));
	part = (partition_t *) malloc(sizeof(partition_t));
	memset(part, 0, sizeof(partition_t));
	part = head;

	parse_proc_partitions();
	parse_proc_filesystems();
	parse_proc_mounts();
	printf("starting find parent devices\n");
	find_parent_devices();

	printf("complete list\n");
	part = head;
	while(part->next != NULL) {
		printf("device name is %s\n",part->device_name);
/*		printf(" device name is %s ",part->device_path);
		printf(" fs type is %s",part->fs_type);
		printf(" mount point is %s",part->mount_point);
		printf(" size is %ld\n",part->blocks);
*/		part = part->next;
	}
	getchar();

	part = mounted_partitions();
	printf("mounted list\n");
	while(part->next != NULL) {
		printf("device name is %s\n",part->device_name);
/*		printf(" fs type is %s ",part->fs_type);
		printf(" mount point is %s",part->mount_point);
		printf(" size is %ld\n",part->blocks);
		if (part->num_of_parents == 1) {
			tmp = part->parent[0];
			printf("parent name is [%s]\n",tmp->device_name);
		}*/
		part = part->next;
	}
	getchar();

	part = unused_partitions();
	printf("unused  list\n");
	while(part->next != NULL) {
		printf("device name is %s \n",part->device_name);
/*		printf(" fs type is %s ",part->fs_type);
		printf(" mount point is %s",part->mount_point);
		printf(" size is %ld\n",part->blocks);
		if (part->num_of_parents == 1) {
			tmp = part->parent[0];
			printf("parent name is [%s]\n",tmp->device_name);
		} */
		part = part->next;
	}

	return EXIT_SUCCESS;
}


Reply to: