Add nice logs
diff --git a/include/kernel/dri/fs/ext2/ext2.h b/include/kernel/dri/fs/ext2/ext2.h
index 1adf51c..4205c4b 100644
--- a/include/kernel/dri/fs/ext2/ext2.h
+++ b/include/kernel/dri/fs/ext2/ext2.h
@@ -78,5 +78,8 @@
 	EXT2_OS_OTHER_BSD,
 };
 
+#define EXT2_SIGNATURE 0xef53
+
 struct ext2_superblock ext2_read_superblock();
 void ext2_mount(struct fs_node *where);
+bool ext2_valid_filesystem();
diff --git a/include/kernel/io.h b/include/kernel/io.h
index 136c4f9..718bb20 100644
--- a/include/kernel/io.h
+++ b/include/kernel/io.h
@@ -28,6 +28,9 @@
 int strcmp(char *a, char *b);
 uint strlen(char *a);
 
+bool isdigit(char c);
+uint parse_int(char *string);
+
 uchar kbd_scan_code();
 void kbd_handle_input(struct registers *registers);
 void init_kbd();
diff --git a/include/kernel/log.h b/include/kernel/log.h
index fe5dcd9..3365474 100644
--- a/include/kernel/log.h
+++ b/include/kernel/log.h
@@ -2,11 +2,17 @@
 
 #include "kint.h"
 
+#define RESET "\033[0m"
+#define INFO "[\033[96m INFO  " RESET "] "
+#define OKAY "[\033[92m  OK   " RESET "] "
+#define ERROR "[\033[91m ERROR " RESET "] "
+#define DEBUG "[\033[93m DEBUG " RESET "] "
+
 void kprintf(const char *format, ...);
 void kassert_int(bool condition, const char *message, const char *file,
 				 const int line);
 
 #define kassert(cond, msg) kassert_int((cond), (msg), __FILE__, __LINE__)
-#define kpanic(msg)                                                            \
-	kassert(false, msg);                                                       \
+#define kpanic(msg)      \
+	kassert(false, msg); \
 	__builtin_unreachable()
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index 3b718b8..8beb214 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -27,7 +27,7 @@
 
 LDFLAGS += -Tlink.ld -melf_i386
 ASMFLAGS += -felf -Fdwarf
-QEMUFLAGS = -d cpu_reset -hda hd0_$(FS).img
+QEMUFLAGS = -hda hd0_$(FS).img
 
 OBJECTS = 	boot.o \
 			main.o \
@@ -63,7 +63,7 @@
 	qemu-system-i386 -s -S -kernel kernel.elf
 
 debug: kernel.elf
-	qemu-system-i386 -s -S -kernel kernel.elf &
+	qemu-system-i386 -s -S $(QEMUFLAGS) -kernel kernel.elf &
 	@echo run "target remote localhost:1234" to connect to qemu
 	gdb $<
 	@pkill qemu-system-i38
@@ -74,7 +74,7 @@
 	@$(patsubst hd0_%.img,mkfs.%,$@) $@
 
 qemu: kernel.elf hd0_$(FS).img
-	qemu-system-i386 $(QEMUFLAGS) -monitor stdio -kernel kernel.elf -no-reboot
+	qemu-system-i386 $(QEMUFLAGS) -d cpu_reset -monitor stdio -kernel kernel.elf -no-reboot
 
 qemu-iso: install
 	qemu-system-i386 $(QEMUFLAGS) -monitor stdio $(ROOT)/bin/bluejay.iso
@@ -84,9 +84,9 @@
 
 mount: hd0_$(FS).img
 	status_log(MOUNT, $^ $(ROOT)/mnt)
-	@if [ $(whoami) = root ]; then echo "DON'T RUN THIS AS ROOT" && exit 1; fi
+	@if [ "$(whoami)" = root ]; then echo "DON'T RUN THIS AS ROOT" && exit 1; fi
 	@mkdir -p $(ROOT)/mnt
-	@sudo mount $^ $(ROOT)/mnt -o rw,uid=$$(id -u),gid=$$(id -g)
+	@mount $^ $(ROOT)/mnt
 
 umount:
 	status_log(UMOUNT, $(ROOT)/mnt)
diff --git a/src/kernel/alloc.c b/src/kernel/alloc.c
index e3c85b1..9c08098 100644
--- a/src/kernel/alloc.c
+++ b/src/kernel/alloc.c
@@ -290,13 +290,13 @@
 	for (int i = 0; i < 12; i++)
 		array[i] = i;
 
-	kprintf("Allocated one, two, array[3] = %d, %d, %d\n", *one, *two,
+	kprintf(DEBUG "Allocated one, two, array[3] = %d, %d, %d\n", *one, *two,
 			array[3]);
-	kprintf("[%x, %x, %x]\n", one, two, array);
+	kprintf(DEBUG "[%x, %x, %x]\n", one, two, array);
 
-	kprintf("Freeing two\n");
+	kprintf(DEBUG "Freeing two\n");
 	free(two);
 	int *four = malloc(sizeof(int));
 	*four = 4;
-	kprintf("Allocated four = %d (%x)\n", *four, four);
+	kprintf(DEBUG "Allocated four = %d (%x)\n", *four, four);
 }
diff --git a/src/kernel/dri/ata_pio/ata_pio.c b/src/kernel/dri/ata_pio/ata_pio.c
index db1b7cb..cf55b51 100644
--- a/src/kernel/dri/ata_pio/ata_pio.c
+++ b/src/kernel/dri/ata_pio/ata_pio.c
@@ -76,7 +76,7 @@
 
 void test_ata_pio()
 {
-	kprintf("Going to ata_pio_read_sectors\n");
+	kprintf(INFO "Going to ata_pio_read_sectors\n");
 
 	ata_pio_read_sectors(test_buffer, 0, 1);
 	print_buffer();
diff --git a/src/kernel/dri/fs/ext2/ext2.c b/src/kernel/dri/fs/ext2/ext2.c
index 31ed7fe..d0dd3bd 100644
--- a/src/kernel/dri/fs/ext2/ext2.c
+++ b/src/kernel/dri/fs/ext2/ext2.c
@@ -16,5 +16,12 @@
 {
 	struct ext2_superblock sb = ext2_read_superblock();
 
-	kprintf("Magic = 0x%x\n", sb.signature);
+	kprintf(INFO "EXT2 magic = 0x%x\n", sb.signature);
 }
+
+bool ext2_valid_filesystem()
+{
+	struct ext2_superblock sb = ext2_read_superblock();
+
+	return sb.signature == EXT2_SIGNATURE;
+}
\ No newline at end of file
diff --git a/src/kernel/dri/ide/ide.c b/src/kernel/dri/ide/ide.c
index 21f2651..0025970 100644
--- a/src/kernel/dri/ide/ide.c
+++ b/src/kernel/dri/ide/ide.c
@@ -16,12 +16,12 @@
 
 void ide_print_device(struct ide_device *dev)
 {
-    kprintf("<ide-device dma=%b>", dev->supports_dma);
+    kprintf(INFO "<ide-device dma=%b>", dev->supports_dma);
 }
 
 void ide_thread(struct ide_thread_data *data)
 {
-    kprintf("IDE driver thread starting: device=0x%x\n", data->dev.device_id);
+    kprintf(DEBUG "IDE driver thread starting: device=0x%x\n", data->dev.device_id);
 
     struct ide_device dev;
 
diff --git a/src/kernel/dri/pci/pci.c b/src/kernel/dri/pci/pci.c
index 6d35edc..4d2d01e 100644
--- a/src/kernel/dri/pci/pci.c
+++ b/src/kernel/dri/pci/pci.c
@@ -67,7 +67,7 @@
 
 void pci_print_devices()
 {
-	kprintf("Enumerating PCI devices:\n");
+	kprintf(INFO "Enumerating PCI devices:\n");
 	for (int bus = 0; bus < 0xff; bus++)
 	{
 		for (int slot = 0; slot < 32; slot++)
@@ -78,7 +78,7 @@
 
 				if (dev.valid)
 				{
-					kprintf("%d %d %d --- d:0x%x --- %d:%d:%d --- %s\n", bus,
+					kprintf(INFO "%d %d %d --- d:0x%x --- %d:%d:%d --- %s\n", bus,
 							slot, func, dev.device_id, dev.class, dev.subclass,
 							dev.prog_if, dev.vendor->name);
 				}
@@ -134,13 +134,13 @@
 
 void pci_print_drivers()
 {
-	kprintf("Enumerating PCI device drivers:\n");
+	kprintf(INFO "Enumerating PCI device drivers:\n");
 	for (int i = 0; i < num_drivers; i++)
 	{
 		for (int j = 0; j < drivers[i].loaded; j++)
 		{
 			struct pci_device_driver d = drivers[i];
-			kprintf("Driver: %s, vendor: %s\n", d.generic_name, d.dev.vendor->name);
+			kprintf(INFO "Driver: %s, vendor: %s\n", d.generic_name, d.dev.vendor->name);
 		}
 	}
 }
diff --git a/src/kernel/faults.c b/src/kernel/faults.c
index ba5a615..e7c4180 100644
--- a/src/kernel/faults.c
+++ b/src/kernel/faults.c
@@ -4,7 +4,7 @@
 #define DECLARE_INTERRUPT(sym, name)                                           \
 	static void sym##_h(struct registers *regs)                                \
 	{                                                                          \
-		kprintf("Fault " name ": eip = 0x%x, err = 0x%x\n", regs->eip,         \
+		kprintf(ERROR "Fault " name ": eip = 0x%x, err = 0x%x\n", regs->eip,   \
 				regs->error_code);                                             \
 		asm volatile("cli");                                                   \
 		kpanic(name);                                                          \
diff --git a/src/kernel/io.c b/src/kernel/io.c
index 90a365c..c53ef17 100644
--- a/src/kernel/io.c
+++ b/src/kernel/io.c
@@ -124,3 +124,21 @@
 	memset(pressed_keys, 0, LAST_KBD_KEY);
 	add_interrupt_handler(33, kbd_handle_input);
 }
+
+bool isdigit(char c)
+{
+	return c >= '0' && c <= '9';
+}
+
+uint parse_int(char *string)
+{
+	uint number = 0;
+
+	for (; isdigit(*string); string++)
+	{
+		number *= 10;
+		number += *string - '0';
+	}
+
+	return number;
+}
diff --git a/src/kernel/log.c b/src/kernel/log.c
index 11ce505..ff22727 100644
--- a/src/kernel/log.c
+++ b/src/kernel/log.c
@@ -66,7 +66,7 @@
 	if (!condition)
 	{
 		vga_set_color(LIGHT_RED, BLACK);
-		kprintf("ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
+		kprintf(ERROR "ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
 
 		while (1)
 		{
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 0fef9c5..04dc9a7 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -17,15 +17,15 @@
 
 void greet()
 {
-	kprintf("Hello from get_task_id() = %d, get_process_id() = %d\n",
+	kprintf(DEBUG "Hello from get_task_id() = %d, get_process_id() = %d\n",
 			get_task_id(), get_process_id());
 }
 
 void other_thread(size_t data)
 {
-	kprintf("data is 0x%x\n", data);
+	kprintf(DEBUG "data is 0x%x\n", data);
 	greet();
-	kprintf("Returning from other_thread\n");
+	kprintf(DEBUG "Returning from other_thread\n");
 
 	return;
 }
@@ -52,27 +52,25 @@
 
 #ifdef INITRD
 	kassert(mb.mods_count, "No multiboot modules loaded!");
-	kprintf("mboot->mods_addr = %d (0x%x)\n", mb.mods_addr, mb.mods_addr);
+	kprintf(DEBUG "mboot->mods_addr = %d (0x%x)\n", mb.mods_addr, mb.mods_addr);
 	uchar *initrd_loc = (uchar *)((uint *)mb.mods_addr)[0];
 
-	kprintf("initrd is at 0x%x to 0x%x\n", initrd_loc);
+	kprintf(DEBUG "initrd is at 0x%x to 0x%x\n", initrd_loc);
 
 	init_initrd_vfs(initrd_loc);
 #endif
 
-	kprintf("VFS initialized\n");
+	kprintf(OKAY "VFS initialized\n");
 
-	vga_set_color(LIGHT_GREEN, BLACK);
-	kprintf("Setup complete!\n");
-	vga_set_color(WHITE, BLACK);
+	kprintf(OKAY "Initial setup complete!\n");
 
 #ifdef TEST_VFS_INITRD
-	kprintf("fs_readdir(\"/dev/initrd\")\n");
+	kprintf(INFO "fs_readdir(\"/dev/initrd\")\n");
 
 	struct fs_dirent dirent;
 	for (int i = 0; fs_readdir(&root, i, &dirent); i++)
 	{
-		kprintf("name: %s, inode: %d\n", dirent.name, dirent.inode);
+		kprintf(INFO "name: %s, inode: %d\n", dirent.name, dirent.inode);
 	}
 #endif
 
@@ -86,6 +84,8 @@
 
 	pci_load();
 
+	kprintf(OKAY "Loaded PCI devices\n");
+
 #ifdef TEST_THREADS
 	spawn_thread(other_thread, NULL);
 
@@ -101,7 +101,13 @@
 	test_ata_pio();
 #endif
 
-	ext2_mount(&root);
+#ifdef TEST_EXT2
+	if (ext2_valid_filesystem())
+	{
+		kprintf(INFO "Mounting EXT2 to /\n");
+		ext2_mount(&root);
+	}
+#endif
 
 	while (true)
 		asm("hlt");
diff --git a/src/kernel/multiboot.c b/src/kernel/multiboot.c
index d69f56c..3170472 100644
--- a/src/kernel/multiboot.c
+++ b/src/kernel/multiboot.c
@@ -14,7 +14,7 @@
 	TO_VIRT(mb.mods_addr, uint);
 	TO_VIRT(mb.cmdline, char);
 
-	kprintf("mb.mods_addr = %d, 0x%x\n", mb.mods_addr, mb.mods_addr);
+	kprintf(DEBUG "mb.mods_addr = %d, 0x%x\n", mb.mods_addr, mb.mods_addr);
 	kassert((size_t)mb.mods_addr >= 0xc0000000, "mb.mods_addr PHYSICAL");
 	for (int i = 0; i < mb.mods_count + 1; i++)
 	{
diff --git a/src/kernel/paging.c b/src/kernel/paging.c
index 536fdef..50ee738 100644
--- a/src/kernel/paging.c
+++ b/src/kernel/paging.c
@@ -51,7 +51,7 @@
 			{
 				/* found unused frame */
 				uint frame = i * BITS + j;
-				kprintf("first_free_frame returning %d\n", frame);
+				kprintf(DEBUG "first_free_frame returning %d\n", frame);
 //				kpanic("asdf");
 				return frame;
 			}
@@ -68,7 +68,7 @@
 		return; /* frame already allocated */
 
 	uint frame = first_free_frame();
-	//	kprintf("first_free_frame found %d\n", frame);
+	//	kprintf(DEBUG "first_free_frame found %d\n", frame);
 	set_frame(frame * 0x1000); /* mark as mapped */
 	*page_table_entry = frame | 1 | writable << 1 | user << 2;
 }
@@ -130,12 +130,12 @@
 	// Page number % pages per table
 	uint page = ((size_t)virt / 0x1000) % 1024;
 	uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
-	kprintf("table = 0x%x (virt)\n", table);
-	kprintf("dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
+	kprintf(DEBUG "table = 0x%x (virt)\n", table);
+	kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
 
 	alloc_frame(&table[page], false, false);
 
-	kprintf("alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
+	kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
 	return;
 }
 
@@ -183,6 +183,6 @@
 
 void page_fault(struct registers *regs)
 {
-	kprintf("Page fault! eip = %d\n", regs->eip);
+	kprintf(ERROR "Page fault! eip = %d\n", regs->eip);
 	kpanic("Page fault");
 }
diff --git a/src/kernel/pic.c b/src/kernel/pic.c
index a9a06ef..5d33213 100644
--- a/src/kernel/pic.c
+++ b/src/kernel/pic.c
@@ -33,7 +33,7 @@
 	if (interrupt_handlers[regs.interrupt_number])
 		interrupt_handlers[regs.interrupt_number](&regs);
 	else
-		kprintf("Unhandled hardware interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
+		kprintf(ERROR "Unhandled hardware interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
 }
 
 void isr_handler(struct registers regs)
@@ -41,7 +41,7 @@
 	if (interrupt_handlers[regs.interrupt_number])
 		interrupt_handlers[regs.interrupt_number](&regs);
 	else
-		kprintf("Unhandled interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
+		kprintf(ERROR "Unhandled interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
 }
 
 void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *))
diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c
index 6877e63..5a48b30 100644
--- a/src/kernel/syscall.c
+++ b/src/kernel/syscall.c
@@ -4,7 +4,7 @@
 
 void do_syscall(struct registers *regs)
 {
-	kprintf("Syscall executed: %d\n", regs->eax);
+	kprintf(INFO "Syscall executed: %d\n", regs->eax);
 }
 
 void init_syscall()
diff --git a/src/kernel/vfs_initrd.c b/src/kernel/vfs_initrd.c
index cad6d0b..bca0b50 100644
--- a/src/kernel/vfs_initrd.c
+++ b/src/kernel/vfs_initrd.c
@@ -81,7 +81,7 @@
 
 	if (h->magic != INITRD_MAGIC)
 	{
-		kprintf("initrd magic is wrong: %x should be %x\n", h->magic,
+		kprintf(ERROR "initrd magic is wrong: %x should be %x\n", h->magic,
 				INITRD_MAGIC);
 		kpanic("initrd magic");
 	}
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
index 49c2701..394d9c8 100644
--- a/src/kernel/vga.c
+++ b/src/kernel/vga.c
@@ -6,10 +6,15 @@
 static uint cursor_x = 0;
 static uint cursor_y = 0;
 
-static ushort color = WHITE;
+static uchar color = WHITE;
 
 static ushort *fb = (ushort *)PHYS_TO_VIRT(0xB8000);
 
+#define BUFFER_SIZE 16
+static char buffer[BUFFER_SIZE];
+static uint buffer_index = 0;
+static bool in_escape = false;
+
 static void move_cursor()
 {
 	ushort pos = cursor_y * 80 + cursor_x;
@@ -43,8 +48,72 @@
 	color = (bg << 4) | (fg & 0xf);
 }
 
+void got_escape()
+{
+	if (buffer[0] != '[')
+		return;
+
+	int c = parse_int(buffer+1);
+
+	static const char ansi_to_vga_colors[] =
+	{
+		[30] = BLACK,
+		RED,
+		GREEN,
+		LIGHT_BROWN,
+		BLUE,
+		MAGENTA,
+		CYAN,
+		WHITE,
+		[90] = LIGHT_GREY,
+		LIGHT_RED,
+		LIGHT_GREEN,
+		LIGHT_BROWN,
+		LIGHT_BLUE,
+		LIGHT_MAGENTA,
+		LIGHT_CYAN,
+		WHITE,
+	};
+
+	if (c == 0)
+	{
+		color = WHITE;
+	}
+	else if ((c >= 30 && c <= 37) || (c >= 90 && c <= 97))
+	{
+		color &= 0xf0;
+		color |= ansi_to_vga_colors[c];
+	}
+	else if ((c >= 40 && c <= 47) || (c >= 100 && c <= 107))
+	{
+		color &= 0x0f;
+		color |= ansi_to_vga_colors[c - 10] << 4;
+	}
+}
+
 void vga_put(char c)
 {
+	if (in_escape)
+	{
+		if (buffer_index >= BUFFER_SIZE || c == 'm')
+		{
+			// For now we are only supporting color escape sequences.
+			if (c == 'm')
+				got_escape();
+
+			// Escape sequence is too long, sorry. Failing silently.
+			in_escape = false;
+			buffer_index = 0;
+			memset(buffer, 0, sizeof(buffer));
+		}
+		else
+		{
+			buffer[buffer_index++] = c;
+		}
+
+		return;
+	}
+
 	switch (c)
 	{
 	case '\b':
@@ -60,6 +129,9 @@
 	case '\r':
 		cursor_x = 0;
 		break;
+	case 033:
+		in_escape = true;
+		break;
 	default:
 		fb[cursor_y * 80 + cursor_x] = c | (color << 8);
 		cursor_x++;