Skip to content

Instantly share code, notes, and snippets.

@spacelatte
Last active October 10, 2016 18:31
Show Gist options
  • Save spacelatte/f8a99486e5027a86f7efe75d48593fc3 to your computer and use it in GitHub Desktop.
Save spacelatte/f8a99486e5027a86f7efe75d48593fc3 to your computer and use it in GitHub Desktop.
disk managament/partitioning program in C (you can use arbitary files as disk images also)
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>
#include <fcntl.h>
#define BS 65536
#define OUT stderr
#define MAXPARTS 12
#define LBLSIZE 256
#define HEXWIDTH 32
#define CLR_DEFAULT "\033[0m"
#define CLR_BLACK "\033[30m"
#define CLR_RED "\033[31m"
#define CLR_GREEN "\033[32m"
#define CLR_YELLOW "\033[33m"
#define MAX(a,b) ( (a>b)?(a):(b) )
#define MIN(a,b) ( (a<b)?(a):(b) )
// typedef enum { false, true } bool;
typedef enum part_flags {
UNALLOCATED = 0,
STANDARD = 1<<0,
HIDDEN = 1<<1,
BOOT = 1<<2,
READONLY = 1<<3,
SWAP = 1<<4,
_PR1 = 1<<5,
_PR2 = 1<<6,
_PR3 = 1<<7,
_PR4 = 1<<8,
} part_flags_t;
typedef enum disk_flags {
UNINITIALIZED = 0,
INITIALIZED = 1<<0,
GHOST = 1<<1,
BACKUP = 1<<2,
RAID = 1<<3,
TEMP = 1<<4,
_DR1 = 1<<5,
_DR2 = 1<<6,
_DR3 = 1<<7,
_DR4 = 1<<8,
} disk_flags_t;
typedef struct part {
unsigned long id;
unsigned long start;
unsigned long end;
unsigned short type;
unsigned char flags;
char label[LBLSIZE];
} part_t;
typedef struct disk {
unsigned long id;
unsigned long size;
unsigned char flags;
char label[LBLSIZE];
part_t parts[MAXPARTS];
} disk_t;
const char magic[] = {'t', 'e', 's', 't', '\0'};
char mode = 0;
void print(FILE *output, const char *function, const char *format, ...) {
va_list args;
va_start(args,format);
char data[strlen(function)+strlen(format)+32];
sprintf(data,"[%ld] [%s]: %s\n",time(NULL),function,format);
vfprintf(output,data,args);
va_end(args);
return;
}
void hexdump(void *object, size_t length) {
for(int i=0;i<length;i++) {
if(i%HEXWIDTH == 0)
printf("\n% 8d |",i);
printf(" %2hhx",*(char*)(object+i));
}
printf("\n%8zu\n",length);
return;
}
void error(FILE *out, unsigned short code, const char *err, ...) {
va_list args;
va_start(args,err);
char data[strlen(err)+32];
sprintf(data,"\033[31mERR (%hd): %s\033[0m\n",code,err);
vfprintf(out,data,args);
va_end(args);
return;
}
disk_t *disk_create(void) {
disk_t *disk = malloc(sizeof(disk_t));
return disk;
}
void disk_edit(disk_t *disk, unsigned long id, unsigned char flags, const char *label, long size) {
if(!disk) {
error(OUT,1,"valid disk pointer necessary to edit drive");
return;
}
disk->id = id;
disk->flags = flags;
if(size)
disk->size = size;
if(label)
strncpy(disk->label,label,LBLSIZE);
return;
}
part_t *part_create(void) {
part_t *part = malloc(sizeof(part_t));
return part;
}
void part_edit(part_t *part, unsigned long id, unsigned long start, unsigned long end, unsigned short type, unsigned char flags, const char *label) {
// do sanity checks
if(!part || start < 2048 || start <= sizeof(disk_t)/*+sizeof(magic)*/ || end <= start) {
error(OUT,2,"part edit param check failed");
return;
}
part->id = id;
part->start = start;
part->end = end;
part->type = type;
part->flags = flags;
if(label)
strncpy(part->label,label,LBLSIZE);
return;
}
void disk_initialize(disk_t *disk, long size) {
if(disk) {
memset(disk,0,sizeof(disk_t)); // just zero main table
disk_edit(disk,time(NULL),INITIALIZED,NULL,size);
}
return;
if(disk) {
free(disk); // remove old reference
disk = disk_create(); // and create new
}
return;
}
void part_create_handler(disk_t *disk) {
char label[LBLSIZE];
short part, type;
long start, end;
printf("enter partition number to create (%d-%d): ",1,MAXPARTS);
scanf(" %hd",&part);
printf("enter start (%lu-%lu): ",(MAX(2048,sizeof(disk_t)))/(1<<mode),(disk->size-1)/(1<<mode));
scanf(" %ld",&start);
printf("enter end (%lu-%lu): ",start+1,(disk->size-1)/(1<<mode));
scanf(" %ld",&end);
printf("enter type (%04x-%04x): ",0x0001,0xffff);
scanf(" %hx",&type);
printf("enter label: ");
scanf(" %[^\n]",label);
start *= (1<<mode);
end *= (1<<mode);
if(start <= MAX(2048,sizeof(disk_t)))
start = MAX(2048,sizeof(disk_t))+1;
if(end >= disk->size-1 || end <= start)
end = disk->size-1;
if(disk->parts[part].id && disk->parts[part].flags) {
error(OUT,31,"error, this space is allocated already");
return;
}
for(int i=0;i<MAXPARTS;i++) {
if(start >= disk->parts[i].start && start <= disk->parts[i].end) {
error(OUT,32,"error, this space is allocated already");
return;
}
if(end <= disk->parts[i].end && start >= disk->parts[i].start) {
error(OUT,33,"error, this space is allocated already");
return;
}
continue;
}
// print(OUT,__func__,"part; s: %ld, e: %ld",start,end);
part_edit(&(disk->parts[part-1]),time(NULL),start,end,type,STANDARD,label);
return;
}
void part_delete(disk_t *disk, unsigned part) {
memset(disk->parts+part,0,sizeof(part_t));
return;
}
void pretty_print(disk_t *disk) {
printf(
"disk id: %ld\n"
"disk size: %ld\n"
"disk flags: %02x\n"
"disk label: %s\n"
,disk->id
,disk->size/(1<<mode)
,disk->flags
,disk->label
);
for(int i=0;i<MAXPARTS;i++)
if(disk->parts[i].id && disk->parts[i].flags)
printf(
"\t> partition: %d\n"
"\tpart id: %ld\n"
"\tpart size: %ld\n"
"\tpart start: %ld\n"
"\tpart end: %ld\n"
"\tpart type: %04x\n"
"\tpart flags: %02x\n"
"\tpart label: %s\n"
"\n",i+1
,disk->parts[i].id
,((disk->parts[i].end)-(disk->parts[i].start))/(1<<mode)
,disk->parts[i].start
,disk->parts[i].end
,disk->parts[i].type
,disk->parts[i].flags
,disk->parts[i].label
);
return;
}
void write_to(int fd, disk_t *disk) {
lseek(fd,0,SEEK_SET);
write(fd,magic,sizeof(magic));
write(fd,disk,sizeof(disk_t));
return;
}
bool menu(const char *file, disk_t *disk) {
int fd = open(file, O_RDWR|O_CREAT|O_SYMLINK);
char *bytes = malloc(sizeof(magic));
long size = lseek(fd,0L,SEEK_END);
lseek(fd,0L,SEEK_SET);
read(fd,bytes,sizeof(magic));
if(!disk->id && !disk->size) {
read(fd,disk,sizeof(disk_t));
for(int i=0;i<sizeof(magic);i++)
if(magic[i] != bytes[i]) {
disk_initialize(disk,size);
error(OUT,4,"partition table not found, creating new one");
write_to(fd,disk);
break;
}
disk->size = size;
}
free(bytes); // free mem
// menu
printf(
"o) new partition table\n"
"n) new partition\n"
"d) delete partition\n"
"m) change coefficient (k/m/g)\n"
"p) show table\n"
"x) hexdump current\n"
"w) write to disk\n"
"e) exit (switches to next)\n"
"q) quit application\n"
"#) wipe drive\n"
"selection: (mode: 2^%hhd) > ",mode
);
char sel;
scanf(" %c",&sel);
if(sel > 127 || sel < 32)
return false;
char *block = malloc(sizeof(char)*BS);
switch(tolower(sel)) {
case 'o':
disk_initialize(disk,size);
break;
case 'n':
part_create_handler(disk);
break;
case 'd':
printf("enter partition number to delete (%d-%d): ",1,MAXPARTS);
scanf(" %hhd",&sel);
if(sel > 0 && sel < MAXPARTS)
part_delete(disk,sel-1);
else
error(OUT,6,"invalid input");
break;
case 'x':
hexdump(disk,sizeof(disk_t));
break;
case 'p':
pretty_print(disk);
break;
case 'w':
write_to(fd,disk);
break;
case 'e':
return false;
break;
case 'm':
printf("enter desired mode (n/k/m/g): ");
scanf(" %c",&sel);
switch(tolower(sel)) {
case 'n':
mode = 0;
break;
case 'k':
mode = 10;
break;
case 'm':
mode = 20;
break;
case 'g':
mode = 30;
break;
default:
error(stdout,7,"not implemented");
}
break;
case 'q':
exit(0);
break;
case '#':
lseek(fd,0L,SEEK_SET);
printf("Wipe sequence initialized to sector %ld\n",size);
for(long i=0;i<size;i+=BS) {
printf("> from %ld, to %ld, current %ld \n",sizeof(disk_t),size,i);
write(fd,block,sizeof(char)*BS);
}
break;
default:
error(stdout,0,"not implemented");
}
close(fd);
return true;
}
int main(int argc, char **argv) {
if(argc < 2) {
error(OUT,0,"At least 1 argument required!");
return 1;
}
disk_t *cdisk = malloc(sizeof(disk_t));
// print(OUT,__func__,"test %d",1);
for(int i=1;i<argc;i++) {
while(menu(argv[i],cdisk));
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment