diff --git a/clite/commands.js b/clite/commands.js index a489c4d..c12c027 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -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] 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] @@ -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] @@ -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; }); diff --git a/clite/core.js b/clite/core.js index 19af49e..ebff4c0 100644 --- a/clite/core.js +++ b/clite/core.js @@ -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) { diff --git a/clite/shell.js b/clite/shell.js index 8ac7a72..097e303 100644 --- a/clite/shell.js +++ b/clite/shell.js @@ -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();