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.
This commit is contained in:
Andreas Kling 2018-10-27 16:43:03 +02:00
parent de2fb183cc
commit 8f91a47aeb
Notes: sideshowbarker 2024-07-19 18:37:32 +09:00
8 changed files with 212 additions and 272 deletions

181
AK/printf.cpp Normal file
View file

@ -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<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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;
}

View file

@ -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.

Binary file not shown.

View file

@ -2,95 +2,18 @@
#include "Console.h"
#include <stdarg.h>
#include <AK/Types.h>
template<typename PutChFunc> static int printNumber(PutChFunc, char*&, dword);
template<typename PutChFunc> static int printHex(PutChFunc, char*&, dword, byte fields);
template<typename PutChFunc> static int printSignedNumber(PutChFunc, char*&, int);
#include <AK/printf.cpp>
static void console_putch(char*, char ch)
{
Console::the().write((byte*)&ch, 1);
}
template<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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);
}

View file

@ -4,140 +4,7 @@
#include "string.h"
#include "errno.h"
#include <Kernel/Syscall.h>
#define ALWAYS_INLINE __attribute__ ((always_inline))
static constexpr const char* h = "0123456789abcdef";
template<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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<typename PutChFunc>
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 <AK/printf.cpp>
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;

View file

@ -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");
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "VirtualFileSystem.h"
#include "InodeMetadata.h"
#include <AK/ByteBuffer.h>
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

View file

@ -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); }