/*
* The `cd' shell.
* Just has cd and lc.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
char *pwd;
char *root = "/";
void
usage(void)
{
fprint(2, "usage: cdsh [-r root]\n");
exits("usage");
}
int
system(char *cmd)
{
int pid;
if((pid = fork()) < 0)
return -1;
if(pid == 0) {
dup(2, 1);
execl("/bin/rc", "rc", "-c", cmd, nil);
exits("exec");
}
waitpid();
return 0;
}
int
cd(char *s)
{
char *newpwd;
int l;
if(s[0] == '/') {
cleanname(s);
newpwd = strdup(s);
} else {
l = strlen(pwd)+1+strlen(s)+1+50; /* 50 = crud for unicode mistakes */
newpwd = malloc(l);
snprint(newpwd, l, "%s/%s", pwd, s);
cleanname(newpwd);
assert(newpwd[0] == '/');
}
if(chdir(root) < 0 || (newpwd[1] != '\0' && chdir(newpwd+1) < 0)) {
chdir(root);
chdir(pwd+1);
free(newpwd);
return -1;
} else {
free(pwd);
pwd = newpwd;
return 0;
}
}
void
main(int argc, char **argv)
{
char *p;
Biobuf bin;
char *f[2];
int nf;
ARGBEGIN{
case 'r':
root = ARGF();
if(root == nil)
usage();
if(root[0] != '/') {
fprint(2, "root must be rooted\n");
exits("root");
}
break;
default:
usage();
}ARGEND;
if(argc != 0)
usage();
cleanname(root);
if(cd("/") < 0) {
fprint(2, "cannot cd %s: %r\n", root);
exits("root");
}
Binit(&bin, 0, OREAD);
while(fprint(2, "%s%% ", pwd), (p = Brdline(&bin, '\n'))) {
p[Blinelen(&bin)-1] = '\0';
nf = tokenize(p, f, nelem(f));
if(nf < 1)
continue;
if(strcmp(f[0], "exit") == 0)
break;
if(strcmp(f[0], "lc") == 0) {
if(nf == 1) {
if(system("/bin/lc") < 0)
fprint(2, "lc: %r\n");
} else if(nf == 2) {
if(strpbrk(p, "'`{}^@$#&()|\\;><"))
fprint(2, "no shell characters allowed\n");
else {
p = f[1];
*--p = ' ';
*--p = 'c';
*--p = 'l';
if(system(p) < 0)
fprint(2, "lc: %r\n");
}
}
continue;
}
if(strcmp(f[0], "cd") == 0) {
if(nf < 2)
fprint(2, "usage: cd dir\n");
else if(cd(f[1]) < 0)
fprint(2, "cd: %r\n");
continue;
}
fprint(2, "commands are cd, lc, and exit\n");
}
print("%s\n", pwd);
}
|