Implement isatty on xv6
Problem #
This bug happens when we try to run shell commands from a file:
// xargstest.sh
mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello
It will print out $
for all commands:
$ sh < xargstest.sh
$ $ $ $ $ $ hello
hello
hello
$ $
The problem is that we need to determine where the input comes from.
If it comes from terminal, the program should print out $
. If it
comes from file, the program should not print out $
.
isatty #
isatty
is a system call that telling us whether the file descriptor comes from terminal or not.
int main()
{
if(isatty(0)){
printf("0 is device\n");
} else {
printf("0 is file\n");
}
exit(0);
}
After writing some tests, we can see that when isatty
is false when we send commands to stdin
by
file redirection.
$ ./main
0 is device
$ ./main < input.txt
0 is file
Therefore, we need to implement isatty
on xv6 to support this feature. The logic here is simple
and not be tested for every scenario.
// kernel/sysfile.c
uint64
sys_isatty(void)
{
int fd;
struct file *f;
if(argfd(0, &fd, &f) < 0){
return -1;
}
return f->type == FD_DEVICE;
}
Finally, we modify user/sh.c
and only print out $
when commands come from terminal.
// user/sh.c
int
getcmd(char *buf, int nbuf)
{
if(isatty(0)){
fprintf(2, "$ ");
}
memset(buf, 0, nbuf);
gets(buf, nbuf);
if(buf[0] == 0) // EOF
return -1;
return 0;
}
Test #
$ sh < xargstest.sh
hello
hello
hello