From 8f91a47aebe4154124ec7d54f5c71d167937e5e4 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 27 Oct 2018 16:43:03 +0200 Subject: [PATCH] Add some basic field width support to printf(). Use it to make "ls" output a bit better. Also sys$spawn now fails with EACCES if the path is not a file that's executable by the current uid/gid. --- AK/printf.cpp | 181 ++++++++++++++++++++++++++++++ Kernel/Task.cpp | 5 + Kernel/_fs_contents | Bin 1024000 -> 1024000 bytes Kernel/kprintf.cpp | 139 +---------------------- LibC/stdio.cpp | 140 +---------------------- Userland/ls.cpp | 7 +- VirtualFileSystem/FileHandle.h | 3 + VirtualFileSystem/InodeMetadata.h | 9 ++ 8 files changed, 212 insertions(+), 272 deletions(-) create mode 100644 AK/printf.cpp diff --git a/AK/printf.cpp b/AK/printf.cpp new file mode 100644 index 0000000000..5df39a8cfa --- /dev/null +++ b/AK/printf.cpp @@ -0,0 +1,181 @@ +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned int dword; + +inline size_t strlen(const char* str) +{ + size_t len = 0; + while (*(str++)) + ++len; + return len; +} + +static constexpr const char* h = "0123456789abcdef"; + +template +int printHex(PutChFunc putch, char*& bufptr, dword number, byte fields) +{ + int ret = 0; + byte shr_count = fields * 4; + while (shr_count) { + shr_count -= 4; + putch(bufptr, h[(number >> shr_count) & 0x0F]); + ++ret; + } + return ret; +} + +template +int printNumber(PutChFunc putch, char*& bufptr, dword number, bool leftPad, bool zeroPad, dword fieldWidth) +{ + dword divisor = 1000000000; + char ch; + char padding = 1; + char buf[16]; + char* p = buf; + + for (;;) { + ch = '0' + (number / divisor); + number %= divisor; + if (ch != '0') + padding = 0; + if (!padding || divisor == 1) + *(p++) = ch; + if (divisor == 1) + break; + divisor /= 10; + } + + size_t numlen = p - buf; + if (!fieldWidth) + fieldWidth = numlen; + if (!leftPad) { + for (unsigned i = 0; i < fieldWidth - numlen; ++i) { + putch(bufptr, zeroPad ? '0' : ' '); + } + } + for (unsigned i = 0; i < numlen; ++i) { + putch(bufptr, buf[i]); + } + if (leftPad) { + for (unsigned i = 0; i < fieldWidth - numlen; ++i) { + putch(bufptr, ' '); + } + } + + return fieldWidth; +} + +template +int printString(PutChFunc putch, char*& bufptr, const char* str, bool leftPad, dword fieldWidth) +{ + size_t len = strlen(str); + if (!fieldWidth) + fieldWidth = len; + if (!leftPad) { + for (unsigned i = 0; i < fieldWidth - len; ++i) + putch(bufptr, ' '); + } + for (unsigned i = 0; i < len; ++i) { + putch(bufptr, str[i]); + } + if (leftPad) { + for (unsigned i = 0; i < fieldWidth - len; ++i) + putch(bufptr, ' '); + } + return fieldWidth; +} + + +template +int printSignedNumber(PutChFunc putch, char*& bufptr, int number, bool leftPad, bool zeroPad, dword fieldWidth) +{ + if (number < 0) { + putch(bufptr, '-'); + return printNumber(putch, bufptr, 0 - number, leftPad, zeroPad, fieldWidth) + 1; + } + return printNumber(putch, bufptr, number, leftPad, zeroPad, fieldWidth); +} + +template +int printfInternal(PutChFunc putch, char* buffer, const char*& fmt, char*& ap) +{ + const char *p; + + int ret = 0; + char* bufptr = buffer; + + for (p = fmt; *p; ++p) { + bool leftPad = false; + bool zeroPad = false; + unsigned fieldWidth = 0; + if (*p == '%' && *(p + 1)) { +one_more: + ++p; + if (*p == ' ') { + leftPad = true; + if (*(p + 1)) + goto one_more; + } + if (!zeroPad && !fieldWidth && *p == '0') { + zeroPad = true; + if (*(p + 1)) + goto one_more; + } + if (*p >= '0' && *p <= '9') { + fieldWidth *= 10; + fieldWidth += *p - '0'; + if (*(p + 1)) + goto one_more; + } + switch( *p ) + { + case 's': + { + const char* sp = va_arg(ap, const char*); + ret += printString(putch, bufptr, sp ? sp : "(null)", leftPad, fieldWidth); + } + break; + + case 'd': + ret += printSignedNumber(putch, bufptr, va_arg(ap, int), leftPad, zeroPad, fieldWidth); + break; + + case 'u': + ret += printNumber(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth); + break; + + case 'x': + ret += printHex(putch, bufptr, va_arg(ap, dword), 8); + break; + + case 'w': + ret += printHex(putch, bufptr, va_arg(ap, int), 4); + break; + + case 'b': + ret += printHex(putch, bufptr, va_arg(ap, int), 2); + break; + + case 'c': + putch(bufptr, (char)va_arg(ap, int)); + ++ret; + break; + + case 'p': + putch(bufptr, '0'); + putch(bufptr, 'x'); + ret += 2; + ret += printHex(putch, bufptr, va_arg(ap, dword), 8); + break; + } + } + else { + putch(bufptr, *p); + ++ret; + } + } + return ret; +} + + diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 72293365c1..10326fe03d 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -230,6 +230,11 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren return nullptr; } + if (!handle->metadata().mayExecute(uid, gid)) { + error = -EACCES; + return nullptr; + } + auto elfData = handle->readEntireFile(); if (!elfData) { error = -EIO; // FIXME: Get a more detailed error from VFS. diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index 1adddde26b8f0b28d1a3698eec64c8ca3775aa32..93f5d7a1445af339dd5722edfee57cdc31cab5ee 100644 GIT binary patch delta 100621 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 delta 52914 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 f!Q^cVcokTdE9CGd7!*e-~;pU#Rbd&SUjd4 diff --git a/Kernel/kprintf.cpp b/Kernel/kprintf.cpp index b80fcc2e0b..463a3ce915 100644 --- a/Kernel/kprintf.cpp +++ b/Kernel/kprintf.cpp @@ -2,95 +2,18 @@ #include "Console.h" #include #include - -template static int printNumber(PutChFunc, char*&, dword); -template static int printHex(PutChFunc, char*&, dword, byte fields); -template static int printSignedNumber(PutChFunc, char*&, int); +#include static void console_putch(char*, char ch) { Console::the().write((byte*)&ch, 1); } -template -int kprintfInternal(PutChFunc putch, char* buffer, const char*& fmt, char*& ap) -{ - const char *p; - - int ret = 0; - char* bufptr = buffer; - - for (p = fmt; *p; ++p) { - if (*p == '%' && *(p + 1)) { - ++p; - switch( *p ) - { - case 's': - { - const char* sp = va_arg(ap, const char*); - //ASSERT(sp != nullptr); - if (!sp) { - putch(bufptr, '<'); - putch(bufptr, 'N'); - putch(bufptr, 'u'); - putch(bufptr, 'L'); - putch(bufptr, '>'); - ret += 5; - } else { - for (; *sp; ++sp) { - putch(bufptr, *sp); - ++ret; - } - } - } - break; - - case 'd': - ret += printSignedNumber(putch, bufptr, va_arg(ap, int)); - break; - - case 'u': - ret += printNumber(putch, bufptr, va_arg(ap, dword)); - break; - - case 'x': - ret += printHex(putch, bufptr, va_arg(ap, dword), 8); - break; - - case 'w': - ret += printHex(putch, bufptr, va_arg(ap, int), 4); - break; - - case 'b': - ret += printHex(putch, bufptr, va_arg(ap, int), 2); - break; - - case 'c': - putch(bufptr, (char)va_arg(ap, int)); - ++ret; - break; - - case 'p': - putch(bufptr, '0'); - putch(bufptr, 'x'); - ret += 2; - ret += printHex(putch, bufptr, va_arg(ap, dword), 8); - break; - } - } - else { - putch(bufptr, *p); - ++ret; - } - } - return ret; -} - int kprintf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); - int ret = kprintfInternal(console_putch, nullptr, fmt, ap); + int ret = printfInternal(console_putch, nullptr, fmt, ap); va_end(ap); return ret; } @@ -104,64 +27,8 @@ int ksprintf(char* buffer, const char* fmt, ...) { va_list ap; va_start(ap, fmt); - int ret = kprintfInternal(buffer_putch, buffer, fmt, ap); + int ret = printfInternal(buffer_putch, buffer, fmt, ap); buffer[ret] = '\0'; va_end(ap); return ret; } - -template -int printHex(PutChFunc putch, char*& bufptr, dword number, byte fields) -{ - static const char h[] = { - '0','1','2','3','4','5','6','7', - '8','9','a','b','c','d','e','f' - }; - - int ret = 0; - byte shr_count = fields * 4; - while (shr_count) { - shr_count -= 4; - putch(bufptr, h[(number >> shr_count) & 0x0F]); - ++ret; - } - return ret; -} - -template -int printNumber(PutChFunc putch, char*& bufptr, dword number) -{ - dword divisor = 1000000000; - char ch; - char padding = 1; - int ret = 0; - - for (;;) { - ch = '0' + (number / divisor); - number %= divisor; - - if (ch != '0') - padding = 0; - - if (!padding || divisor == 1) { - putch(bufptr, ch); - ++ret; - } - - if (divisor == 1) - break; - divisor /= 10; - } - return ret; -} - -template -static int printSignedNumber(PutChFunc putch, char*& bufptr, int number) -{ - if (number < 0) { - putch(bufptr, '-'); - return printNumber(putch, bufptr, 0 - number) + 1; - } - return printNumber(putch, bufptr, number); -} - diff --git a/LibC/stdio.cpp b/LibC/stdio.cpp index 3448659fab..ed0a169ab8 100644 --- a/LibC/stdio.cpp +++ b/LibC/stdio.cpp @@ -4,140 +4,7 @@ #include "string.h" #include "errno.h" #include - -#define ALWAYS_INLINE __attribute__ ((always_inline)) - -static constexpr const char* h = "0123456789abcdef"; - -template -ALWAYS_INLINE int printHex(PutChFunc putch, char*& bufptr, dword number, byte fields) -{ - int ret = 0; - byte shr_count = fields * 4; - while (shr_count) { - shr_count -= 4; - putch(bufptr, h[(number >> shr_count) & 0x0F]); - ++ret; - } - return ret; -} - -template -ALWAYS_INLINE int printNumber(PutChFunc putch, char*& bufptr, dword number) -{ - dword divisor = 1000000000; - char ch; - char padding = 1; - int ret = 0; - - for (;;) { - ch = '0' + (number / divisor); - number %= divisor; - - if (ch != '0') - padding = 0; - - if (!padding || divisor == 1) { - putch(bufptr, ch); - ++ret; - } - - if (divisor == 1) - break; - divisor /= 10; - } - return ret; -} - -template -ALWAYS_INLINE int printSignedNumber(PutChFunc putch, char*& bufptr, int number) -{ - if (number < 0) { - putch(bufptr, '-'); - return printNumber(putch, bufptr, 0 - number) + 1; - } - return printNumber(putch, bufptr, number); -} - -static void sys_putch(char*, char ch) -{ - Syscall::invoke(Syscall::PutCharacter, ch); -} - -template -int printfInternal(PutChFunc putch, char* buffer, const char*& fmt, char*& ap) -{ - const char *p; - - int ret = 0; - char* bufptr = buffer; - - for (p = fmt; *p; ++p) { - if (*p == '%' && *(p + 1)) { - ++p; - switch( *p ) - { - case 's': - { - const char* sp = va_arg(ap, const char*); - //ASSERT(sp != nullptr); - if (!sp) { - putch(bufptr, '('); - putch(bufptr, 'n'); - putch(bufptr, 'u'); - putch(bufptr, 'l'); - putch(bufptr, 'l'); - putch(bufptr, ')'); - ret += 6; - } else { - for (; *sp; ++sp) { - putch(bufptr, *sp); - ++ret; - } - } - } - break; - - case 'd': - ret += printSignedNumber(putch, bufptr, va_arg(ap, int)); - break; - - case 'u': - ret += printNumber(putch, bufptr, va_arg(ap, dword)); - break; - - case 'x': - ret += printHex(putch, bufptr, va_arg(ap, dword), 8); - break; - - case 'w': - ret += printHex(putch, bufptr, va_arg(ap, int), 4); - break; - - case 'b': - ret += printHex(putch, bufptr, va_arg(ap, int), 2); - break; - - case 'c': - putch(bufptr, (char)va_arg(ap, int)); - ++ret; - break; - - case 'p': - putch(bufptr, '0'); - putch(bufptr, 'x'); - ret += 2; - ret += printHex(putch, bufptr, va_arg(ap, dword), 8); - break; - } - } - else { - putch(bufptr, *p); - ++ret; - } - } - return ret; -} +#include extern "C" { @@ -147,6 +14,11 @@ int putchar(int ch) return (byte)ch; } +static void sys_putch(char*, char ch) +{ + Syscall::invoke(Syscall::PutCharacter, ch); +} + int printf(const char* fmt, ...) { va_list ap; diff --git a/Userland/ls.cpp b/Userland/ls.cpp index b37b3f07d3..3af8252608 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -22,6 +22,8 @@ int main(int c, char** v) return 2; } + printf("%08u ", de->d_ino); + if (S_ISDIR(st.st_mode)) printf("d"); else if (S_ISLNK(st.st_mode)) @@ -53,8 +55,9 @@ int main(int c, char** v) else printf("%c", st.st_mode & S_IXOTH ? 'x' : '-'); - printf(" i:%x ", de->d_ino); - printf(" %x ", st.st_size); + printf(" %4u %4u", st.st_uid, st.st_gid); + + printf(" %10u ", st.st_size); printf("%s%c", de->d_name, S_ISDIR(st.st_mode) ? '/' : ' '); printf("\n"); } diff --git a/VirtualFileSystem/FileHandle.h b/VirtualFileSystem/FileHandle.h index cc3cc4ee0a..9e8407f002 100644 --- a/VirtualFileSystem/FileHandle.h +++ b/VirtualFileSystem/FileHandle.h @@ -1,6 +1,7 @@ #pragma once #include "VirtualFileSystem.h" +#include "InodeMetadata.h" #include class FileHandle { @@ -22,6 +23,8 @@ public: bool isDirectory() const; + InodeMetadata metadata() const { return m_vnode->metadata(); } + VirtualFileSystem::Node* vnode() { return m_vnode.ptr(); } #ifdef SERENITY diff --git a/VirtualFileSystem/InodeMetadata.h b/VirtualFileSystem/InodeMetadata.h index e5d35b6b93..9d31145b54 100644 --- a/VirtualFileSystem/InodeMetadata.h +++ b/VirtualFileSystem/InodeMetadata.h @@ -17,6 +17,15 @@ inline bool isSetGID(Unix::mode_t mode) { return mode & 02000; } struct InodeMetadata { bool isValid() const { return inode.isValid(); } + bool mayExecute(uid_t u, gid_t g) const + { + if (uid == u) + return mode & 0100; + if (gid == g) + return mode & 0010; + return mode & 0001; + } + bool isDirectory() const { return ::isDirectory(mode); } bool isCharacterDevice() const { return ::isCharacterDevice(mode); } bool isBlockDevice() const { return ::isBlockDevice(mode); }