diff --git a/CMakeLists.txt b/CMakeLists.txt index 00e58b02..6fa45ac6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,7 @@ set(EMULATOR_FLAGS ${EMULATOR_FLAGS} -drive file=${CMAKE_BINARY_DIR}/rootfs.img, # This first target runs the emualtor passing the kernel binary file. add_custom_target( qemu + COMMAND test -e ${CMAKE_BINARY_DIR}/rootfs.img || ${CMAKE_COMMAND} -E cmake_echo_color --red "No filesystem file detected, you need to run: make filesystem" COMMAND ${EMULATOR} ${EMULATOR_FLAGS} -kernel ${CMAKE_BINARY_DIR}/mentos/kernel-bootloader.bin DEPENDS kernel-bootloader.bin ) @@ -174,6 +175,7 @@ add_custom_target( # debug mode, and pause it up until a debugger connects to it. add_custom_target( qemu-gdb + COMMAND test -e ${CMAKE_BINARY_DIR}/rootfs.img || ${CMAKE_COMMAND} -E cmake_echo_color --red "No filesystem file detected, you need to run: make filesystem" COMMAND echo "\n\n" COMMAND echo "Now, QEMU has loaded the kernel, and it is waiting that you\n" COMMAND echo "remotely connect to it. To start debugging, open a new shell\n" diff --git a/files/etc/issue b/files/etc/issue new file mode 100644 index 00000000..e69de29b diff --git a/files/etc/motd b/files/etc/motd new file mode 100644 index 00000000..e69de29b diff --git a/files/usr/share/man/ls.man b/files/usr/share/man/ls.man new file mode 100644 index 00000000..4eb9949a --- /dev/null +++ b/files/usr/share/man/ls.man @@ -0,0 +1,14 @@ +NAME + ls - list directory contents + +SYNOPSIS + ls [OPTIONS] [FILE/FOLDER] + +DESCRIPTION + List information about the given file, or the files contained in the given + folder. If not argument is provided it will list information about files + inside the current folder. + +OPTIONS + -a : list all entries. + -l : show the entries as a detailed list. diff --git a/libc/src/libc_start.c b/libc/src/libc_start.c index faa0268c..04eca046 100644 --- a/libc/src/libc_start.c +++ b/libc/src/libc_start.c @@ -35,8 +35,3 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char *argv[] //dbg_print("== END %-30s =======================================\n", argv[0]); return result; } - -// WARNING: This declaration must be here, because libc_start is compiled -// with all the programs, and all the programs NEED to have the `sigreturn` -// symbol. It must be this way, period. -_syscall0(int, sigreturn) diff --git a/libc/src/pwd.c b/libc/src/pwd.c index 7a1ed8e8..3fc601f4 100644 --- a/libc/src/pwd.c +++ b/libc/src/pwd.c @@ -162,6 +162,7 @@ int getpwnam_r(const char *name, passwd_t *pwd, char *buf, size_t buflen, passwd // Return success. return 1; } + errno = ENOENT; // Close the file. close(fd); // Return fail. diff --git a/libc/src/unistd/signal.c b/libc/src/unistd/signal.c index 0755c7c8..84f4e831 100644 --- a/libc/src/unistd/signal.c +++ b/libc/src/unistd/signal.c @@ -10,6 +10,10 @@ #include "signal.h" #include "sys/bitops.h" +_syscall0(int, sigreturn) + +_syscall3(int, sigprocmask, int, how, const sigset_t *, set, sigset_t *, oldset) + static const char *sys_siglist[] = { "HUP", "INT", @@ -45,11 +49,19 @@ static const char *sys_siglist[] = { NULL, }; -_syscall2(sighandler_t, signal, int, signum, sighandler_t, handler) - -_syscall3(int, sigaction, int, signum, const sigaction_t *, act, sigaction_t *, oldact) +sighandler_t signal(int signum, sighandler_t handler) +{ + long __res; + __inline_syscall3(__res, signal, signum, handler, (unsigned int)sigreturn); + __syscall_return(sighandler_t, __res); +} -_syscall3(int, sigprocmask, int, how, const sigset_t *, set, sigset_t *, oldset) +int sigaction(int signum, const sigaction_t *act, sigaction_t *oldact) +{ + long __res; + __inline_syscall4(__res, sigaction, signum, act, oldact, (unsigned int)sigreturn); + __syscall_return(int, __res); +} const char *strsignal(int sig) { diff --git a/mentos/inc/process/process.h b/mentos/inc/process/process.h index d0e3421d..6c0e032a 100644 --- a/mentos/inc/process/process.h +++ b/mentos/inc/process/process.h @@ -119,9 +119,8 @@ typedef struct task_struct { /// The current working directory. char cwd[PATH_MAX]; - // struct signal_struct *signal; - /// Instruction Pointer of the LIBC Signal Handler. - uint32_t sigreturn_eip; + /// Address of the LIBC sigreturn function. + uint32_t sigreturn_addr; /// Pointer to the process’s signal handler descriptor sighand_t sighand; /// Mask of blocked signals. diff --git a/mentos/inc/system/signal.h b/mentos/inc/system/signal.h index 75da6c30..ab7b8322 100644 --- a/mentos/inc/system/signal.h +++ b/mentos/inc/system/signal.h @@ -269,14 +269,14 @@ int sys_kill(pid_t pid, int sig); /// @param signum The signal number. /// @param handler The handler for the signal. /// @return The previous value of the signal handler, or SIG_ERR on error. -sighandler_t sys_signal(int signum, sighandler_t handler); +sighandler_t sys_signal(int signum, sighandler_t handler, uint32_t sigreturn_addr); /// @brief Examine and change a signal action. /// @param signum Specifies the signal and can be any valid signal except SIGKILL and SIGSTOP. /// @param act If non-NULL, the new action for signal signum is installed from act. /// @param oldact If non-NULL, the previous action is saved in oldact. /// @return returns 0 on success; on error, -1 is returned, and errno is set to indicate the error. -int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact); +int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact, uint32_t sigreturn_addr); /// @brief Examine and change blocked signals. /// @param how Determines the behavior of the call. diff --git a/mentos/src/elf/elf.c b/mentos/src/elf/elf.c index c485ce3a..305191ff 100644 --- a/mentos/src/elf/elf.c +++ b/mentos/src/elf/elf.c @@ -222,17 +222,6 @@ static inline void elf_dump_symbol_table(elf_header_t *header) // EXEC-RELATED FUNCTIONS // ============================================================================ -static inline int elf_set_sigreturn(elf_header_t *header, task_struct *task) -{ - elf_symbol_t *sigreturn = elf_find_symbol(header, "sigreturn"); - if (sigreturn == NULL) { - pr_err("Failed to find `sigreturn`!\n"); - return false; - } - task->sigreturn_eip = sigreturn->value; - return true; -} - /// @brief Loads an ELF executable. /// @param task The task for which we load the ELF. /// @param file The ELF file. @@ -311,11 +300,6 @@ int elf_load_file(task_struct *task, vfs_file_t *file, uint32_t *entry) pr_err("Elf file is not an executable.\n"); goto return_error_free_buffer; } - // Set the sigreturn of the task. - if (!elf_set_sigreturn(header, task)) { - pr_err("Failed to set `sigreturn` for the executable.\n"); - goto return_error_free_buffer; - } if (!elf_load_exec(header, task)) { pr_err("Failed to load the executable.\n"); goto return_error_free_buffer; diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index e3b09e07..bc64e201 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -386,7 +386,6 @@ static int ext2_mkdir(const char *path, mode_t mode); static int ext2_rmdir(const char *path); static int ext2_stat(const char *path, stat_t *stat); static vfs_file_t *ext2_creat(const char *path, mode_t permission); - static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path); // ============================================================================ @@ -430,6 +429,28 @@ static const char *uuid_to_string(uint8_t uuid[16]) return s; } +/// @brief Turns an ext2_file_type to string. +/// @param ext2_type the ext2_file_type to turn to string. +/// @return the string representing the ext2_file_type. +static const char *ext2_file_type_to_string(ext2_file_type_t ext2_type) +{ + if (ext2_type == ext2_file_type_regular_file) + return "REG"; + if (ext2_type == ext2_file_type_directory) + return "DIR"; + if (ext2_type == ext2_file_type_character_device) + return "CHR"; + if (ext2_type == ext2_file_type_block_device) + return "BLK"; + if (ext2_type == ext2_file_type_named_pipe) + return "FIFO"; + if (ext2_type == ext2_file_type_socket) + return "SOCK"; + if (ext2_type == ext2_file_type_symbolic_link) + return "LNK"; + return "UNK"; +} + static int ext2_file_type_to_vfs_file_type(int ext2_type) { if (ext2_type == ext2_file_type_regular_file) @@ -502,63 +523,63 @@ static bool_t ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gi /// @param sb the object to dump. static void ext2_dump_superblock(ext2_superblock_t *sb) { - pr_debug("inodes_count : %d\n", sb->inodes_count); - pr_debug("blocks_count : %d\n", sb->blocks_count); - pr_debug("r_blocks_count : %d\n", sb->r_blocks_count); - pr_debug("free_blocks_count : %d\n", sb->free_blocks_count); - pr_debug("free_inodes_count : %d\n", sb->free_inodes_count); - pr_debug("first_data_block : %d\n", sb->first_data_block); - pr_debug("log_block_size : %d\n", sb->log_block_size); - pr_debug("log_frag_size : %d\n", sb->log_frag_size); - pr_debug("blocks_per_group : %d\n", sb->blocks_per_group); - pr_debug("frags_per_group : %d\n", sb->frags_per_group); - pr_debug("inodes_per_group : %d\n", sb->inodes_per_group); + pr_debug("inodes_count : %u\n", sb->inodes_count); + pr_debug("blocks_count : %u\n", sb->blocks_count); + pr_debug("r_blocks_count : %u\n", sb->r_blocks_count); + pr_debug("free_blocks_count : %u\n", sb->free_blocks_count); + pr_debug("free_inodes_count : %u\n", sb->free_inodes_count); + pr_debug("first_data_block : %u\n", sb->first_data_block); + pr_debug("log_block_size : %u\n", sb->log_block_size); + pr_debug("log_frag_size : %u\n", sb->log_frag_size); + pr_debug("blocks_per_group : %u\n", sb->blocks_per_group); + pr_debug("frags_per_group : %u\n", sb->frags_per_group); + pr_debug("inodes_per_group : %u\n", sb->inodes_per_group); pr_debug("mtime : %s\n", time_to_string(sb->mtime)); pr_debug("wtime : %s\n", time_to_string(sb->wtime)); pr_debug("mnt_count : %d\n", sb->mnt_count); pr_debug("max_mnt_count : %d\n", sb->max_mnt_count); - pr_debug("magic : 0x%0x\n", sb->magic); + pr_debug("magic : 0x%0x (== 0x%0x)\n", sb->magic, EXT2_SUPERBLOCK_MAGIC); pr_debug("state : %d\n", sb->state); pr_debug("errors : %d\n", sb->errors); pr_debug("minor_rev_level : %d\n", sb->minor_rev_level); pr_debug("lastcheck : %s\n", time_to_string(sb->lastcheck)); - pr_debug("checkinterval : %d\n", sb->checkinterval); - pr_debug("creator_os : %d\n", sb->creator_os); - pr_debug("rev_level : %d\n", sb->rev_level); - pr_debug("def_resuid : %d\n", sb->def_resuid); - pr_debug("def_resgid : %d\n", sb->def_resgid); - pr_debug("first_ino : %d\n", sb->first_ino); - pr_debug("inode_size : %d\n", sb->inode_size); - pr_debug("block_group_nr : %d\n", sb->block_group_nr); - pr_debug("feature_compat : %d\n", sb->feature_compat); - pr_debug("feature_incompat : %d\n", sb->feature_incompat); - pr_debug("feature_ro_compat : %d\n", sb->feature_ro_compat); + pr_debug("checkinterval : %u\n", sb->checkinterval); + pr_debug("creator_os : %u\n", sb->creator_os); + pr_debug("rev_level : %u\n", sb->rev_level); + pr_debug("def_resuid : %u\n", sb->def_resuid); + pr_debug("def_resgid : %u\n", sb->def_resgid); + pr_debug("first_ino : %u\n", sb->first_ino); + pr_debug("inode_size : %u\n", sb->inode_size); + pr_debug("block_group_nr : %u\n", sb->block_group_nr); + pr_debug("feature_compat : %u\n", sb->feature_compat); + pr_debug("feature_incompat : %u\n", sb->feature_incompat); + pr_debug("feature_ro_compat : %u\n", sb->feature_ro_compat); pr_debug("uuid : %s\n", uuid_to_string(sb->uuid)); pr_debug("volume_name : %s\n", (char *)sb->volume_name); pr_debug("last_mounted : %s\n", (char *)sb->last_mounted); - pr_debug("algo_bitmap : %d\n", sb->algo_bitmap); - pr_debug("prealloc_blocks : %d\n", sb->prealloc_blocks); - pr_debug("prealloc_dir_blocks : %d\n", sb->prealloc_dir_blocks); + pr_debug("algo_bitmap : %u\n", sb->algo_bitmap); + pr_debug("prealloc_blocks : %u\n", sb->prealloc_blocks); + pr_debug("prealloc_dir_blocks : %u\n", sb->prealloc_dir_blocks); pr_debug("journal_uuid : %s\n", uuid_to_string(sb->journal_uuid)); - pr_debug("journal_inum : %d\n", sb->journal_inum); - pr_debug("jounral_dev : %d\n", sb->jounral_dev); - pr_debug("last_orphan : %d\n", sb->last_orphan); + pr_debug("journal_inum : %u\n", sb->journal_inum); + pr_debug("jounral_dev : %u\n", sb->jounral_dev); + pr_debug("last_orphan : %u\n", sb->last_orphan); pr_debug("hash_seed : %u %u %u %u\n", sb->hash_seed[0], sb->hash_seed[1], sb->hash_seed[2], sb->hash_seed[3]); - pr_debug("def_hash_version : %d\n", sb->def_hash_version); - pr_debug("default_mount_options : %d\n", sb->default_mount_options); - pr_debug("first_meta_bg : %d\n", sb->first_meta_block_group_id); + pr_debug("def_hash_version : %u\n", sb->def_hash_version); + pr_debug("default_mount_options : %u\n", sb->default_mount_options); + pr_debug("first_meta_bg : %u\n", sb->first_meta_block_group_id); } /// @brief Dumps on debugging output the group descriptor. /// @param gd the object to dump. static void ext2_dump_group_descriptor(ext2_group_descriptor_t *gd) { - pr_debug("block_bitmap : %d\n", gd->block_bitmap); - pr_debug("inode_bitmap : %d\n", gd->inode_bitmap); - pr_debug("inode_table : %d\n", gd->inode_table); - pr_debug("free_blocks_count : %d\n", gd->free_blocks_count); - pr_debug("free_inodes_count : %d\n", gd->free_inodes_count); - pr_debug("used_dirs_count : %d\n", gd->used_dirs_count); + pr_debug("block_bitmap : %u\n", gd->block_bitmap); + pr_debug("inode_bitmap : %u\n", gd->inode_bitmap); + pr_debug("inode_table : %u\n", gd->inode_table); + pr_debug("free_blocks_count : %u\n", gd->free_blocks_count); + pr_debug("free_inodes_count : %u\n", gd->free_inodes_count); + pr_debug("used_dirs_count : %u\n", gd->used_dirs_count); } /// @brief Dumps on debugging output the inode. @@ -601,6 +622,13 @@ static void ext2_dump_inode(ext2_inode_t *inode) inode->generation, inode->file_acl, inode->dir_acl); } +/// @brief Dumps on debugging output the dirent. +/// @param dirent the object to dump. +static void ext2_dump_dirent(ext2_dirent_t *dirent) +{ + pr_debug("Inode: %4u Rec. Len.: %4u Name Len.: %4u Type:%4s Name: %s\n", dirent->inode, dirent->rec_len, dirent->name_len, ext2_file_type_to_string(dirent->file_type), dirent->name); +} + /// @brief Dumps on debugging output the BGDT. /// @param fs the filesystem of which we print the BGDT. static void ext2_dump_bgdt(ext2_filesystem_t *fs) @@ -612,21 +640,21 @@ static void ext2_dump_bgdt(ext2_filesystem_t *fs) for (uint32_t i = 0; i < fs->block_groups_count; ++i) { // Get the pointer to the current group descriptor. ext2_group_descriptor_t *gd = &(fs->block_groups[i]); - pr_debug("Block Group Descriptor [%d] @ %d:\n", i, fs->bgdt_start_block + i * fs->superblock.blocks_per_group); - pr_debug(" block_bitmap : %d\n", gd->block_bitmap); - pr_debug(" inode_bitmap : %d\n", gd->inode_bitmap); - pr_debug(" inode_table : %d\n", gd->inode_table); - pr_debug(" Used Dirs : %d\n", gd->used_dirs_count); - pr_debug(" Free Blocks : %4d of %d\n", gd->free_blocks_count, fs->superblock.blocks_per_group); - pr_debug(" Free Inodes : %4d of %d\n", gd->free_inodes_count, fs->superblock.inodes_per_group); + pr_debug("Block Group Descriptor [%u] @ %u:\n", i, fs->bgdt_start_block + i * fs->superblock.blocks_per_group); + pr_debug(" block_bitmap : %u\n", gd->block_bitmap); + pr_debug(" inode_bitmap : %u\n", gd->inode_bitmap); + pr_debug(" inode_table : %u\n", gd->inode_table); + pr_debug(" Used Dirs : %u\n", gd->used_dirs_count); + pr_debug(" Free Blocks : %4u of %u\n", gd->free_blocks_count, fs->superblock.blocks_per_group); + pr_debug(" Free Inodes : %4u of %u\n", gd->free_inodes_count, fs->superblock.inodes_per_group); // Dump the block bitmap. ext2_read_block(fs, gd->block_bitmap, cache); - pr_debug(" Block Bitmap at %d\n", gd->block_bitmap); + pr_debug(" Block Bitmap at %u\n", gd->block_bitmap); for (uint32_t j = 0; j < fs->block_size; ++j) { if ((j % 8) == 0) - pr_debug(" Block index: %4d, Bitmap: %s\n", j / 8, dec_to_binary(cache[j / 8], 8)); + pr_debug(" Block index: %4u, Bitmap: %s\n", j / 8, dec_to_binary(cache[j / 8], 8)); if (!ext2_check_bitmap_bit(cache, j)) { - pr_debug(" First free block in group is in block %d, the linear index is %d\n", j / 8, j); + pr_debug(" First free block in group is in block %u, the linear index is %u\n", j / 8, j); break; } } @@ -674,6 +702,7 @@ static void ext2_dump_filesystem(ext2_filesystem_t *fs) /// @details Remember that inode addressing starts from 1. static uint32_t ext2_get_group_index_from_inode(ext2_filesystem_t *fs, uint32_t inode_index) { + assert(inode_index != 0 && "Your are trying to access inode 0."); return (inode_index - 1) / fs->superblock.inodes_per_group; } @@ -684,6 +713,7 @@ static uint32_t ext2_get_group_index_from_inode(ext2_filesystem_t *fs, uint32_t /// @details Remember that inode addressing starts from 1. static uint32_t ext2_get_inode_offest_in_group(ext2_filesystem_t *fs, uint32_t inode_index) { + assert(inode_index != 0 && "Your are trying to access inode 0."); return (inode_index - 1) % fs->superblock.inodes_per_group; } @@ -852,7 +882,6 @@ static int ext2_write_superblock(ext2_filesystem_t *fs) /// @return the amount of data we read, or negative value for an error. static int ext2_read_block(ext2_filesystem_t *fs, uint32_t block_index, uint8_t *buffer) { - //pr_debug("Read block %4d for EXT2 filesystem (0x%x)\n", block_index, fs); if (block_index == 0) { pr_err("You are trying to read an invalid block index (%d).\n", block_index); return -1; @@ -871,7 +900,6 @@ static int ext2_read_block(ext2_filesystem_t *fs, uint32_t block_index, uint8_t /// @return the amount of data we wrote, or negative value for an error. static int ext2_write_block(ext2_filesystem_t *fs, uint32_t block_index, uint8_t *buffer) { - //pr_debug("Write block %4d for EXT2 filesystem (0x%x)\n", block_index, fs); if (block_index == 0) { pr_err("You are trying to write on an invalid block index (%d).\n", block_index); return -1; @@ -920,30 +948,33 @@ static int ext2_write_bgdt(ext2_filesystem_t *fs) /// @return 0 on success, -1 on failure. static int ext2_read_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index) { + uint32_t group_index, block_index, inode_offset; if (inode_index == 0) { pr_err("You are trying to read an invalid inode index (%d).\n", inode_index); return -1; } // Retrieve the group index. - uint32_t group_index = ext2_get_group_index_from_inode(fs, inode_index); + group_index = ext2_get_group_index_from_inode(fs, inode_index); if (group_index > fs->block_groups_count) { pr_err("Invalid group index computed from inode index `%d`.\n", inode_index); return -1; } // Get the index of the inode inside the group. - uint32_t offset = ext2_get_inode_offest_in_group(fs, inode_index); + inode_offset = ext2_get_inode_offest_in_group(fs, inode_index); // Get the block offest. - uint32_t block = ext2_get_block_index_from_inode_offset(fs, offset); + block_index = ext2_get_block_index_from_inode_offset(fs, inode_offset); // Get the real inode offset inside the block. - offset %= fs->inodes_per_block_count; + inode_offset %= fs->inodes_per_block_count; + // Log the address to the inode. + pr_debug("Read inode (inode:%4u block:%4u offset:%4u)\n", inode_index, block_index, inode_offset); // Allocate the cache. uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); // Clean the cache. memset(cache, 0, fs->block_size); // Read the block containing the inode table. - ext2_read_block(fs, fs->block_groups[group_index].inode_table + block, cache); + ext2_read_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Save the inode content. - memcpy(inode, (ext2_inode_t *)((uintptr_t)cache + (offset * fs->superblock.inode_size)), fs->superblock.inode_size); + memcpy(inode, (ext2_inode_t *)((uintptr_t)cache + (inode_offset * fs->superblock.inode_size)), sizeof(ext2_inode_t)); // Free the cache. kmem_cache_free(cache); return 0; @@ -956,32 +987,35 @@ static int ext2_read_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t /// @return 0 on success, -1 on failure. static int ext2_write_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index) { + uint32_t group_index, block_index, inode_offset; if (inode_index == 0) { pr_err("You are trying to read an invalid inode index (%d).\n", inode_index); return -1; } // Retrieve the group index. - uint32_t group_index = ext2_get_group_index_from_inode(fs, inode_index); + group_index = ext2_get_group_index_from_inode(fs, inode_index); if (group_index > fs->block_groups_count) { pr_err("Invalid group index computed from inode index `%d`.\n", inode_index); return -1; } // Get the offset of the inode inside the group. - uint32_t offset = ext2_get_inode_offest_in_group(fs, inode_index); + inode_offset = ext2_get_inode_offest_in_group(fs, inode_index); // Get the block offest. - uint32_t block = ext2_get_block_index_from_inode_offset(fs, offset); + block_index = ext2_get_block_index_from_inode_offset(fs, inode_offset); // Get the real inode offset inside the block. - offset %= fs->inodes_per_block_count; + inode_offset %= fs->inodes_per_block_count; + // Log the address to the inode. + pr_debug("Write inode (inode:%4u block:%4u offset:%4u)\n", inode_index, block_index, inode_offset); // Allocate the cache. uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); // Clean the cache. memset(cache, 0, fs->block_size); // Read the block containing the inode table. - ext2_read_block(fs, fs->block_groups[group_index].inode_table + block, cache); + ext2_read_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Write the inode. - memcpy((ext2_inode_t *)((uintptr_t)cache + (offset * fs->superblock.inode_size)), inode, fs->superblock.inode_size); + memcpy((ext2_inode_t *)((uintptr_t)cache + (inode_offset * fs->superblock.inode_size)), inode, sizeof(ext2_inode_t)); // Write back the block. - ext2_write_block(fs, fs->block_groups[group_index].inode_table + block, cache); + ext2_write_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Free the cache. kmem_cache_free(cache); return 0; @@ -1380,6 +1414,8 @@ static ssize_t ext2_read_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t real_index = ext2_get_real_block_index(fs, inode, block_index); if (real_index == 0) return -1; + // Log the address to the inode block. + pr_debug("Read inode block (block:%4u real:%4u)\n", block_index, real_index); // Read the block. return ext2_read_block(fs, real_index, buffer); } @@ -1401,6 +1437,8 @@ static ssize_t ext2_write_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode uint32_t real_index = ext2_get_real_block_index(fs, inode, block_index); if (real_index == 0) return -1; + // Log the address to the inode block. + pr_debug("Write inode block (block:%4u real:%4u inode:%4u)\n", block_index, real_index, inode_index); // Write the block. return ext2_write_block(fs, real_index, buffer); } @@ -1919,7 +1957,6 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se pr_err("You provided a NULL direntry.\n"); return -1; } - pr_debug("ext2_resolve_path(directory: \"%s\", path: \"%s\")\n", directory->name, path); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)directory->device; if (fs == NULL) { @@ -1943,8 +1980,6 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se token = strtok(NULL, "/"); } kfree(tmp_path); - pr_debug("ext2_resolve_path(directory: \"%s\", path: \"%s\") -> (ino: %d, name: \"%s\")\n", - directory->name, path, search->direntry->inode, search->direntry->name); return 0; } @@ -1955,7 +1990,6 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se /// @return 0 on success, -1 on failure. static int ext2_resolve_path_direntry(vfs_file_t *directory, char *path, ext2_dirent_t *direntry) { - pr_debug("ext2_resolve_path_direntry(%s, %s, %p)\n", directory->name, path, direntry); // Check the pointers. if (directory == NULL) { pr_err("You provided a NULL directory.\n"); @@ -1985,7 +2019,6 @@ static int ext2_resolve_path_direntry(vfs_file_t *directory, char *path, ext2_di /// @return a pointer to the EXT2 filesystem, NULL otherwise. static ext2_filesystem_t *get_ext2_filesystem(const char *absolute_path) { - pr_debug("get_ext2_filesystem(%s)\n", absolute_path); if (absolute_path == NULL) { pr_err("We received a NULL absolute path.\n"); return NULL; @@ -2924,7 +2957,7 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) NULL, NULL); // Compute the maximum number of inodes per block. - fs->inodes_per_block_count = fs->block_size / sizeof(ext2_inode_t); + fs->inodes_per_block_count = fs->block_size / fs->superblock.inode_size; // Compute the number of blocks per block. This value is mostly used for // inodes. // If you check inside the inode structure you will find the `blocks_count` diff --git a/mentos/src/kernel.c b/mentos/src/kernel.c index c2151f95..a051c1e2 100644 --- a/mentos/src/kernel.c +++ b/mentos/src/kernel.c @@ -374,8 +374,6 @@ int kmain(boot_info_t *boot_informations) // We have completed the booting procedure. pr_notice("Booting done, jumping into init process.\n"); - // Print the welcome message. - printf("\n .: Welcome to MentOS :.\n\n"); // Switch to the page directory of init. paging_switch_directory_va(init_p->mm->pgd); // Jump into init process. diff --git a/mentos/src/system/signal.c b/mentos/src/system/signal.c index e83eba02..8d6f7d70 100644 --- a/mentos/src/system/signal.c +++ b/mentos/src/system/signal.c @@ -300,7 +300,7 @@ static inline int __handle_signal(int signr, siginfo_t *info, sigaction_t *ka, s PUSH_VALUE_ON_STACK(regs->useresp, signr); // Push on the stack the function required to handle the signal return. - PUSH_VALUE_ON_STACK(regs->useresp, current->sigreturn_eip); + PUSH_VALUE_ON_STACK(regs->useresp, current->sigreturn_addr); return 1; } @@ -631,9 +631,9 @@ int sys_kill(pid_t pid, int sig) return __send_sig_info(sig, &info, current); } -sighandler_t sys_signal(int signum, sighandler_t handler) +sighandler_t sys_signal(int signum, sighandler_t handler, uint32_t sigreturn_addr) { - pr_debug("sys_signal(%d, %p)\n", signum, handler); + pr_debug("sys_signal(%d, %p, %p)\n", signum, handler, sigreturn_ptr); // Check the signal that we want to send. if ((signum < 0) || (signum >= NSIG)) { pr_err("sys_signal(%d, %p): Wrong signal number!\n", signum, handler); @@ -658,6 +658,8 @@ sighandler_t sys_signal(int signum, sighandler_t handler) sigemptyset(&new_sigaction.sa_mask); // Lock the signal handling for the given task. __lock_task_sighand(current); + // Set the address of the sigreturn. + current->sigreturn_addr = sigreturn_addr; // Get the old sigaction. sigaction_t *old_sigaction = ¤t->sighand.action[signum - 1]; pr_err("sys_signal(%d, %p): Signal action ptr %p\n", signum, handler, old_sigaction); @@ -672,9 +674,9 @@ sighandler_t sys_signal(int signum, sighandler_t handler) return old_handler; } -int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact) +int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact, uint32_t sigreturn_addr) { - pr_debug("sys_sigaction(%d, %p, %p)\n", signum, act, oldact); + pr_debug("sys_sigaction(%d, %p, %p, %p)\n", signum, act, oldact, sigreturn_ptr); // Check the signal that we want to send. if ((signum < 0) || (signum >= NSIG)) { pr_err("sys_sigaction(%d, %p, %p): Wrong signal number!\n", signum, act, oldact); @@ -691,6 +693,8 @@ int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact) } // Lock the signal handling for the given task. __lock_task_sighand(current); + // Set the address of the sigreturn. + current->sigreturn_addr = sigreturn_addr; // Get a pointer to the entry in the sighand.action array. sigaction_t *current_sigaction = ¤t->sighand.action[signum - 1]; pr_debug("sys_sigaction(%d, %p, %p): : Signal old action ptr %p\n", signum, act, oldact, current_sigaction); diff --git a/programs/ansi_colors.h b/programs/ansi_colors.h new file mode 100644 index 00000000..65b9cc6d --- /dev/null +++ b/programs/ansi_colors.h @@ -0,0 +1,61 @@ +/// @file ansi_colors.h +/// @author Enrico Fraccaroli (enry.frak@gmail.com) +/// @brief Macros for ANSI colors. + +#pragma once + +#define FG_RESET "\033[0m" ///< ANSI code for resetting. + +#define FG_BLACK "\033[30m" ///< ANSI code for setting a BLACK foreground. +#define FG_RED "\033[31m" ///< ANSI code for setting a RED foreground. +#define FG_GREEN "\033[32m" ///< ANSI code for setting a GREEN foreground. +#define FG_YELLOW "\033[33m" ///< ANSI code for setting a YELLOW foreground. +#define FG_BLUE "\033[34m" ///< ANSI code for setting a BLUE foreground. +#define FG_MAGENTA "\033[35m" ///< ANSI code for setting a MAGENTA foreground. +#define FG_CYAN "\033[36m" ///< ANSI code for setting a CYAN foreground. +#define FG_WHITE "\033[37m" ///< ANSI code for setting a WHITE foreground. + +#define FG_BLACK_BOLD "\033[1;30m" ///< ANSI code for setting a BLACK foreground. +#define FG_RED_BOLD "\033[1;31m" ///< ANSI code for setting a RED foreground. +#define FG_GREEN_BOLD "\033[1;32m" ///< ANSI code for setting a GREEN foreground. +#define FG_YELLOW_BOLD "\033[1;33m" ///< ANSI code for setting a YELLOW foreground. +#define FG_BLUE_BOLD "\033[1;34m" ///< ANSI code for setting a BLUE foreground. +#define FG_MAGENTA_BOLD "\033[1;35m" ///< ANSI code for setting a MAGENTA foreground. +#define FG_CYAN_BOLD "\033[1;36m" ///< ANSI code for setting a CYAN foreground. +#define FG_WHITE_BOLD "\033[1;37m" ///< ANSI code for setting a WHITE foreground. + +#define FG_BLACK_BRIGHT "\033[90m" ///< ANSI code for setting a BRIGHT_BLACK foreground. +#define FG_RED_BRIGHT "\033[91m" ///< ANSI code for setting a BRIGHT_RED foreground. +#define FG_GREEN_BRIGHT "\033[92m" ///< ANSI code for setting a BRIGHT_GREEN foreground. +#define FG_YELLOW_BRIGHT "\033[93m" ///< ANSI code for setting a BRIGHT_YELLOW foreground. +#define FG_BLUE_BRIGHT "\033[94m" ///< ANSI code for setting a BRIGHT_BLUE foreground. +#define FG_MAGENTA_BRIGHT "\033[95m" ///< ANSI code for setting a BRIGHT_MAGENTA foreground. +#define FG_CYAN_BRIGHT "\033[96m" ///< ANSI code for setting a BRIGHT_CYAN foreground. +#define FG_WHITE_BRIGHT "\033[97m" ///< ANSI code for setting a BRIGHT_WHITE foreground. + +#define FG_BLACK_BRIGHT_BOLD "\033[1;90m" ///< ANSI code for setting a BRIGHT_BLACK foreground. +#define FG_RED_BRIGHT_BOLD "\033[1;91m" ///< ANSI code for setting a BRIGHT_RED foreground. +#define FG_GREEN_BRIGHT_BOLD "\033[1;92m" ///< ANSI code for setting a BRIGHT_GREEN foreground. +#define FG_YELLOW_BRIGHT_BOLD "\033[1;93m" ///< ANSI code for setting a BRIGHT_YELLOW foreground. +#define FG_BLUE_BRIGHT_BOLD "\033[1;94m" ///< ANSI code for setting a BRIGHT_BLUE foreground. +#define FG_MAGENTA_BRIGHT_BOLD "\033[1;95m" ///< ANSI code for setting a BRIGHT_MAGENTA foreground. +#define FG_CYAN_BRIGHT_BOLD "\033[1;96m" ///< ANSI code for setting a BRIGHT_CYAN foreground. +#define FG_WHITE_BRIGHT_BOLD "\033[1;97m" ///< ANSI code for setting a BRIGHT_WHITE foreground. + +#define BG_BLACK "\033[40m" ///< ANSI code for setting a BLACK background. +#define BG_RED "\033[41m" ///< ANSI code for setting a RED background. +#define BG_GREEN "\033[42m" ///< ANSI code for setting a GREEN background. +#define BG_YELLOW "\033[43m" ///< ANSI code for setting a YELLOW background. +#define BG_BLUE "\033[44m" ///< ANSI code for setting a BLUE background. +#define BG_MAGENTA "\033[45m" ///< ANSI code for setting a MAGENTA background. +#define BG_CYAN "\033[46m" ///< ANSI code for setting a CYAN background. +#define BG_WHITE "\033[47m" ///< ANSI code for setting a WHITE background. + +#define BG_BRIGHT_BLACK "\033[100m" ///< ANSI code for setting a BRIGHT_BLACK background. +#define BG_BRIGHT_RED "\033[101m" ///< ANSI code for setting a BRIGHT_RED background. +#define BG_BRIGHT_GREEN "\033[102m" ///< ANSI code for setting a BRIGHT_GREEN background. +#define BG_BRIGHT_YELLOW "\033[103m" ///< ANSI code for setting a BRIGHT_YELLOW background. +#define BG_BRIGHT_BLUE "\033[104m" ///< ANSI code for setting a BRIGHT_BLUE background. +#define BG_BRIGHT_MAGENTA "\033[105m" ///< ANSI code for setting a BRIGHT_MAGENTA background. +#define BG_BRIGHT_CYAN "\033[106m" ///< ANSI code for setting a BRIGHT_CYAN background. +#define BG_BRIGHT_WHITE "\033[107m" ///< ANSI code for setting a BRIGHT_WHITE background. diff --git a/programs/login.c b/programs/login.c index 14b96359..de9d6e3a 100644 --- a/programs/login.c +++ b/programs/login.c @@ -3,7 +3,6 @@ /// @copyright (c) 2014-2022 This file is distributed under the MIT License. /// See LICENSE.md for details. -/// Maximum length of credentials. #include #include #include @@ -15,50 +14,74 @@ #include #include #include - #include +#include "ansi_colors.h" + +/// Maximum length of credentials. #define CREDENTIALS_LENGTH 50 -#define FG_BLACK "\033[30m" -#define FG_WHITE "\033[37m" -#define FG_RED "\033[31m" -#define BG_WHITE "\033[47m" -#define BG_BLACK "\033[40m" +static inline int __setup_env(passwd_t *pwd) +{ + // Set the USER. + if (setenv("USER", pwd->pw_name, 1) == -1) { + printf("Failed to set env: `USER`\n"); + return 0; + } + // Set the SHELL. + if (setenv("SHELL", pwd->pw_shell, 1) == -1) { + printf("Failed to set env: `SHELL`\n"); + return 0; + } + // Set the HOME. + if (setenv("HOME", pwd->pw_dir, 1) == -1) { + printf("Failed to set env: `HOME`\n"); + return 0; + } + return 1; +} -void set_echo(bool_t active) +static inline void __set_io_flags(unsigned flag, bool_t active) { struct termios _termios; tcgetattr(STDIN_FILENO, &_termios); if (active) - _termios.c_lflag |= (ICANON | ECHO); + _termios.c_lflag |= flag; else - _termios.c_lflag &= ~(ICANON | ECHO); + _termios.c_lflag &= ~flag; tcsetattr(STDIN_FILENO, 0, &_termios); } -void set_erase(bool_t active) +static inline void __print_message_file(const char * file) { - struct termios _termios; - tcgetattr(STDIN_FILENO, &_termios); - if (active) - _termios.c_lflag |= ECHOE; - else - _termios.c_lflag &= ~ECHOE; - tcsetattr(STDIN_FILENO, 0, &_termios); + char buffer[256]; + ssize_t nbytes, total = 0; + int fd; + + // Try to open the file. + if ((fd = open(file, O_RDONLY, 0600)) == -1) + return; + // Read the lines of the file. + while ((nbytes = read(fd, buffer, sizeof(char) * 256)) > 0) { + // TODO: Parsing message files for special characters (such as `\t` for time). + printf("%s\n", buffer); + total += nbytes; + } + close(fd); + if (total > 0) + printf("\n"); } /// @brief Gets the inserted command. -static bool_t get_input(char *input, size_t max_len, bool_t hide) +static inline bool_t __get_input(char *input, size_t max_len, bool_t hide) { size_t index = 0; int c; bool_t result = false; - //set_erase(false); - if (hide) { - set_echo(false); - } + __set_io_flags(ICANON, false); + if (hide) + __set_io_flags(ECHO, false); memset(input, 0, max_len); do { @@ -104,6 +127,8 @@ static bool_t get_input(char *input, size_t max_len, bool_t hide) putchar('\b'); --index; } + } else if (c == 0) { + // Do nothing. } else { input[index++] = c; if (index == (max_len - 1)) { @@ -114,59 +139,34 @@ static bool_t get_input(char *input, size_t max_len, bool_t hide) } } while (index < max_len); - //set_erase(true); if (hide) { - set_echo(true); + __set_io_flags(ECHO, true); putchar('\n'); } + __set_io_flags(ICANON, true); return result; } -static inline int setup_env(passwd_t *pwd) -{ - // Set the USER. - if (setenv("USER", pwd->pw_name, 1) == -1) { - printf("Failed to set env: `USER`\n"); - return 0; - } - // Set the SHELL. - if (setenv("SHELL", pwd->pw_shell, 1) == -1) { - printf("Failed to set env: `SHELL`\n"); - return 0; - } - // Set the HOME. - if (setenv("HOME", pwd->pw_dir, 1) == -1) { - printf("Failed to set env: `HOME`\n"); - return 0; - } - return 1; -} - int main(int argc, char **argv) { - // Print /etc/issue if it exists - // TODO: Parsing /etc/issue for special characters (such as `\t` for time) - int issues_fd = open("/etc/issue", O_RDONLY, 0600); - if (issues_fd != -1){ - char buffer[256]; - - if(read(issues_fd, buffer, sizeof(char)*256) != -1){ - printf("%s \n", buffer); - } - close(issues_fd); - } - + // Print /etc/issue if it exists. + __print_message_file("/etc/issue"); + passwd_t *pwd; - char username[50], password[50]; + char username[CREDENTIALS_LENGTH], password[CREDENTIALS_LENGTH]; do { // Get the username. do { printf("Username :"); - } while (!get_input(username, 50, false)); + } while (!__get_input(username, CREDENTIALS_LENGTH, false)); + + // Get the password. do { printf("Password :"); - } while (!get_input(password, 50, true)); + } while (!__get_input(password, CREDENTIALS_LENGTH, true)); + + // Check if we can find the user. if ((pwd = getpwnam(username)) == NULL) { if (errno == ENOENT) { printf("The given name was not found.\n"); @@ -177,29 +177,47 @@ int main(int argc, char **argv) } continue; } + + // Check if the password is correct. if (strcmp(pwd->pw_passwd, password) != 0) { printf("Wrong password.\n"); continue; } + break; } while (true); + + // If there is not shell set for the user, should we rollback to standard shell? if (pwd->pw_shell == NULL) { - printf("%s: There is no shell set for the user `%s`.\n", argv[0], pwd->pw_name); + printf("login: There is no shell set for the user `%s`.\n", pwd->pw_name); return 1; } - if (!setup_env(pwd)) { - printf("%s: Failed to setup the environmental variables.\n", argv[0]); + // Set the standard environmental variables. + if (!__setup_env(pwd)) { + printf("login: Failed to setup the environmental variables.\n"); return 1; } + // Set the group id. setgid(pwd->pw_gid); + + // Set the user id. setuid(pwd->pw_uid); + // Print /etc/motd if it exists. + __print_message_file("/etc/motd"); + + // Welcome the user. + puts(BG_WHITE FG_BLACK); + printf("Welcome " FG_RED "%s" FG_BLACK "...\n", pwd->pw_name); + puts(BG_BLACK FG_WHITE_BRIGHT); + + // Call the shell. char *_argv[] = { pwd->pw_shell, (char *)NULL }; if (execv(pwd->pw_shell, _argv) == -1) { - printf("%s: Failed to execute the shell.\n", argv[0]); - printf("%s: %s.\n", argv[0], strerror(errno)); + printf("login: Failed to execute the shell.\n"); + printf("login: %s.\n", strerror(errno)); return 1; } return 0; diff --git a/programs/man.c b/programs/man.c index b0887b1e..dc588a72 100644 --- a/programs/man.c +++ b/programs/man.c @@ -3,32 +3,67 @@ /// @copyright (c) 2014-2022 This file is distributed under the MIT License. /// See LICENSE.md for details. +#include +#include #include +#include #include #include -#include -#include int main(int argc, char *argv[]) { - int fd = open("/bin", O_RDONLY | O_DIRECTORY, 0); - if (fd == -1) { - printf("%s: cannot access '/bin': %s\n\n", argv[0], strerror(errno)); - return 1; + if (argc == 1) + { + int fd = open("/bin", O_RDONLY | O_DIRECTORY, 0); + if (fd == -1) + { + printf("%s: cannot access '/bin': %s\n\n", argv[0], strerror(errno)); + return 1; + } + dirent_t dent; + int per_line = 0; + while (getdents(fd, &dent, sizeof(dirent_t)) == sizeof(dirent_t)) + { + // Shows only regular files + if (dent.d_type == DT_REG) + { + printf("%10s ", dent.d_name); + if (++per_line == 6) + { + per_line = 0; + putchar('\n'); + } + } + } + putchar('\n'); + close(fd); } - dirent_t dent; - int per_line = 0; - while (getdents(fd, &dent, sizeof(dirent_t)) == sizeof(dirent_t)) { - // Shows only regular files - if(dent.d_type == DT_REG){ - printf("%10s ", dent.d_name); - if (++per_line == 6) { - per_line = 0; - putchar('\n'); + else if (argc == 2) + { + char filepath[PATH_MAX]; + strcpy(filepath, "/usr/share/man/"); + strcat(filepath, argv[1]); + strcat(filepath, ".man"); + int fd = open(filepath, O_RDONLY, 42); + if (fd < 0) + { + printf("%s: No manual entry for %s\n\n", argv[0], argv[1]); + } + else + { + // Prepare the buffer for reading the man file. + char buffer[BUFSIZ]; + // Put on the standard output the characters. + while (read(fd, buffer, BUFSIZ) > 0) + { + puts(buffer); } + // Close the file descriptor. + close(fd); + // Terminate with a pair of newlines. + putchar('\n'); + putchar('\n'); } } - putchar('\n'); - close(fd); return 0; } diff --git a/programs/shell.c b/programs/shell.c index 922e1321..a0605fa3 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -21,46 +21,13 @@ #include "limits.h" #include "sys/utsname.h" #include "ctype.h" +#include "ansi_colors.h" /// Maximum length of commands. #define CMD_LEN 32 /// Maximum lenght of the history. #define HISTORY_MAX 10 -/// @brief A set of colors. -#define FG_BLACK "\033[30m" -#define FG_RED "\033[31m" -#define FG_GREEN "\033[32m" -#define FG_YELLOW "\033[33m" -#define FG_BLUE "\033[34m" -#define FG_MAGENTA "\033[35m" -#define FG_CYAN "\033[36m" -#define FG_WHITE "\033[37m" -#define FG_BRIGHT_BLACK "\033[90m" -#define FG_BRIGHT_RED "\033[91m" -#define FG_BRIGHT_GREEN "\033[92m" -#define FG_BRIGHT_YELLOW "\033[93m" -#define FG_BRIGHT_BLUE "\033[94m" -#define FG_BRIGHT_MAGENTA "\033[95m" -#define FG_BRIGHT_CYAN "\033[96m" -#define FG_BRIGHT_WHITE "\033[97m" -#define BG_BLACK "\033[40m" -#define BG_RED "\033[41m" -#define BG_GREEN "\033[42m" -#define BG_YELLOW "\033[43m" -#define BG_BLUE "\033[44m" -#define BG_MAGENTA "\033[45m" -#define BG_CYAN "\033[46m" -#define BG_WHITE "\033[47m" -#define BG_BRIGHT_BLACK "\033[100m" -#define BG_BRIGHT_RED "\033[101m" -#define BG_BRIGHT_GREEN "\033[102m" -#define BG_BRIGHT_YELLOW "\033[103m" -#define BG_BRIGHT_BLUE "\033[104m" -#define BG_BRIGHT_MAGENTA "\033[105m" -#define BG_BRIGHT_CYAN "\033[106m" -#define BG_BRIGHT_WHITE "\033[107m" - // Required by `export` #define ENV_NORM 1 #define ENV_BRAK 2 @@ -188,7 +155,7 @@ static inline void __prompt_print() } else { HOSTNAME = buffer.nodename; } - printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BRIGHT_BLUE "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_BRIGHT_WHITE "%% ", + printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BLUE_BRIGHT "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_WHITE_BRIGHT "%% ", USER, HOSTNAME, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, CWD); } @@ -704,23 +671,6 @@ int main(int argc, char *argv[]) printf("Failed to set signal handler (%s).\n", SIGCHLD, strerror(errno)); return 1; } - // Clear the screen. - puts("\033[J"); - // Welcome the user. - puts(BG_WHITE FG_BLACK); - printf("Welcome " FG_RED "%s" FG_BLACK "...\n\n", USER); - puts(BG_BLACK FG_BRIGHT_WHITE); - - // Print /etc/motd if it exists - int motd_fd = open("/etc/motd", O_RDONLY, 0600); - if (motd_fd != -1){ - char buffer[256]; - - if(read(motd_fd, buffer, sizeof(char)*256) != -1){ - printf("%s \n", buffer); - } - close(motd_fd); - } // Move inside the home directory. __cd(0, NULL);