diff --git a/libc/inc/stdio.h b/libc/inc/stdio.h index 14a2a49..460836a 100644 --- a/libc/inc/stdio.h +++ b/libc/inc/stdio.h @@ -30,7 +30,7 @@ void putchar(int character); /// @brief Writes the string pointed by str to the standard output (stdout) /// and appends a newline character. /// @param str The string to send to stdout. -void puts(char *str); +void puts(const char *str); /// @brief Returns the next character from the standard input (stdin). /// @return The character received from stdin. @@ -124,3 +124,7 @@ int sscanf(const char *str, const char *fmt, ...); /// argument list successfully filled. EOF otherwise. int fscanf(int fd, const char *fmt, ...); #endif + +/// @brief Prints a system error message. +/// @param s the message we prepend to the actual error message. +void perror(const char *s); \ No newline at end of file diff --git a/libc/inc/stdlib.h b/libc/inc/stdlib.h index 8c6ebfd..76fe92c 100644 --- a/libc/inc/stdlib.h +++ b/libc/inc/stdlib.h @@ -7,6 +7,9 @@ #include "stddef.h" +#define EXIT_SUCCESS 0 ///< Successful execution of a program. +#define EXIT_FAILURE 1 ///< Unsuccessful execution of a program. + /// @brief Returns the number of usable bytes in the block pointed to by ptr. /// @param ptr The pointer for which we want to retrieve the usable size. /// @return The number of usable bytes in the block of allocated memory diff --git a/libc/inc/sys/unistd.h b/libc/inc/sys/unistd.h index fdebcb7..55be6e3 100644 --- a/libc/inc/sys/unistd.h +++ b/libc/inc/sys/unistd.h @@ -25,7 +25,7 @@ ssize_t read(int fd, void *buf, size_t nbytes); /// @param buf The buffer collecting data to written. /// @param nbytes The number of bytes to write. /// @return The number of written bytes. -ssize_t write(int fd, void *buf, size_t nbytes); +ssize_t write(int fd, const void *buf, size_t nbytes); /// @brief Opens the file specified by pathname. /// @param pathname A pathname for a file. @@ -238,7 +238,7 @@ int fchdir(int fd); /// @return On success, the number of bytes read is returned. On end of /// directory, 0 is returned. On error, -1 is returned, and errno is set /// appropriately. -int getdents(int fd, dirent_t *dirp, unsigned int count); +ssize_t getdents(int fd, dirent_t *dirp, unsigned int count); /// @brief Send signal to calling thread after desired seconds. /// @param seconds the amount of seconds. diff --git a/libc/src/stdio.c b/libc/src/stdio.c index 3250669..7cb6802 100644 --- a/libc/src/stdio.c +++ b/libc/src/stdio.c @@ -9,13 +9,14 @@ #include "string.h" #include "stdbool.h" #include "sys/unistd.h" +#include "strerror.h" void putchar(int character) { write(STDOUT_FILENO, &character, 1); } -void puts(char *str) +void puts(const char *str) { write(STDOUT_FILENO, str, strlen(str)); } @@ -206,3 +207,13 @@ char *fgets(char *buf, int n, int fd) return NULL; return (p); } + +void perror(const char *s) +{ + if (s) { + puts(s); + putchar(':'); + putchar(' '); + } + puts(strerror(errno)); +} \ No newline at end of file diff --git a/libc/src/unistd/getdents.c b/libc/src/unistd/getdents.c index 560ccef..e490c53 100644 --- a/libc/src/unistd/getdents.c +++ b/libc/src/unistd/getdents.c @@ -8,4 +8,4 @@ #include "sys/errno.h" -_syscall3(int, getdents, int, fd, dirent_t *, dirp, unsigned int, count) +_syscall3(ssize_t, getdents, int, fd, dirent_t *, dirp, unsigned int, count) diff --git a/libc/src/unistd/write.c b/libc/src/unistd/write.c index 2e553c5..e7bf2cf 100644 --- a/libc/src/unistd/write.c +++ b/libc/src/unistd/write.c @@ -7,4 +7,4 @@ #include "system/syscall_types.h" #include "sys/errno.h" -_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes) +_syscall3(ssize_t, write, int, fd, const void *, buf, size_t, nbytes) diff --git a/mentos/inc/fs/vfs.h b/mentos/inc/fs/vfs.h index c080d83..6258b7b 100644 --- a/mentos/inc/fs/vfs.h +++ b/mentos/inc/fs/vfs.h @@ -64,7 +64,7 @@ ssize_t vfs_read(vfs_file_t *file, void *buf, size_t offset, size_t nbytes); /// @param offset The offset from which the function starts to write. /// @param nbytes The number of bytes to write. /// @return The number of written characters. -ssize_t vfs_write(vfs_file_t *file, void *buf, size_t offset, size_t nbytes); +ssize_t vfs_write(vfs_file_t *file, const void *buf, size_t offset, size_t nbytes); /// @brief Repositions the file offset inside a file. /// @param file The file for which we reposition the offest. @@ -84,7 +84,7 @@ off_t vfs_lseek(vfs_file_t *file, off_t offset, int whence); /// @return On success, the number of bytes read is returned. On end of /// directory, 0 is returned. On error, -1 is returned, and errno is set /// appropriately. -int vfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t off, size_t count); +ssize_t vfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t off, size_t count); /// @brief Perform the I/O control operation specified by REQUEST on FD. /// One argument may follow; its presence and type depend on REQUEST. diff --git a/mentos/inc/fs/vfs_types.h b/mentos/inc/fs/vfs_types.h index e06f47e..1e0057e 100644 --- a/mentos/inc/fs/vfs_types.h +++ b/mentos/inc/fs/vfs_types.h @@ -25,7 +25,7 @@ typedef int (*vfs_rmdir_callback)(const char *); /// Function used to open a file (or directory). typedef vfs_file_t *(*vfs_creat_callback)(const char *, mode_t); /// Function used to read the entries of a directory. -typedef int (*vfs_getdents_callback)(vfs_file_t *, dirent_t *, off_t, size_t); +typedef ssize_t (*vfs_getdents_callback)(vfs_file_t *, dirent_t *, off_t, size_t); /// Function used to open a file (or directory). typedef vfs_file_t *(*vfs_open_callback)(const char *, int, mode_t); /// Function used to remove a file. diff --git a/mentos/inc/system/syscall.h b/mentos/inc/system/syscall.h index f989b7d..a1e7778 100644 --- a/mentos/inc/system/syscall.h +++ b/mentos/inc/system/syscall.h @@ -38,7 +38,7 @@ ssize_t sys_read(int fd, void *buf, size_t nbytes); /// @param buf The buffer collecting data to written. /// @param nbytes The number of bytes to write. /// @return The number of written bytes. -ssize_t sys_write(int fd, void *buf, size_t nbytes); +ssize_t sys_write(int fd, const void *buf, size_t nbytes); /// @brief Repositions the file offset inside a file. /// @param fd The file descriptor of the file. @@ -225,7 +225,7 @@ int sys_creat(const char *path, mode_t mode); /// @return On success, the number of bytes read is returned. On end of /// directory, 0 is returned. On error, -1 is returned, and errno is set /// appropriately. -int sys_getdents(int fd, dirent_t *dirp, unsigned int count); +ssize_t sys_getdents(int fd, dirent_t *dirp, unsigned int count); /// @brief Returns the current time. /// @param time Where the time should be stored. diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 7361eb8..a597248 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -377,7 +377,7 @@ static ssize_t ext2_write(vfs_file_t *file, const void *buffer, off_t offset, si static off_t ext2_lseek(vfs_file_t *file, off_t offset, int whence); static int ext2_fstat(vfs_file_t *file, stat_t *stat); static int ext2_ioctl(vfs_file_t *file, int request, void *data); -static int ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); +static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); static int ext2_mkdir(const char *path, mode_t mode); static int ext2_rmdir(const char *path); @@ -2640,7 +2640,7 @@ static int ext2_ioctl(vfs_file_t *file, int request, void *data) /// @param doff The offset inside the buffer where the data should be written. /// @param count The maximum length of the buffer. /// @return The number of written bytes in the buffer. -static int ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count) +static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count) { pr_debug("ext2_getdents(%s, %p, %d, %d)\n", file->name, dirp, doff, count); // Get the filesystem. @@ -2655,7 +2655,8 @@ static int ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t co pr_err("Failed to read the inode (%d).\n", file->ino); return -ENOENT; } - uint32_t current = 0, written = 0; + uint32_t current = 0; + ssize_t written = 0; // Allocate the cache. uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); // Clean the cache. diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index a120da7..8d1e54a 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -90,7 +90,7 @@ static ssize_t procfs_write(vfs_file_t *file, const void *buffer, off_t offset, 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); +static ssize_t procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); // ============================================================================ // Virtual FileSystem (VFS) Operaions @@ -691,63 +691,71 @@ static int procfs_ioctl(vfs_file_t *file, int request, void *data) /// @param doff The offset inside the buffer where the data should be written. /// @param count The maximum length of the buffer. /// @return The number of written bytes in the buffer. -static inline int procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count) +static inline ssize_t procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count) { if (!file || !dirp) return -1; + // Check if the size of the buffer is big enough to hold the data about the + // directory entry. + if (count < sizeof(dirent_t)) + return -1; + // If there are no file, stop right here. + if (list_head_empty(&fs.files)) + return 0; + // Find the directory entry. procfs_file_t *direntry = procfs_find_entry_inode(file->ino); if (direntry == NULL) { return -ENOENT; } + // Check if it is a directory. if ((direntry->flags & DT_DIR) == 0) return -ENOTDIR; + // Clear the buffer. memset(dirp, 0, count); + // Initialize, the length of the directory name. int len = strlen(direntry->name); - size_t written = 0; - off_t current = 0; + ssize_t written_size = 0; + off_t iterated_size = 0; char *parent = NULL; - 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; + // Iterate the filesystem files. + list_for_each_decl(it, &fs.files) + { + // Get the file structure. + procfs_file_t *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)) + continue; + // Get the parent directory. + parent = dirname(entry->name); + // Check if the parent of the entry is the directory we are iterating. + if (strcmp(direntry->name, parent)) + continue; + // Advance the size we just iterated. + iterated_size += sizeof(dirent_t); + // Check if the iterated size is still below the offset. + if (iterated_size < doff) { + continue; } + // Check if the last character of the entry is a slash. + 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_size += sizeof(dirent_t); + // Move to next writing position. + ++dirp; + if (written_size >= count) + break; } - return written; + return written_size; } /// @brief Mounts the block device as an EXT2 filesystem. diff --git a/mentos/src/fs/read_write.c b/mentos/src/fs/read_write.c index 3101fdf..ad0a7b4 100644 --- a/mentos/src/fs/read_write.c +++ b/mentos/src/fs/read_write.c @@ -46,7 +46,7 @@ ssize_t sys_read(int fd, void *buf, size_t nbytes) return read; } -ssize_t sys_write(int fd, void *buf, size_t nbytes) +ssize_t sys_write(int fd, const void *buf, size_t nbytes) { // Get the current task. task_struct *task = scheduler_get_current_process(); diff --git a/mentos/src/fs/readdir.c b/mentos/src/fs/readdir.c index ee5f5a0..430cb1f 100644 --- a/mentos/src/fs/readdir.c +++ b/mentos/src/fs/readdir.c @@ -11,45 +11,40 @@ #include "stdio.h" #include "fs/vfs.h" #include "string.h" +#include "assert.h" -int sys_getdents(int fd, dirent_t *dirp, unsigned int count) +ssize_t sys_getdents(int fd, dirent_t *dirp, unsigned int count) { if (dirp == NULL) { printf("getdents: cannot read directory :" "Directory pointer is not valid\n"); return 0; } - // Get the current task. - task_struct *task = scheduler_get_current_process(); - + // Get the current process. + task_struct *current_process = scheduler_get_current_process(); + // Check the current task. + assert(current_process && "There is no current process!"); // Check the current FD. - if (fd < 0 || fd >= task->max_fd) { + if ((fd < 0) || (fd >= current_process->max_fd)) { return -EMFILE; } - - // Get the file descriptor. - vfs_file_descriptor_t *vfd = &task->fd_list[fd]; - - // Check the permissions. + // Get the process-specific file descriptor. + vfs_file_descriptor_t *process_fd = ¤t_process->fd_list[fd]; #if 0 - if (!(task->fd_list[fd].flags_mask & O_RDONLY)) { + // Check the permissions. + if (!(current_process->fd_list[fd].flags_mask & O_RDONLY)) { return -EROFS; } #endif - - // Get the file. - vfs_file_t *file = vfd->file_struct; + // Get the associated file. + vfs_file_t *file = process_fd->file_struct; if (file == NULL) { return -ENOSYS; } - // Clean the buffer. - memset(dirp, 0, count); - // Perform the read. - int actual_read = vfs_getdents(file, dirp, vfd->file_struct->f_pos, count); - - // Update the offset. + ssize_t actual_read = vfs_getdents(file, dirp, process_fd->file_struct->f_pos, count); + // Update the offset, only if the value the function returns is positive. if (actual_read > 0) - vfd->file_struct->f_pos += actual_read; + process_fd->file_struct->f_pos += actual_read; return actual_read; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index b799da2..1ac79ac 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -172,7 +172,7 @@ ssize_t vfs_read(vfs_file_t *file, void *buf, size_t offset, size_t nbytes) return file->fs_operations->read_f(file, buf, offset, nbytes); } -ssize_t vfs_write(vfs_file_t *file, void *buf, size_t offset, size_t nbytes) +ssize_t vfs_write(vfs_file_t *file, const void *buf, size_t offset, size_t nbytes) { if (file->fs_operations->write_f == NULL) { pr_err("No WRITE function found for the current filesystem.\n"); @@ -190,7 +190,7 @@ off_t vfs_lseek(vfs_file_t *file, off_t offset, int whence) return file->fs_operations->lseek_f(file, offset, whence); } -int vfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t off, size_t count) +ssize_t vfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t off, size_t count) { if (file->fs_operations->getdents_f == NULL) { pr_err("No GETDENTS function found for the current filesystem.\n"); diff --git a/programs/ps.c b/programs/ps.c index ac19d55..efbcc6b 100644 --- a/programs/ps.c +++ b/programs/ps.c @@ -7,21 +7,19 @@ #include #include #include -#include #include +#include #define FORMAT_S "%5s %5s %6s %s\n" #define FORMAT "%5d %5d %6c %s\n" -static inline void __iterate_proc_dirs(int fd) +static inline void __iterate_proc_dirs(int proc_fd) { char absolute_path[PATH_MAX] = "/proc/"; // Holds the file descriptor of the stat file. int stat_fd; // Buffer used to read the stat file. char stat_buffer[BUFSIZ] = { 0 }; - // Holds the number of bytes read from stat file. - ssize_t ret; // Variables used to read the stat file. // (1) pid %d // (2) comm %s @@ -33,7 +31,20 @@ static inline void __iterate_proc_dirs(int fd) pid_t ppid; // The directory entry. dirent_t dent; - while (getdents(fd, &dent, sizeof(dirent_t)) == sizeof(dirent_t)) { + // Holds the number of bytes read. + ssize_t read_bytes; + do { + // Read an entry. + read_bytes = getdents(proc_fd, &dent, sizeof(dirent_t)); + // We reached the end of the folder. + if (read_bytes == 0) { + break; + } + // We encountered an error. + if (read_bytes == -1) { + perror("Failed to read entry in `/proc` folder"); + exit(EXIT_FAILURE); + } // Skip non-directories. if (dent.d_type != DT_DIR) continue; @@ -42,14 +53,20 @@ static inline void __iterate_proc_dirs(int fd) strcat(absolute_path, "/stat"); // Open the `/proc//stat` file. if ((stat_fd = open(absolute_path, O_RDONLY, 0)) == -1) { - printf("Failed to open `%s`\n", absolute_path); + printf("Failed to open `%s`: ", absolute_path); + perror(NULL); + putchar('\n'); continue; } // Reset the stat buffer. memset(stat_buffer, 0, BUFSIZ); // Read the content of the stat file. - if ((ret = read(stat_fd, stat_buffer, BUFSIZ)) <= 0) { - printf("Cannot read `%s`\n", absolute_path); + read_bytes = read(stat_fd, stat_buffer, BUFSIZ); + // Check if the read failed. + if (read_bytes <= 0) { + printf("Cannot read `%s`", absolute_path); + perror(NULL); + putchar('\n'); close(stat_fd); continue; } @@ -61,14 +78,15 @@ static inline void __iterate_proc_dirs(int fd) printf(FORMAT, pid, ppid, state, comm); // Closing stat FD. close(stat_fd); - } + } while (1); } int main(int argc, char **argv) { int fd = open("/proc", O_RDONLY | O_DIRECTORY, 0); if (fd == -1) { - printf("ps: cannot access '/proc': %s\n\n", strerror(errno)); + perror("ps: cannot access '/proc' folder"); + return EXIT_FAILURE; } else { printf(FORMAT_S, "PID", "PPID", "STATUS", "CMD"); __iterate_proc_dirs(fd); @@ -124,5 +142,5 @@ int main(int argc, char **argv) } close(fd_self); #endif - return 0; + return EXIT_SUCCESS; }