start getting commands working again, and cleanup some old io workarounds

This commit is contained in:
Lisa Milne 2023-11-26 12:18:48 +10:00
parent b34d9590cb
commit 7ac6f677be
3 changed files with 196 additions and 125 deletions

View file

@ -2,11 +2,12 @@ clite.commands.data = function() {
// insert commands below this line
clite.commands.load('help',function(args,env,io) {
var stdio = io.include('stdio');
if (args.length > 1) {
// TODO: implement command help lookup
io.write('help with arguments is a work in progress');
stdio.printf('help with arguments is a work in progress');
}
io.write(`
stdio.printf(`
Welcome to CLIte (pronounced like 'site' with an added L).
Various unix-like commands are available for navigating the CLIte shell:
@ -38,7 +39,7 @@ clite.commands.load('ls',function(args,env,io) {
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
function help() {
io.write(`
stdio.printf(`
ls - list directory contents
Usage: ls [OPTION] [FILE]
@ -54,12 +55,12 @@ Options:
var d = stdio.readAll(fd);
if (!d)
d = '?';
io.write(st.perms+'\t'+st.uid+'\t'+st.gid+'\t'+st.name+' -> '+d);
stdio.printf(st.perms+'\t'+st.uid+'\t'+st.gid+'\t'+st.name+' -> '+d);
}else{
io.write(st.perms+'\t'+st.uid+'\t'+st.gid+'\t'+st.name);
stdio.printf(st.perms+'\t'+st.uid+'\t'+st.gid+'\t'+st.name);
}
}else{
io.write(st.name);
stdio.printf(st.name);
}
}
@ -75,7 +76,7 @@ Options:
long = true;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else{
@ -88,10 +89,10 @@ Options:
dirs.forEach(function(dir,index) {
if (dirs.length > 1)
io.write(dir+':');
stdio.printf(dir+':');
var fd = stdio.open(dir,false);
if (!fd) {
io.error('cannot open directory: '+dir);
stdio.write(io.stderr,'cannot open directory: '+dir);
return;
}
var st = stdio.fstat(fd);
@ -104,13 +105,13 @@ Options:
while ((e = stdio.read(fd)) != null) {
var efd = stdio.open(dir+'/'+e,false,true);
if (!efd) {
io.error('cannot read contents: '+dir);
stdio.write(io.stderr,'cannot read contents: '+dir);
break;
}
var est = stdio.fstat(efd);
if (!est) {
stdio.close(efd);
io.error('cannot read contents: '+dir);
stdio.write(io.stderr,'cannot read content: '+dir);
break;
}
writeNodeData(est,efd);
@ -125,18 +126,20 @@ Options:
clite.commands.load('cat',function(args,env,io) {
var files = [];
var download = false;
var remote = true;
var pending = 0;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
function help() {
io.write(`
stdio.printf(`
cat - concatenate files and print to std output or local file
Usage: cat [OPTION] <FILE> [FILE]
Options:
-? Print this help information
-d Download the file data, instead of printing it
-l Only display files if remote data is loaded
`);
}
@ -151,8 +154,11 @@ Options:
case 'd':
download = true;
break;
case 'l':
remote = false;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else{
@ -164,14 +170,28 @@ Options:
return 1;
pending = files.length;
// check if we're on a webserver
if (!remote) {
var u = stdlib.uname();
if (u && u.hostname != 'localhost')
remote = true;
}
function fcb(fd) {
var st = stdio.fstat(fd);
// check if it's a directory or link
if (!st || st.type == stdio.types.FT_DIR || st.type == stdio.types.FT_LINK) {
if (
!st
|| st.type == stdio.types.FT_DIR
|| st.type == stdio.types.FT_LINK
|| st.type == stdio.types.FT_BINARY
|| st.type == stdio.types.FT_UNKOWN
|| st.type == stdio.types.FT_IMAGE
) {
if (st) {
io.error('not a normal file: '+st.name);
stdio.write(io.stderr,'not a normal file: '+st.name);
}else{
io.error('not a normal file');
stdio.write(io.stderr,'not a normal file');
}
}else{
var d = stdio.readAll(fd);
@ -182,10 +202,10 @@ Options:
stdio.write(ld,{name:st.name,data:d});
stdio.close(ld);
}else{
io.error('can not write to local device');
stdio.write(io.stderr,'can not write to local device');
}
}else{
io.write(d);
stdio.printf(d);
}
}
}
@ -198,14 +218,23 @@ Options:
files.forEach(function(file,index) {
var st = stdio.stat(file);
// check if it's a directory or link
if (!st || st.type == stdio.types.FT_DIR || st.type == stdio.types.FT_LINK) {
io.error('not a normal file: '+file);
if (
!st
|| st.type == stdio.types.FT_DIR
|| st.type == stdio.types.FT_LINK
|| st.type == stdio.types.FT_BINARY
|| st.type == stdio.types.FT_UNKOWN
|| st.type == stdio.types.FT_IMAGE
) {
stdio.write(io.stderr,'not a normal file: '+file);
pending--;
return;
}
if (!remote && st.type == stdio.types.FT_REMOTE)
return;
var fd = stdio.open(file,fcb);
if (!fd) {
io.error('cannot open file: '+file);
stdio.write(io.stderr,'cannot open file: '+file);
pending--;
return;
}
@ -222,7 +251,7 @@ clite.commands.load('touch',function(args,env,io) {
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
function help() {
io.write(`
stdio.printf(`
touch - create a new empty file
Usage: touch [OPTION] <FILE>
@ -240,24 +269,24 @@ Options:
return 0;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else if (file == null) {
file = stdlib.resolvePath(args[i],false);
}else{
io.error('unknown argument: '+args[i]);
stdio.write(io.stderr,'unknown argument: '+args[i]);
}
}
if (file == null) {
io.error('no file specified');
stdio.write(io.stderr,'no file specified');
return 1;
}
function loadRemote(fd) {
if (!fd) {
io.error('unable to create file: '+file);
stdio.write(io.stderr,'unable to create file: '+file);
io.exit(1);
return;
}
@ -279,7 +308,7 @@ clite.commands.load('less',function(args,env,io) {
var file = null;
function help() {
io.write(`
stdio.printf(`
less - text file viewer
Usage: less [OPTION] <FILE>
@ -297,18 +326,18 @@ Options:
return 0;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else if (file == null) {
file = stdlib.resolvePath(args[i],false);
}else{
io.error('unknown argument: '+args[i]);
stdio.write(io.stderr,'unknown argument: '+args[i]);
}
}
if (file == null) {
io.error('no file specified');
stdio.write(io.stderr,'no file specified');
return 1;
}
@ -329,13 +358,13 @@ Options:
function prepFile(fd) {
if (!fd) {
io.error('could not open file: '+file);
stdio.write(io.stderr,'could not open file: '+file);
io.exit(1);
return;
}
var st = stdio.fstat(fd);
if ( !st || (st.type != stdio.types.FT_TEXT && st.type != stdio.types.FT_SCRIPT)) {
io.error('can not read files of this type');
stdio.write(io.stderr,'can not read files of this type');
io.exit(1);
return;
}
@ -359,7 +388,7 @@ Options:
var fd = stdio.open(file,prepFile);
if (!fd) {
io.error('could not open file: '+file);
stdio.write(io.stderr,'could not open file: '+file);
io.exit(1);
return;
}
@ -420,12 +449,12 @@ Options:
});
clite.commands.load('view',function(args,env,io) {
io.write('view is under development');
stdio.printf('view is under development');
return 0;
});
clite.commands.load('edit',function(args,env,io) {
io.write('edit is under development');
stdio.printf('edit is under development');
return 0;
});
@ -435,7 +464,7 @@ clite.commands.load('file',function(args,env,io) {
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
function help() {
io.write(`
stdio.printf(`
file - determine type of FILE
Usage: touch [OPTION] [FILE]
@ -453,25 +482,25 @@ Options:
return 0;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else if (file == null) {
short = args[i];
file = stdlib.resolvePath(args[i],false);
}else{
io.error('unknown argument: '+args[i]);
stdio.write(io.stderr,'unknown argument: '+args[i]);
}
}
if (file == null) {
io.error('no file specified');
stdio.write(io.stderr,'no file specified');
return 1;
}
var fd = stdio.open(file,false);
if (!fd) {
io.error('cannot open file: '+file);
stdio.write(io.stderr,'cannot open file: '+file);
return 1;
}
@ -513,7 +542,7 @@ Options:
}
}
io.write(txt);
stdio.printf(txt);
return 0;
});
@ -521,7 +550,7 @@ Options:
clite.commands.load('reboot',function(args,env,io) {
var stdio = io.include('stdio');
function help() {
io.write(`
stdio.printf(`
reboot - reboot the system, forcing reload of all code
Options:
@ -538,11 +567,11 @@ Options:
return 0;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else{
io.error('unknown argument: '+args[i]);
stdio.write(io.stderr,'unknown argument: '+args[i]);
}
}
@ -564,7 +593,7 @@ clite.commands.load('uname',function(args,env,io) {
var machine = false;
function help() {
io.write(`
stdio.printf(`
uname - print system information
Options:
@ -609,11 +638,11 @@ Options:
version = true;
break;
default:
io.error('unknown argument: -'+args[i][j]);
stdio.write(io.stderr,'unknown argument: -'+args[i][j]);
}
}
}else{
io.error('unknown argument: '+args[i]);
stdio.write(io.stderr,'unknown argument: '+args[i]);
}
}
@ -634,7 +663,7 @@ Options:
if (machine)
txt += ut.machine;
io.write(txt);
stdio.printf(txt);
return 0;
});
@ -642,15 +671,13 @@ Options:
if (window.location.protocol == 'file:')
clite.commands.load('test',function(args,env,io) {
var stdio = io.include('stdio');
var fd = stdio.open('/dev/tty');
stdio.write(fd,'Hello world');
stdio.printf('Hello world');
function rcb(data) {
stdio.write(fd,data);
stdio.close(fd);
stdio.printf(data);
io.exit(0);
}
stdio.read(fd,rcb);
stdio.read(io.stdin,rcb);
return null;
});

View file

@ -251,6 +251,33 @@ guest:x:1:1:guest:/usr/home/guest:/bin/sh
`;
// TODO: check cookies for a local user
n.perms = '-rw-r--r--';
// /etc/greeting is displayed by the shell after login
vfsapi.mkFile('/etc/greeting');
var n = vfsapi.getNode('/etc/greeting');
if (!n) {
clite.log.write('config failure');
return false;
}
n.data.content =`
_____ _ _____ _
/ ____| | |_ _| |
| | | | | | | |_ ___
| | | | | | | __/ _ \\
| |____| |____ _| |_| || __/
\\_____|______|_____|\\__\\___|`;
n.perms = '-rw-r--r--';
// /etc/shrc shell startup file
vfsapi.mkFile('/etc/shrc');
var n = vfsapi.getNode('/etc/shrc');
if (!n) {
clite.log.write('shell config failure');
return false;
}
n.data.content =`
#!/bin/sh
cat /etc/greeting
`;
n.perms = '-rwxr-xr-x';
}
function init1() {
@ -287,7 +314,7 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`;
return;
}
n.data.content = data;
n.perms = 'cr--r-----';
n.perms = 'cr--r--r--';
n.data.isdev = true;
var fd = clite.io.open('/dev/wfs');
var l;
@ -371,36 +398,13 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`;
clite.io.close(fd);
}
// check cookies for login
var clite_text =`
_____ _ _____ _
/ ____| | |_ _| |
| | | | | | | |_ ___
| | | | | | | __/ _ \\
| |____| |____ _| |_| || __/
\\_____|______|_____|\\__\\___|`;
clite.log.write('Checking for user session');
if (clite.user.init(vfsapi)) {// if logged in:
clite.log.write('found user session?');
// create user session
}else{// if new user:
clite.log.write('Generating guest session');
// read in /usr/share/introduction and write to shell
if (window.location.protocol == 'file:') {
clite.user.genGuest();
//clite.shell.writeLine(clite_text);
}else{
//var fd = clite.io.open('/usr/share/introduction',function(fd) {
//clite.user.genGuest();
//clite.shell.writeLine(clite_text);
//if (!fd)
//return;
//var d = clite.io.readAll(fd);
//if (d != null)
//clite.shell.writeLine(d);
//clite.io.close(fd);
//});
}
clite.user.genGuest();
// create the login shell
// should really have init/getty exec the shell with the env data etc
var env = clite.user.getEnv();
@ -408,28 +412,8 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`;
stdin:clite.io.open('/dev/tty',false),
stdout:clite.io.open('/dev/tty',false),
stderr:clite.io.open('/dev/tty',false),
exit:null,
include:function(name) {
switch (name) {
case 'stdlib':
return clite.lib.api;
break;
case 'stdio':
return clite.io;
break;
case 'term':
return clite.term.api;
break;
default:
return null;
break;
}
return null;
},
istty:{
stdin:true, // false if stdin (read) is not clite.shell.readLine
stdout:true // false if stdout (write) is not clite.term.writeLine
}
exit:null, // filled in by fork()
include:null, // filled in by fork()
};
clite.lib.fork(env,io,init5);
}
@ -617,6 +601,18 @@ clite.user = {
}
vfs.mkLink('/usr/home/guest/web','/usr/share/site');
vfs.mkFile('/usr/home/guest/.shrc');
n = vfs.getNode('/usr/home/guest/.shrc');
if (n) {
n.perms = '-rwx------';
n.uid = 1;
n.gid = 1;
n.data.content = `
#!/bin/sh
cat -l /usr/share/introduction
`;
}
setLogin(1);
}
clite.user.getEnv = function() {
@ -1222,7 +1218,8 @@ clite.term = {
form:null,
field:null,
handler:null,
prompt:''
prompt:'',
buff:''
},
events:{
keydown:function(e) {
@ -1236,10 +1233,12 @@ clite.term = {
if (e.key.length > 1 && e.key != 'Spacebar' && clite.term.data.handler != null) {
if (e.key == 'Enter') {
clite.term.data.handler(e.target.value);
clite.term.buff = '';
}else{
clite.term.data.handler('\1'+e.key);
}
}
clite.term.buff = e.target.value;
return false;
},
refocus:function(e) {
@ -1255,16 +1254,10 @@ clite.term = {
tty:{
data:null,
keydown:function(e) {
if (e.key == 'Tab')
return false;
},
keypress:function(e) {
if (e.key == 'Tab') {
clite.term.events.refocus();
return false;
}
// urgh, no. handle press in keyup because fuck js
//return clite.term.tty.data.data.onkeypress(e);
},
keyup:function(e) {
return clite.term.tty.data.data.onkeypress(e);
@ -1306,7 +1299,7 @@ clite.term = {
f.appendChild(l);
var i = document.createElement('input');
i.type = clite.term.getType();
//i.value = clite.shell.history.getCurrent();
i.value = clite.term.data.buff;
f.appendChild(i);
clite.term.data.form = f;
clite.term.data.field = i;
@ -1362,7 +1355,7 @@ clite.term = {
switch (fn) {
case 'iget': // returns the current input string - bypassing tty read
try{
return clite.term.data.field.value;
return clite.term.data.buff;
} catch(err) {
return '';
}
@ -1372,6 +1365,7 @@ clite.term = {
if (typeof v !== 'string')
v = '';
clite.term.data.field.value = v;
clite.term.data.buff = v;
return true;
} catch(err) {
return false;
@ -1632,13 +1626,18 @@ clite.lib = {
return buff;
},
uname:function() {
return Object.create({
var o = Object.create({
sysname:'CLIte',
nodename:'localhost',
release:clite.state.version,
version:clite.state.version,
machine:navigator.userAgent
});
if (window.location.protocol != 'file:')
o.nodename = window.location.hostname;
return o;
},
fork:function(env,io,call) {
var pid = clite.proc.add(call);
@ -1647,6 +1646,9 @@ clite.lib = {
var nio = Object.create(io);
nio.exit = function(v) {
clite.lib.exit(pid,v);
try{
io.exit(pid,v);
} catch(err) {}
}
nio.include = function(name) {
switch (name) {

View file

@ -5,6 +5,7 @@ clite.commands.load('sh',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var term = io.include('term');
var active_pid = 0;
var prompt = '$ ';
var macro = {
clear:function(args,io) {
@ -79,6 +80,12 @@ clite.commands.load('sh',function(args,env,io) {
}
};
function active_exit(pid,v) {
if (pid != active_pid)
return;
inputRead();
}
function resolvePATH(txt) {
if (typeof env.PATH === 'undefined')
env.PATH = '/bin';
@ -150,15 +157,27 @@ clite.commands.load('sh',function(args,env,io) {
return pptxt;
}
function run(txt) {
function parseScript(fd) {
var l;
while ((l = stdio.readLine(fd)) != null) {
if (l[0] == '#')
continue;
run(l,false);
}
}
function run(txt,interactive) {
if (txt.length < 1) {
stdio.write(io.stdout,prompt);
inputRead();
if (interactive) {
stdio.write(io.stdout,prompt);
inputRead();
}
return;
}
//clite.shell.history.add(txt);
//clite.shell.history.resetCurrent();
stdio.write(io.stdout,prompt+txt);
if (interactive)
stdio.write(io.stdout,prompt+txt);
// clear the tty prompt
term.ttyctrl('prompt','');
// split command line into arguments
@ -172,21 +191,23 @@ clite.commands.load('sh',function(args,env,io) {
stdin:io.stdin,
stdout:io.stdout,
stderr:io.stderr,
exit:null, // filled in by fork()
exit:active_exit, // filled in by fork()
include:null, // filled in by fork()
};
// check for a macro
// then either run the macro or expand the program to be executed via PATH
if (typeof macro[args[0]] != 'undefined') {
var r = macro[args[0]](args,fio);
inputRead();
if (interactive)
inputRead();
return;
}
var path = resolvePATH(args[0]);
if (!path) {
stdio.write(io.stderr,'Shell: unknown command: '+args[0]);
inputRead();
if (interactive)
inputRead();
return;
}
@ -195,16 +216,21 @@ clite.commands.load('sh',function(args,env,io) {
if (r > 0)
return;
if (r == -1)
if (r == -1) {
stdlib.write(io.stderr,'Shell: unknown command: '+args[0]);
io.exit(-1);
}
if (r == -2)
if (r == -2) {
stdio.write(io.stderr,'Shell: error in command:'+args[0]);
inputRead();
io.exit(-1);
}
}
if (!stdlib.fork(env,fio,execFunc)) {
active_pid = stdlib.fork(env,fio,execFunc);
if (active_pid == 0) {
stdio.write(io.stderr,'Shell: internal error');
inputRead();
if (interactive)
inputRead();
}
}
@ -237,7 +263,8 @@ clite.commands.load('sh',function(args,env,io) {
return;
}
run(str);
active_pid = 0;
run(str,true);
}
function inputRead() {
// generate the prompt
@ -257,9 +284,24 @@ clite.commands.load('sh',function(args,env,io) {
stdio.read(io.stdin,input);
}
// TODO: this check will exec future shell scripts
if (!stdio.isatty(io.stdin))
// run a shell script
if (!stdio.isatty(io.stdin)) {
parseScript(io.stdin);
return 0;
// otherwise we have an interactive shell
// so run /etc/shrc and ~/.shrc
}else{
var fd = stdio.open('/etc/shrc',false);
if (fd) {
parseScript(fd);
stdio.close(fd);
}
fd = stdio.open(env.HOME+'/.shrc',false);
if (fd) {
parseScript(fd);
stdio.close(fd);
}
}
inputRead();