diff --git a/mentos/src/drivers/ata.c b/mentos/src/drivers/ata.c index 6ef86a4..17cc04d 100644 --- a/mentos/src/drivers/ata.c +++ b/mentos/src/drivers/ata.c @@ -8,10 +8,12 @@ #include "drivers/ata.h" -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[ATA ]" -/// Defines the debug level. -//#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "descriptor_tables/isr.h" #include "hardware/pic8259.h" @@ -1057,22 +1059,22 @@ int ata_initialize() type = ata_device_detect(&ata_primary_master); if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { printf(" Found %s device connected to primary master.\n", ata_get_device_type_str(type)); - pr_notice(" Found %s device connected to primary master.\n", ata_get_device_type_str(type)); + pr_info(" Found %s device connected to primary master.\n", ata_get_device_type_str(type)); } type = ata_device_detect(&ata_primary_slave); if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { printf(" Found %s device connected to primary slave.\n", ata_get_device_type_str(type)); - pr_notice(" Found %s device connected to primary slave.\n", ata_get_device_type_str(type)); + pr_info(" Found %s device connected to primary slave.\n", ata_get_device_type_str(type)); } type = ata_device_detect(&ata_secondary_master); if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { printf(" Found %s device connected to secondary master.\n", ata_get_device_type_str(type)); - pr_notice(" Found %s device connected to secondary master.\n", ata_get_device_type_str(type)); + pr_info(" Found %s device connected to secondary master.\n", ata_get_device_type_str(type)); } type = ata_device_detect(&ata_secondary_slave); if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { printf(" Found %s device connected to secondary slave.\n", ata_get_device_type_str(type)); - pr_notice(" Found %s device connected to secondary slave.\n", ata_get_device_type_str(type)); + pr_info(" Found %s device connected to secondary slave.\n", ata_get_device_type_str(type)); } return 0; } diff --git a/mentos/src/elf/elf.c b/mentos/src/elf/elf.c index a84cbfa..684ca2b 100644 --- a/mentos/src/elf/elf.c +++ b/mentos/src/elf/elf.c @@ -4,9 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[ELF ]" -#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "elf/elf.h" diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 1405685..94654ca 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -8,8 +8,12 @@ #include "fs/ext2.h" +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[EXT2 ]" -//#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "process/scheduler.h" #include "process/process.h" diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index 3fc59d2..4d2a546 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -4,9 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[PROCFS]" -#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "fs/procfs.h" #include "fs/vfs.h" @@ -16,15 +19,20 @@ #include "fcntl.h" #include "libgen.h" #include "assert.h" +#include "stdio.h" #include "time.h" /// Maximum length of name in PROCFS. #define PROCFS_NAME_MAX 255U /// Maximum number of files in PROCFS. -#define PROCFS_MAX_FILES 512U +#define PROCFS_MAX_FILES 1024U /// The magic number used to check if the procfs file is valid. #define PROCFS_MAGIC_NUMBER 0xBF +// ============================================================================ +// Data Structures +// ============================================================================ + /// @brief Information concerning a file. typedef struct procfs_file_t { /// Number used as delimiter, it must be set to 0xBF. @@ -33,10 +41,10 @@ typedef struct procfs_file_t { int inode; /// Flags. unsigned flags; + /// The file mask. + mode_t mask; /// The name of the file. char name[PROCFS_NAME_MAX]; - /// Associated files. - list_head files; /// User id of the file. uid_t uid; /// Group id of the file. @@ -49,115 +57,300 @@ typedef struct procfs_file_t { time_t ctime; /// Pointer to the associated proc_dir_entry_t. proc_dir_entry_t dir_entry; + /// Associated files. + list_head files; + /// List of procfs siblings. + list_head siblings; } procfs_file_t; /// @brief The details regarding the filesystem. /// @brief Contains the number of files inside the initrd filesystem. -static struct procfs_t { +typedef struct procfs_t { /// Number of files. unsigned int nfiles; /// List of headers. - procfs_file_t headers[PROCFS_MAX_FILES]; -} __attribute__((aligned(16))) fs_specs; + list_head files; + /// Cache for creating new `procfs_file_t`. + kmem_cache_t *procfs_cache; +} procfs_t; -static inline procfs_file_t *procfs_create_file(const char *path, unsigned flags); +procfs_t fs; -static inline int procfs_destroy_file(procfs_file_t *procfs_file); +// ============================================================================ +// Forward Declaration of Functions +// ============================================================================ -static inline vfs_file_t *procfs_create_file_struct(procfs_file_t *procfs_file); +static int procfs_mkdir(const char *path, mode_t mode); +static int procfs_rmdir(const char *path); +static int procfs_stat(const char *path, stat_t *stat); + +static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode); +static int procfs_unlink(const char *path); +static int procfs_close(vfs_file_t *file); +static ssize_t procfs_read(vfs_file_t *file, char *buffer, off_t offset, size_t nbyte); +static ssize_t procfs_write(vfs_file_t *file, const void *buffer, off_t offset, size_t nbyte); +static off_t procfs_lseek(vfs_file_t *file, off_t offset, int whence); +static int procfs_fstat(vfs_file_t *file, stat_t *stat); +static int procfs_ioctl(vfs_file_t *file, int request, void *data); +static int procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); + +// ============================================================================ +// Virtual FileSystem (VFS) Operaions +// ============================================================================ + +/// Filesystem general operations. +static vfs_sys_operations_t procfs_sys_operations = { + .mkdir_f = procfs_mkdir, + .rmdir_f = procfs_rmdir, + .stat_f = procfs_stat +}; + +/// Filesystem file operations. +static vfs_file_operations_t procfs_fs_operations = { + .open_f = procfs_open, + .unlink_f = procfs_unlink, + .close_f = procfs_close, + .read_f = procfs_read, + .write_f = procfs_write, + .lseek_f = procfs_lseek, + .stat_f = procfs_fstat, + .ioctl_f = procfs_ioctl, + .getdents_f = procfs_getdents +}; + +// ============================================================================ +// PROCFS Core Functions +// ============================================================================ + +/// @brief Checks if the file is a valid PROCFS file. +/// @param procfs_file the file to check. +/// @return true if valid, false otherwise. +static inline bool_t procfs_check_file(procfs_file_t *procfs_file) +{ + return (procfs_file && (procfs_file->magic == PROCFS_MAGIC_NUMBER)); +} + +/// @brief Returns the PROCFS file associated with the given list entry. +/// @param entry the entry to transform to PROCFS file. +/// @return a valid pointer to a PROCFS file, NULL otherwise. +static inline procfs_file_t *procfs_get_file(list_head *entry) +{ + procfs_file_t *procfs_file; + if (entry) + if (procfs_check_file((procfs_file = list_entry(entry, procfs_file_t, siblings)))) + return procfs_file; + return NULL; +} + +/// @brief Finds the PROCFS file at the given path. +/// @param path the path to the entry. +/// @return a pointer to the PROCFS file, NULL otherwise. +static inline procfs_file_t *procfs_find_entry_path(const char *path) +{ + procfs_file_t *procfs_file; + if (!list_head_empty(&fs.files)) { + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + procfs_file = procfs_get_file(it); + // Check its name. + if (procfs_file && !strcmp(procfs_file->name, path)) + return procfs_file; + } + } + return NULL; +} + +/// @brief Finds the PROCFS file with the given inode. +/// @param inode the inode we search. +/// @return a pointer to the PROCFS file, NULL otherwise. +static inline procfs_file_t *procfs_find_entry_inode(int inode) +{ + procfs_file_t *procfs_file; + if (!list_head_empty(&fs.files)) { + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + procfs_file = procfs_get_file(it); + // Check its inode. + if (procfs_file && (procfs_file->inode == inode)) { + return procfs_file; + } + } + } + return NULL; +} + +/// @brief Finds the inode associated with a PROCFS file at the given path. +/// @param path the path to the entry. +/// @return a valid inode, or -1 on failure. +static inline int procfs_find_inode(const char *path) +{ + procfs_file_t *procfs_file = procfs_find_entry_path(path); + if (procfs_file) + return procfs_file->inode; + return -1; +} static inline int procfs_get_free_inode() { - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - assert(fs_specs.headers[i].magic == PROCFS_MAGIC_NUMBER); - if (fs_specs.headers[i].inode == -1) { - return i; - } - } - return -1; -} - -static inline procfs_file_t *procfs_get_free_entry() -{ - int free_inode = procfs_get_free_inode(); - if (free_inode != -1) { - procfs_file_t *free_entry = &fs_specs.headers[free_inode]; - free_entry->inode = free_inode; - return free_entry; - } else { - pr_err("There are no more free inodes (%d/%d).\n", fs_specs.nfiles, PROCFS_MAX_FILES); - } - return NULL; -} - -static inline procfs_file_t *procfs_find_entry_path(const char *path) -{ - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - if (strcmp(fs_specs.headers[i].name, path) == 0) { - return &fs_specs.headers[i]; - } - } - return NULL; -} - -static inline procfs_file_t *procfs_find_entry_inode(int inode) -{ - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - if (fs_specs.headers[i].inode == inode) { - return &fs_specs.headers[i]; - } - } - return NULL; -} - -static inline int procfs_find_inode(const char *path) -{ - procfs_file_t *file = procfs_find_entry_path(path); - if (file) - return file->inode; + for (int inode = 1; inode < PROCFS_MAX_FILES; ++inode) + if (procfs_find_entry_inode(inode) == NULL) + return inode; return -1; } +/// @brief Checks if the PROCFS directory at the given path is empty. +/// @param path the path to the directory. +/// @return 0 if empty, 1 if not. static inline int procfs_check_if_empty(const char *path) { - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - procfs_file_t *entry = &fs_specs.headers[i]; - // There is nothing here. - if (entry->inode == -1) { - continue; - } - // It's the directory itself. - if (strcmp(path, entry->name) == 0) { - continue; - } - // Get the directory of the file. - char *filedir = dirname(entry->name); - // Check if directory path and file directory are the same. - if (strcmp(path, filedir) == 0) { - return 1; + procfs_file_t *procfs_file; + if (!list_head_empty(&fs.files)) { + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + procfs_file = procfs_get_file(it); + // Check if it a valid pointer. + if (procfs_file) { + // It's the directory itself. + if (!strcmp(path, procfs_file->name)) + continue; + // Get the directory of the file. + char *filedir = dirname(procfs_file->name); + // Check if directory path and file directory are the same. + if (filedir && !strcmp(path, filedir)) + return 1; + } } } return 0; } +/// @brief Creates a new PROCFS file. +/// @param path where the file resides. +/// @param flags the creation flags. +/// @return a pointer to the new PROCFS file, NULL otherwise. +static inline procfs_file_t *procfs_create_file(const char *path, unsigned flags) +{ + procfs_file_t *procfs_file = (procfs_file_t *)kmem_cache_alloc(fs.procfs_cache, GFP_KERNEL); + if (!procfs_file) { + pr_err("Failed to get free entry (%p).\n", procfs_file); + return NULL; + } + // Clean up the memory. + memset(procfs_file, 0, sizeof(procfs_file_t)); + // Initialize the magic number. + procfs_file->magic = PROCFS_MAGIC_NUMBER; + // Initialize the inode. + procfs_file->inode = procfs_get_free_inode(); + // Flags. + procfs_file->flags = flags; + // The name of the file. + strcpy(procfs_file->name, path); + // Associated files. + list_head_init(&procfs_file->files); + // List of all the PROCFS files. + list_head_init(&procfs_file->siblings); + // Add the file to the list of opened files. + list_head_add_tail(&procfs_file->siblings, &fs.files); + // Time of last access. + procfs_file->atime = sys_time(NULL); + // Time of last data modification. + procfs_file->mtime = procfs_file->atime; + // Time of last status change. + procfs_file->ctime = procfs_file->atime; + // Initialize the dir_entry. + procfs_file->dir_entry.name = basename(procfs_file->name); + procfs_file->dir_entry.data = NULL; + procfs_file->dir_entry.sys_operations = NULL; + procfs_file->dir_entry.fs_operations = NULL; + // Increase the number of files. + ++fs.nfiles; + pr_debug("procfs_create_file(%p) `%s`\n", procfs_file, path); + return procfs_file; +} + +/// @brief Destroyes the given PROCFS file. +/// @param procfs_file pointer to the PROCFS file to destroy. +/// @return 0 on success, 1 on failure. +static inline int procfs_destroy_file(procfs_file_t *procfs_file) +{ + if (!procfs_file) { + pr_err("Received a null entry (%p).\n", procfs_file); + return 1; + } + pr_debug("procfs_destroy_file(%p) `%s`\n", procfs_file, procfs_file->name); + // Remove the file from the list of opened files. + list_head_del(&procfs_file->siblings); + // Free the cache. + kmem_cache_free(procfs_file); + // Decrease the number of files. + --fs.nfiles; + return 0; +} + +/// @brief Creates a VFS file, from a PROCFS file. +/// @param procfs_file the PROCFS file. +/// @return a pointer to the newly create VFS file, NULL on failure. +static inline vfs_file_t *procfs_create_file_struct(procfs_file_t *procfs_file) +{ + if (!procfs_file) { + pr_err("procfs_create_file_struct(%p): Procfs file not valid!\n", procfs_file); + return NULL; + } + vfs_file_t *vfs_file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL); + if (!vfs_file) { + pr_err("procfs_create_file_struct(%p): Failed to allocate memory for VFS file!\n", procfs_file); + return NULL; + } + memset(vfs_file, 0, sizeof(vfs_file_t)); + strcpy(vfs_file->name, procfs_file->name); + vfs_file->device = &procfs_file->dir_entry; + vfs_file->ino = procfs_file->inode; + vfs_file->uid = 0; + vfs_file->gid = 0; + vfs_file->mask = S_IRUSR | S_IRGRP | S_IROTH; + vfs_file->length = 0; + vfs_file->flags = procfs_file->flags; + vfs_file->sys_operations = &procfs_sys_operations; + vfs_file->fs_operations = &procfs_fs_operations; + list_head_init(&vfs_file->siblings); + pr_debug("procfs_create_file_struct(%p): VFS file : %p\n", procfs_file, vfs_file); + return vfs_file; +} + +/// @brief Dumps on debugging output the PROCFS. static void dump_procfs() { - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - procfs_file_t *file = &fs_specs.headers[i]; - pr_debug("[%3d]ino:%3d, name:`%s`\n", i, file->inode, file->name); + procfs_file_t *file; + if (!list_head_empty(&fs.files)) { + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + file = procfs_get_file(it); + // Check if it a valid procfs file. + if (file) + pr_debug("[%3d] `%s`\n", file->inode, file->name); + } } } +/// @brief Initializes the procfs. static void procfs_init() { // Initialize the procfs. - memset(&fs_specs, 0, sizeof(struct procfs_t)); - for (int i = 0; i < PROCFS_MAX_FILES; ++i) { - fs_specs.headers[i].magic = PROCFS_MAGIC_NUMBER; - fs_specs.headers[i].inode = -1; - } + memset(&fs, 0, sizeof(struct procfs_t)); + // Initialize the cache. + fs.procfs_cache = KMEM_CREATE(procfs_file_t); + // Initialize the list of procfs files. + list_head_init(&fs.files); } +// ============================================================================ +// Virtual FileSystem (VFS) Functions +// ============================================================================ + /// @brief Creates a new directory. /// @param path The path to the new directory. /// @param mode The file mode. @@ -228,21 +421,57 @@ static int procfs_rmdir(const char *path) return 0; } +/// @brief Open the file at the given path and returns its file descriptor. +/// @param path The path to the file. +/// @param flags The flags used to determine the behavior of the function. +/// @param mode The mode with which we open the file. +/// @return The file descriptor of the opened file, otherwise returns -1. static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) { + // Get the parent path. + char *parent_path = dirname(path); + // Check if the directories before it exist. + if ((strcmp(parent_path, ".") != 0) && (strcmp(parent_path, "/") != 0)) { + procfs_file_t *parent_file = procfs_find_entry_path(parent_path); + if (parent_file == NULL) { + pr_err("Cannot find parent `%s`.\n", parent_path); + errno = ENOENT; + return NULL; + } + if (!bitmask_check(parent_file->flags, DT_DIR)) { + pr_err("Parent folder `%s` is not a directory.\n", parent_path); + errno = ENOTDIR; + return NULL; + } + } + // Find the entry. procfs_file_t *procfs_file = procfs_find_entry_path(path); if (procfs_file != NULL) { - // Check if it is a directory. - if (flags == (O_RDONLY | O_DIRECTORY)) { - if ((procfs_file->flags & DT_DIR) == 0) { - pr_err("Is not a directory `%s`...\n", path); + // Check if the user wants to create a file. + if (bitmask_check(flags, O_CREAT)) { + pr_err("Cannot create, it exists `%s`.\n", path); + errno = EEXIST; + return NULL; + } + // Check if the user wants to open a directory. + if (bitmask_check(flags, O_DIRECTORY)) { + // Check if the file is a directory. + if (!bitmask_check(procfs_file->flags, DT_DIR)) { + pr_err("Is not a directory `%s` but access requested involved a directory.\n", path); errno = ENOTDIR; return NULL; } + // Check if pathname refers to a directory and the access requested + // involved writing. + if (bitmask_check(flags, O_RDWR) || bitmask_check(flags, O_WRONLY)) { + pr_err("Is a directory `%s` but access requested involved writing.\n", path); + errno = EISDIR; + return NULL; + } // Create the associated file. vfs_file_t *vfs_file = procfs_create_file_struct(procfs_file); if (!vfs_file) { - pr_err("Cannot create vfs file for opening directory `%s`...\n", path); + pr_err("Cannot create vfs file for opening directory `%s`.\n", path); errno = ENFILE; return NULL; } @@ -251,15 +480,11 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) // Add the vfs_file to the list of associated files. list_head_add_tail(&vfs_file->siblings, &procfs_file->files); return vfs_file; - } else if ((procfs_file->flags & DT_DIR) != 0) { - pr_err("Is a directory `%s`...\n", path); - errno = EISDIR; - return NULL; } - // Check if the open has to create. - if (flags & O_CREAT) { - pr_err("Cannot create, it exists `%s`...\n", path); - errno = EEXIST; + // Check if the user did not want to open a directory, but it is. + if (bitmask_check(procfs_file->flags, DT_DIR)) { + pr_err("Is a directory `%s` but access requested did not involved a directory.\n", path); + errno = EISDIR; return NULL; } // Create the associated file. @@ -275,23 +500,10 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) list_head_add_tail(&vfs_file->siblings, &procfs_file->files); return vfs_file; } - if (flags & O_CREAT) { - // Check if the directories before it exist. - procfs_file_t *parent_file = NULL; - char *parent_path = dirname(path); - if ((strcmp(parent_path, ".") != 0) && (strcmp(parent_path, "/") != 0)) { - parent_file = procfs_find_entry_path(parent_path); - if (parent_file == NULL) { - pr_err("Cannot find parent `%s`...\n", parent_path); - errno = ENOENT; - return NULL; - } - if ((parent_file->flags & DT_DIR) == 0) { - pr_err("Parent `%s` the parent is not a directory...\n", parent_path); - errno = ENOTDIR; - return NULL; - } - } + // When both O_CREAT and O_DIRECTORY are specified in flags and the file + // specified by pathname does not exist, open() will create a regular file + // (i.e., O_DIRECTORY is ignored). + if (bitmask_check(flags, O_CREAT)) { // Create the new procfs file. procfs_file = procfs_create_file(path, DT_REG); if (!procfs_file) { @@ -308,12 +520,15 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) } // Add the vfs_file to the list of associated files. list_head_add_tail(&vfs_file->siblings, &procfs_file->files); + pr_debug("Created file `%s`.\n", path); return vfs_file; } errno = ENOENT; return NULL; } +/// @brief Closes the given file. +/// @param file The file structure. static int procfs_close(vfs_file_t *file) { assert(file && "Received null file."); @@ -357,6 +572,12 @@ static inline int procfs_unlink(const char *path) return 0; } +/// @brief Reads from the file identified by the file descriptor. +/// @param file The file. +/// @param buffer Buffer where the read content must be placed. +/// @param offset Offset from which we start reading from the file. +/// @param nbyte The number of bytes to read. +/// @return The number of red bytes. static ssize_t procfs_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { if (file) { @@ -368,6 +589,12 @@ static ssize_t procfs_read(vfs_file_t *file, char *buf, off_t offset, size_t nby return -ENOSYS; } +/// @brief Writes the given content inside the file. +/// @param file The file descriptor of the file. +/// @param buffer The content to write. +/// @param offset Offset from which we start writing in the file. +/// @param nbyte The number of bytes to write. +/// @return The number of written bytes. static ssize_t procfs_write(vfs_file_t *file, const void *buf, off_t offset, size_t nbyte) { if (file) { @@ -379,6 +606,35 @@ static ssize_t procfs_write(vfs_file_t *file, const void *buf, off_t offset, siz return -ENOSYS; } +/// @brief Repositions the file offset inside a file. +/// @param file the file we are working with. +/// @param offset the offest to use for the operation. +/// @param whence the type of operation. +/// @return Upon successful completion, returns the resulting offset +/// location as measured in bytes from the beginning of the file. On +/// error, the value (off_t) -1 is returned and errno is set to +/// indicate the error. +off_t procfs_lseek(vfs_file_t *file, off_t offset, int whence) +{ + if (file == NULL) { + pr_err("Received a NULL file.\n"); + return -ENOSYS; + } + procfs_file_t *procfs_file = procfs_find_entry_inode(file->ino); + if (procfs_file == NULL) { + pr_err("There is no PROCFS fiel associated with the VFS file.\n"); + return -ENOSYS; + } + if (procfs_file->dir_entry.fs_operations) + if (procfs_file->dir_entry.fs_operations->lseek_f) + return procfs_file->dir_entry.fs_operations->lseek_f(file, offset, whence); + return -EINVAL; +} + +/// @brief Saves the information concerning the file. +/// @param inode The inode containing the data. +/// @param stat The structure where the information are stored. +/// @return 0 if success. static int __procfs_stat(procfs_file_t *file, stat_t *stat) { stat->st_uid = file->uid; @@ -463,156 +719,69 @@ static inline int procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t written = 0; off_t current = 0; char *parent = NULL; - for (off_t it = 0; (it < PROCFS_MAX_FILES) && (written < count); ++it) { - procfs_file_t *entry = &fs_specs.headers[it]; - if (entry->inode == -1) { - continue; + procfs_file_t *entry; + if (!list_head_empty(&fs.files)) { + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + entry = procfs_get_file(it); + // Check if it a valid procfs file. + if (!entry) + continue; + + // If the entry is the directory itself, skip. + if (strcmp(direntry->name, entry->name) == 0) { + continue; + } + // Get the parent directory. + parent = dirname(entry->name); + // Check if the entry is inside the directory. + if (strcmp(direntry->name, parent) != 0) { + continue; + } + // Skip if already provided. + if (current++ < doff) { + continue; + } + if (*(entry->name + len) == '/') + ++len; + // Write on current dirp. + dirp->d_ino = entry->inode; + dirp->d_type = entry->flags; + strcpy(dirp->d_name, entry->name + len); + dirp->d_off = sizeof(dirent_t); + dirp->d_reclen = sizeof(dirent_t); + // Increment the written counter. + written += sizeof(dirent_t); + // Move to next writing position. + dirp += 1; + + if (written >= count) + break; } - // If the entry is the directory itself, skip. - if (strcmp(direntry->name, entry->name) == 0) { - continue; - } - // Get the parent directory. - parent = dirname(entry->name); - // Check if the entry is inside the directory. - if (strcmp(direntry->name, parent) != 0) { - continue; - } - // Skip if already provided. - if (current++ < doff) { - continue; - } - if (*(entry->name + len) == '/') - ++len; - // Write on current dirp. - dirp->d_ino = it; - dirp->d_type = entry->flags; - strcpy(dirp->d_name, entry->name + len); - dirp->d_off = sizeof(dirent_t); - dirp->d_reclen = sizeof(dirent_t); - // Increment the written counter. - written += sizeof(dirent_t); - // Move to next writing position. - dirp += 1; } return written; } -/// Filesystem general operations. -static vfs_sys_operations_t procfs_sys_operations = { - .mkdir_f = procfs_mkdir, - .rmdir_f = procfs_rmdir, - .stat_f = procfs_stat -}; - -/// Filesystem file operations. -static vfs_file_operations_t procfs_fs_operations = { - .open_f = procfs_open, - .unlink_f = procfs_unlink, - .close_f = procfs_close, - .read_f = procfs_read, - .write_f = procfs_write, - .lseek_f = NULL, - .stat_f = procfs_fstat, - .ioctl_f = procfs_ioctl, - .getdents_f = procfs_getdents -}; - -static inline procfs_file_t *procfs_create_file(const char *path, unsigned flags) +/// @brief Mounts the block device as an EXT2 filesystem. +/// @param block_device the block device formatted as EXT2. +/// @return the VFS root node of the EXT2 filesystem. +static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) { - procfs_file_t *file = procfs_get_free_entry(); - if (!file) { - pr_err("Failed to get free entry (%p).\n", file); - return NULL; - } - // Number used as delimiter, it must be set to 0xBF. - assert(file->magic == PROCFS_MAGIC_NUMBER); - // The file inode. - assert(file->inode != -1); - // Flags. - file->flags = flags; - // The name of the file. - strcpy(file->name, path); - // Associated files. - list_head_init(&file->files); - // Time of last access. - file->atime = sys_time(NULL); - // Time of last data modification. - file->mtime = file->atime; - // Time of last status change. - file->ctime = file->atime; - // Initialize the dir_entry. - file->dir_entry.name = basename(file->name); - file->dir_entry.data = NULL; - file->dir_entry.sys_operations = NULL; - file->dir_entry.fs_operations = NULL; - // Increase the number of files. - ++fs_specs.nfiles; - - pr_debug("procfs_create_file(%s): PROCFS file : %p\n", path, file); - - return file; + return NULL; } -static inline int procfs_destroy_file(procfs_file_t *procfs_file) -{ - if (!procfs_file) { - pr_err("Received a null entry (%p).\n", procfs_file); - return 1; - } - // Check the number used as delimiter, it must be set to 0xBF. - assert(procfs_file->magic == PROCFS_MAGIC_NUMBER); - - // Reset the inode. - procfs_file->inode = -1; - // Reset the flags. - procfs_file->flags = 0; - // Reset the name of the file. - memset(procfs_file->name, 0, PROCFS_NAME_MAX); - // Reset the list of associated files. - list_head_init(&procfs_file->files); - // Reset the time of last access. - procfs_file->atime = sys_time(NULL); - // Reset the time of last data modification. - procfs_file->mtime = procfs_file->atime; - // Reset the time of last status change. - procfs_file->ctime = procfs_file->atime; - - // Decrease the number of files. - --fs_specs.nfiles; - return 0; -} - -static inline vfs_file_t *procfs_create_file_struct(procfs_file_t *procfs_file) -{ - if (!procfs_file) { - pr_err("procfs_create_file_struct(%p): Procfs file not valid!\n", procfs_file); - return NULL; - } - vfs_file_t *file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL); - if (!file) { - pr_err("procfs_create_file_struct(%p): Failed to allocate memory for VFS file!\n", procfs_file); - return NULL; - } - memset(file, 0, sizeof(vfs_file_t)); - - strcpy(file->name, procfs_file->name); - file->device = &procfs_file->dir_entry; - file->ino = procfs_file->inode; - file->uid = 0; - file->gid = 0; - file->mask = S_IRUSR | S_IRGRP | S_IROTH; - file->length = 0; - file->flags = procfs_file->flags; - file->sys_operations = &procfs_sys_operations; - file->fs_operations = &procfs_fs_operations; - list_head_init(&file->siblings); - pr_debug("procfs_create_file_struct(%p): VFS file : %p\n", procfs_file, file); - return file; -} +// ============================================================================ +// Initialization Functions +// ============================================================================ +/// @brief Mounts the filesystem at the given path. +/// @param path the path where we want to mount a procfs. +/// @param device we expect it to be NULL. +/// @return a pointer to the root VFS file. static vfs_file_t *procfs_mount_callback(const char *path, const char *device) { + pr_debug("procfs_mount_callback(%s, %s)\n", path, device); // Create the new procfs file. procfs_file_t *procfs_file = procfs_create_file(path, DT_DIR); assert(procfs_file && "Failed to create procfs_file."); @@ -648,6 +817,10 @@ int procfs_cleanup_module() return 0; } +// ============================================================================ +// Publically available functions +// ============================================================================ + proc_dir_entry_t *proc_dir_entry_get(const char *name, proc_dir_entry_t *parent) { char entry_path[PATH_MAX]; diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 8e8855c..5243eba 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -6,8 +6,12 @@ #include "fs/vfs.h" +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[VFS ]" -#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "process/scheduler.h" #include "klib/spinlock.h" diff --git a/mentos/src/mem/buddysystem.c b/mentos/src/mem/buddysystem.c index cf229e4..0ebdd24 100644 --- a/mentos/src/mem/buddysystem.c +++ b/mentos/src/mem/buddysystem.c @@ -4,9 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[BUDDY ]" -#define __DEBUG_LEVEL__ 100 +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG #include "mem/buddysystem.h" #include "mem/paging.h" diff --git a/mentos/src/mem/kheap.c b/mentos/src/mem/kheap.c index 8a6a91f..29ba641 100644 --- a/mentos/src/mem/kheap.c +++ b/mentos/src/mem/kheap.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[KHEAP ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "mem/kheap.h" #include "math.h" diff --git a/mentos/src/mem/paging.c b/mentos/src/mem/paging.c index c27a292..cc438e6 100644 --- a/mentos/src/mem/paging.c +++ b/mentos/src/mem/paging.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[PAGING]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "mem/paging.h" #include "descriptor_tables/isr.h" diff --git a/mentos/src/mem/slab.c b/mentos/src/mem/slab.c index b530c63..8545100 100644 --- a/mentos/src/mem/slab.c +++ b/mentos/src/mem/slab.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[SLAB ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "mem/zone_allocator.h" #include "mem/paging.h" diff --git a/mentos/src/mem/vmem_map.c b/mentos/src/mem/vmem_map.c index 2bed3cc..8b6e68d 100644 --- a/mentos/src/mem/vmem_map.c +++ b/mentos/src/mem/vmem_map.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[VMEM ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "mem/vmem_map.h" #include "string.h" diff --git a/mentos/src/mem/zone_allocator.c b/mentos/src/mem/zone_allocator.c index 22efb92..87b747d 100644 --- a/mentos/src/mem/zone_allocator.c +++ b/mentos/src/mem/zone_allocator.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[PMM ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "mem/zone_allocator.h" #include "mem/buddysystem.h" diff --git a/mentos/src/multiboot.c b/mentos/src/multiboot.c index 245b555..d55a2ba 100644 --- a/mentos/src/multiboot.c +++ b/mentos/src/multiboot.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Set the debug level to 0. -#define __DEBUG_LEVEL__ 0 +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. +#define __DEBUG_HEADER__ "[BOOT ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "multiboot.h" #include "kernel.h" diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index c313c41..b18f38d 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -6,7 +6,12 @@ #include "sys/kernel_levels.h" -#define __DEBUG_LEVEL__ 100 +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. +#define __DEBUG_HEADER__ "[PROC ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "process/process.h" #include "process/scheduler.h" @@ -340,12 +345,12 @@ void sys_chdir(char const *path) char absolute_path[PATH_MAX]; realpath(path, absolute_path); // Check that the directory exists. - vfs_file_t *dir = vfs_open(absolute_path, O_RDONLY, S_IXUSR); + vfs_file_t *dir = vfs_open(absolute_path, O_RDONLY | O_DIRECTORY, S_IXUSR); if (dir != NULL) { pr_debug("Success `%s` -> `%s` -> `%s`\n", path, absolute_path, dir->name); strcpy(current_process->cwd, absolute_path); vfs_close(dir); - }else{ + } else { pr_debug("Failed `%s` -> `%s` -> `NULL`\n", path, absolute_path); } } diff --git a/mentos/src/process/scheduler.c b/mentos/src/process/scheduler.c index 9e874f4..1a1fae4 100644 --- a/mentos/src/process/scheduler.c +++ b/mentos/src/process/scheduler.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[SCHED ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "assert.h" #include "strerror.h" diff --git a/mentos/src/process/wait.c b/mentos/src/process/wait.c index 9b37b82..a49bda5 100644 --- a/mentos/src/process/wait.c +++ b/mentos/src/process/wait.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[WAIT ]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "process/wait.h" diff --git a/mentos/src/system/signal.c b/mentos/src/system/signal.c index a1efa81..3cd8155 100644 --- a/mentos/src/system/signal.c +++ b/mentos/src/system/signal.c @@ -4,8 +4,12 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Change the header. +// Include the kernel log levels. +#include "sys/kernel_levels.h" +// Change the header. #define __DEBUG_HEADER__ "[SIGNAL]" +// Set the log level. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE #include "system/signal.h" #include "process/wait.h" diff --git a/programs/shell.c b/programs/shell.c index 77cf2d5..269d6d2 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -326,7 +326,7 @@ static int __cd(int argc, char *argv[]) return 1; } } - int fd = open(path, O_RDONLY | O_DIRECTORY, 0); + int fd = open(path, O_RDONLY | O_DIRECTORY, S_IXUSR); if (fd == -1) { printf("cd: %s: %s\n\n", argv[0], strerror(errno), path); return 1;