syscall: utility overhaul
Following is a list of functional changes: * The -o flag outputs the entire buffer to the length returned by the syscall, or, in case of fd2path(2) and errstr(2), to '\0'. * The -x flag is removed; the above makes it possible to pipe into xd(1) to get the same result. * The -s flag uses dirfmt(2) to format the stat message, instead of trying to imitate ls(1). * Stderr reports are normalized and made easier to parse. The code also suffered a number of stylistic changes.
This commit is contained in:
parent
e3166b4fe8
commit
aa7c8cac11
3 changed files with 139 additions and 174 deletions
|
@ -4,7 +4,7 @@ syscall \- test a system call
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B syscall
|
.B syscall
|
||||||
[
|
[
|
||||||
.B -osx
|
.B -os
|
||||||
]
|
]
|
||||||
.I entry
|
.I entry
|
||||||
[
|
[
|
||||||
|
@ -15,39 +15,44 @@ syscall \- test a system call
|
||||||
invokes the system call
|
invokes the system call
|
||||||
.I entry
|
.I entry
|
||||||
with the given arguments.
|
with the given arguments.
|
||||||
(Some functions, such as
|
The return value is printed.
|
||||||
.I write
|
If an error occured, the error string is also printed.
|
||||||
and
|
|
||||||
.IR read (2),
|
|
||||||
although not strictly system calls, are valid
|
|
||||||
.IR entries .)
|
|
||||||
It prints the return value and the error string, if there was an error.
|
|
||||||
An argument is either an integer constant as in C (its value is passed),
|
|
||||||
a string (its address is passed),
|
|
||||||
or the literal
|
|
||||||
.B buf
|
|
||||||
(a pointer to a 1MB buffer is passed).
|
|
||||||
.PP
|
.PP
|
||||||
If
|
For convenience,
|
||||||
.B -o
|
.IR write (2)
|
||||||
is given, the contents of the 1MB buffer are printed as a zero-terminated string
|
|
||||||
after the system call is done.
|
|
||||||
The
|
|
||||||
.B -x
|
|
||||||
and
|
and
|
||||||
|
.IR read (2)
|
||||||
|
are included in
|
||||||
|
.IR entries ,
|
||||||
|
even though they are not strictly syscalls.
|
||||||
|
.PP
|
||||||
|
.I Syscall
|
||||||
|
arguments are integer constants, strings, or the literal
|
||||||
|
.BR buf .
|
||||||
|
The literal
|
||||||
|
.B buf
|
||||||
|
refers to a writable 1 megabyte buffer.
|
||||||
|
Strings and
|
||||||
|
.B buf
|
||||||
|
are passed as pointers.
|
||||||
|
Integers are passed as values.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B -o
|
||||||
|
option prints contents of the 1MB buffer.
|
||||||
|
For
|
||||||
|
.IR errstr (2)
|
||||||
|
and
|
||||||
|
.IR fd2path (2),
|
||||||
|
the buffer is treated as a 0-terminated string.
|
||||||
|
For other calls, the number of bytes printed is
|
||||||
|
determined by the system call's return value.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
.B -s
|
.B -s
|
||||||
options are similar, but
|
option is similar, but interprets the data as a
|
||||||
.B -x
|
|
||||||
formats the data as hexadecimal bytes, while
|
|
||||||
.B -s
|
|
||||||
interprets the data as a
|
|
||||||
.IR stat (5)
|
.IR stat (5)
|
||||||
message and formats it similar to the style of
|
message and formats it to standard output.
|
||||||
.B ls
|
|
||||||
.B -lqm
|
|
||||||
(see
|
|
||||||
.IR ls (1)),
|
|
||||||
with extra detail about the modify and access times.
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
Write a string to standard output:
|
Write a string to standard output:
|
||||||
.IP
|
.IP
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
</$objtype/mkfile
|
</$objtype/mkfile
|
||||||
CFLAGS=-I/sys/src/libc/9syscall $CFLAGS
|
|
||||||
|
|
||||||
TARG=syscall
|
TARG=syscall
|
||||||
OFILES=syscall.$O\
|
OFILES=syscall.$O\
|
||||||
|
@ -18,12 +17,24 @@ UPDATE=\
|
||||||
SYSCALL=/sys/src/libc/9syscall/sys.h
|
SYSCALL=/sys/src/libc/9syscall/sys.h
|
||||||
|
|
||||||
tab.h: $SYSCALL
|
tab.h: $SYSCALL
|
||||||
sed '/#define._X[0-9_]/d;
|
awk '
|
||||||
/#define.NSYSCALL/d;
|
BEGIN{ print "enum{" }
|
||||||
s/#define.([A-Z0-9_][A-Z0-9_]*).*/ "\1", (int(*)(...))\1,/' $SYSCALL |
|
{ printf "%s, ", $2 }
|
||||||
tr A-Z a-z > tab.h
|
END{
|
||||||
echo ' "read", (int(*)(...))read,' >> tab.h
|
print "READ, WRITE, NTAB"
|
||||||
echo ' "write", (int(*)(...))write,' >> tab.h
|
print "};"
|
||||||
|
}' <$SYSCALL >$target
|
||||||
|
awk '
|
||||||
|
BEGIN{ print "struct Call tab[] = {" }
|
||||||
|
{ printf "[%s] \"%s\", (int(*)(...))%s,\n",
|
||||||
|
$2, tolower($2), tolower($2)
|
||||||
|
}
|
||||||
|
END{
|
||||||
|
print "[READ] \"read\", (int(*)(...))read,"
|
||||||
|
print "[WRITE] \"write\", (int(*)(...))write,"
|
||||||
|
print "[NTAB] nil, 0"
|
||||||
|
print "};"
|
||||||
|
}' <$SYSCALL >>$target
|
||||||
|
|
||||||
clean:V:
|
clean:V:
|
||||||
rm -f *.[$OS] [$OS].out $TARG $HFILES
|
rm -f *.[$OS] [$OS].out $TARG $HFILES
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <sys.h>
|
|
||||||
#include <fcall.h>
|
#include <fcall.h>
|
||||||
|
|
||||||
char buf[1048576];
|
char buf[1048576];
|
||||||
#define NARG 5
|
enum{ NARG = 5 };
|
||||||
uintptr arg[NARG];
|
uintptr arg[NARG];
|
||||||
|
|
||||||
/* system calls not defined in libc.h */
|
/* system calls not defined in libc.h */
|
||||||
|
@ -28,144 +27,17 @@ int _mount(int, char*, int, char*);
|
||||||
int _wait(void*);
|
int _wait(void*);
|
||||||
int _nsec(vlong*);
|
int _nsec(vlong*);
|
||||||
|
|
||||||
struct{
|
struct Call{
|
||||||
char *name;
|
char *name;
|
||||||
int (*func)(...);
|
int (*func)(...);
|
||||||
}tab[]={
|
|
||||||
#include "tab.h"
|
|
||||||
0, 0
|
|
||||||
};
|
};
|
||||||
|
#include "tab.h"
|
||||||
uintptr parse(char *);
|
|
||||||
void catch(void*, char*);
|
|
||||||
|
|
||||||
char*
|
|
||||||
xctime(ulong t)
|
|
||||||
{
|
|
||||||
char *buf, *s;
|
|
||||||
|
|
||||||
s = ctime(t);
|
|
||||||
s[strlen(s)-1] = '\0'; /* remove newline */
|
|
||||||
buf = malloc(512);
|
|
||||||
if(buf == nil)
|
|
||||||
sysfatal("can't malloc: %r");
|
|
||||||
snprint(buf, 512, "%s (%lud)", s, t);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char*
|
|
||||||
lstime(long l)
|
|
||||||
{
|
|
||||||
static char buf[32];
|
|
||||||
char *t;
|
|
||||||
long clk;
|
|
||||||
|
|
||||||
clk = time(0);
|
|
||||||
t = ctime(l);
|
|
||||||
/* 6 months in the past or a day in the future */
|
|
||||||
if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
|
|
||||||
memmove(buf, t+4, 7); /* month and day */
|
|
||||||
memmove(buf+7, t+23, 5); /* year */
|
|
||||||
}else
|
|
||||||
memmove(buf, t+4, 12); /* skip day of week */
|
|
||||||
buf[12] = 0;
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
main(int argc, char *argv[])
|
usage(void)
|
||||||
{
|
{
|
||||||
int i, j, c;
|
fprint(2, "usage: %s [-os] entry [arg ...]\n", argv0);
|
||||||
int oflag, xflag, sflag;
|
exits("usage");
|
||||||
vlong r;
|
|
||||||
Dir d;
|
|
||||||
char strs[1024];
|
|
||||||
char ebuf[1024];
|
|
||||||
|
|
||||||
fmtinstall('M', dirmodefmt);
|
|
||||||
|
|
||||||
oflag = 0;
|
|
||||||
xflag = 0;
|
|
||||||
sflag = 0;
|
|
||||||
ARGBEGIN{
|
|
||||||
case 'o':
|
|
||||||
oflag++;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
sflag++;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
xflag++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto Usage;
|
|
||||||
}ARGEND
|
|
||||||
if(argc<1 || argc>1+NARG){
|
|
||||||
Usage:
|
|
||||||
fprint(2, "usage: syscall [-ox] entry [args; buf==1MB buffer]\n");
|
|
||||||
fprint(2, "\tsyscall write 1 hello 5\n");
|
|
||||||
fprint(2, "\tsyscall -o errstr buf 1024\n");
|
|
||||||
fprint(2, "\tsyscall -[xs] stat file buf 1024\n");
|
|
||||||
exits("usage");
|
|
||||||
}
|
|
||||||
for(i=1; i<argc; i++)
|
|
||||||
arg[i-1] = parse(argv[i]);
|
|
||||||
notify(catch);
|
|
||||||
for(i=0; tab[i].name; i++)
|
|
||||||
if(strcmp(tab[i].name, argv[0])==0){
|
|
||||||
/* special case for seek, pread, pwrite; vlongs are problematic */
|
|
||||||
if(strcmp(argv[0], "seek") == 0)
|
|
||||||
r=seek(arg[0], strtoll(argv[2], 0, 0), arg[2]);
|
|
||||||
else if(strcmp(argv[0], "pread") == 0)
|
|
||||||
r=pread(arg[0], (void*)arg[1], arg[2], strtoll(argv[4], 0, 0));
|
|
||||||
else if(strcmp(argv[0], "pwrite") == 0)
|
|
||||||
r=pwrite(arg[0], (void*)arg[1], arg[2], strtoll(argv[4], 0, 0));
|
|
||||||
else
|
|
||||||
r=(*tab[i].func)(arg[0], arg[1], arg[2], arg[3], arg[4]);
|
|
||||||
if(r == -1){
|
|
||||||
errstr(ebuf, sizeof ebuf);
|
|
||||||
fprint(2, "syscall: return %lld, error:%s\n", r, ebuf);
|
|
||||||
}else{
|
|
||||||
ebuf[0] = 0;
|
|
||||||
fprint(2, "syscall: return %lld, no error\n", r);
|
|
||||||
}
|
|
||||||
if(oflag)
|
|
||||||
print("%s", buf);
|
|
||||||
if(xflag){
|
|
||||||
for(j=0; j<r; j++){
|
|
||||||
if(j%16 == 0)
|
|
||||||
print("%.4x\t", j);
|
|
||||||
c = buf[j]&0xFF;
|
|
||||||
if('!'<=c && c<='~')
|
|
||||||
print(" %c ", c);
|
|
||||||
else
|
|
||||||
print("%.2ux ", c);
|
|
||||||
if(j%16 == 15)
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
if(sflag && r > 0){
|
|
||||||
r = convM2D((uchar*)buf, r, &d, strs);
|
|
||||||
if(r <= BIT16SZ)
|
|
||||||
print("short stat message\n");
|
|
||||||
else{
|
|
||||||
print("[%s] ", d.muid);
|
|
||||||
print("(%.16llux %lud %.2ux) ", d.qid.path, d.qid.vers, d.qid.type);
|
|
||||||
print("%M (%luo) ", d.mode, d.mode);
|
|
||||||
print("%c %d ", d.type, d.dev);
|
|
||||||
print("%s %s ", d.uid, d.gid);
|
|
||||||
print("%lld ", d.length);
|
|
||||||
print("%s ", lstime(d.mtime));
|
|
||||||
print("%s\n", d.name);
|
|
||||||
print("\tmtime: %s\n\tatime: %s\n", xctime(d.mtime), xctime(d.atime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exits(ebuf);
|
|
||||||
}
|
|
||||||
fprint(2, "syscall: %s not known\n", argv[0]);
|
|
||||||
exits("unknown");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr
|
uintptr
|
||||||
|
@ -174,18 +46,95 @@ parse(char *s)
|
||||||
char *t;
|
char *t;
|
||||||
uintptr l;
|
uintptr l;
|
||||||
|
|
||||||
if(strcmp(s, "buf") == 0)
|
if(strncmp(s, "buf", 3) == 0)
|
||||||
return (uintptr)buf;
|
return (uintptr)buf;
|
||||||
|
|
||||||
l = strtoull(s, &t, 0);
|
l = strtoull(s, &t, 0);
|
||||||
if(t>s && *t==0)
|
if(t > s && *t == 0)
|
||||||
return l;
|
return l;
|
||||||
|
|
||||||
return (uintptr)s;
|
return (uintptr)s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
catch(void *, char *msg)
|
catch(void *, char *msg)
|
||||||
{
|
{
|
||||||
fprint(2, "syscall: received note='%s'\n", msg);
|
fprint(2, "syscall: received note: %s\n", msg);
|
||||||
noted(NDFLT);
|
noted(NDFLT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int oflag, sflag;
|
||||||
|
vlong r, nbuf;
|
||||||
|
Dir d;
|
||||||
|
char strs[1024];
|
||||||
|
char ebuf[ERRMAX];
|
||||||
|
|
||||||
|
fmtinstall('D', dirfmt);
|
||||||
|
|
||||||
|
oflag = 0;
|
||||||
|
sflag = 0;
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'o':
|
||||||
|
oflag++;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
if(argc < 1 || argc > 1+NARG)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++)
|
||||||
|
arg[i-1] = parse(argv[i]);
|
||||||
|
for(i = 0; tab[i].name; i++)
|
||||||
|
if(strcmp(tab[i].name, argv[0]) == 0)
|
||||||
|
break;
|
||||||
|
if(i == NTAB){
|
||||||
|
fprint(2, "syscall: %s not known\n", argv[0]);
|
||||||
|
exits("unknown");
|
||||||
|
}
|
||||||
|
notify(catch);
|
||||||
|
/* special case for seek, pread, pwrite; vlongs are problematic */
|
||||||
|
switch(i){
|
||||||
|
default:
|
||||||
|
r = (*tab[i].func)(arg[0], arg[1], arg[2], arg[3], arg[4]);
|
||||||
|
break;
|
||||||
|
case SEEK:
|
||||||
|
r = seek(arg[0], strtoll(argv[2], 0, 0), arg[2]);
|
||||||
|
break;
|
||||||
|
case PREAD:
|
||||||
|
r = pread(arg[0], (void*)arg[1], arg[2], strtoll(argv[4], 0, 0));
|
||||||
|
break;
|
||||||
|
case PWRITE:
|
||||||
|
r = pwrite(arg[0], (void*)arg[1], arg[2], strtoll(argv[4], 0, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(r == -1){
|
||||||
|
errstr(ebuf, sizeof ebuf);
|
||||||
|
fprint(2, "syscall: return: %lld error: %s\n", r, ebuf);
|
||||||
|
exits(ebuf);
|
||||||
|
}
|
||||||
|
fprint(2, "syscall: return: %lld\n", r);
|
||||||
|
if(oflag){
|
||||||
|
nbuf = r;
|
||||||
|
switch(i){
|
||||||
|
case _ERRSTR: case ERRSTR: case FD2PATH:
|
||||||
|
nbuf = strlen(buf);
|
||||||
|
}
|
||||||
|
if(write(1, buf, nbuf) != nbuf)
|
||||||
|
sysfatal("write: %r");
|
||||||
|
}else if(sflag){
|
||||||
|
r = convM2D((uchar*)buf, r, &d, strs);
|
||||||
|
if(r <= BIT16SZ)
|
||||||
|
print("short stat message\n");
|
||||||
|
else
|
||||||
|
print("%D\n", &d);
|
||||||
|
}
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue