CLIte/clite/commands.js
2023-12-17 09:42:18 +10:00

2373 lines
48 KiB
JavaScript

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
stdio.printf('help with arguments is a work in progress\n');
}
stdio.printf(`
Welcome to CLIte (pronounced like 'site' with an added L).
Various common Unix commands are available in the CLIte shell:
ls - list directory contents
cat - concatenate files and print to std output or local file
touch - create a new file
less - simple text file viewer
file - determines the file type
And many more.
Running any command with the argument -? will give you help for that program.
As a basic guide for guests:
Use ls to see what content is available, eg: ls web
Use less to view the content, eg: less web/about
`);
return 0;
});
clite.commands.load('ls',function(args,env,io) {
var dirs = [];
var long = false;
var all = false;
var access = false;
var one = false;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var time = io.include('time');
var clite = io.include('clite');
function help() {
stdio.printf(`
ls - list directory contents
Usage: ls [OPTION] [FILE]
Options:
-? Print this help information
-l Display data in long format
-u Display access time in long format
-a Do not ignore entries starting with .
-1 Display one entry per line
`);
}
function writeNodeData(st,fn) {
if (long) {
var pw = stdlib.getpwuid(st.st_uid);
var gr = stdlib.getgrgid(st.st_gid);
var uname = st.st_uid.toString();
var gname = st.st_gid.toString();
if (pw)
uname = pw.pw_name;
if (gr)
gname = gr.gr_name;
var tm;
var t = time.time();
var tmn = time.localtime(t);
if (access) {
tm = time.localtime(st.st_atim.tv_sec);
}else{
tm = time.localtime(st.st_mtim.tv_sec);
}
var d = '';
if (tm.tm_year != tmn.tm_year) {
d = time.strftime('%b %d %Y',tm);
}else{
d = time.strftime('%b %d %H:%M',tm);
}
var ms = clite.strmode(st.st_mode);
if (st.type == stdio.types.FT_LINK) {
var lp = '?';
var fd = stdio.open(fn,stdio.flags.O_RDONLY|stdio.flags.O_NOFOLLOW|stdio.flags.O_SYNC);
if (fd) {
lp = stdio.readAll(fd);
stdio.close(fd);
if (!lp)
lp = '?';
}
stdio.printf('%s%12s%12s%14s%12s -> %s\n',ms,uname,gname,d,st.name,lp);
}else{
stdio.printf('%s%12s%12s%14s%12s\n',ms,uname,gname,d,st.name);
}
}else if (one) {
stdio.printf('%s\n',st.name);
}else{
stdio.printf('%s ',st.name);
}
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'l':
long = true;
break;
case 'u':
access = true;
break;
case 'a':
all = true;
break;
case '1':
one = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
dirs.push(clite.resolvePath(args[i],false));
}
}
if (dirs.length < 1)
dirs.push(env.PWD);
dirs.forEach(function(dir,index) {
if (dirs.length > 1)
stdio.printf('%s:\n',dir);
var fd = stdio.open(dir,stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (!fd) {
stdio.fprintf(io.stderr,'cannot open directory: %s\n',dir);
return;
}
var st = stdio.fstatat(fd,stdio.flags.AT_SYMLINK_NOFOLLOW);
if (!st) {
stdio.fprintf(io.stderr,'cannot read file: %s\n',dir);
stdio.close(fd);
return;
}
if (st.type != stdio.types.FT_DIR) {
writeNodeData(st,fd);
stdio.close(fd);
return;
}
var e;
while ((e = stdio.read(fd)) != null) {
if (e[0] == '.' && !all)
continue;
var est = stdio.lstat(dir+'/'+e,stdio.flags.AT_SYMLINK_NOFOLLOW);
if (!est) {
stdio.fprintf(io.stderr,'cannot read content: %s\n',dir);
break;
}
writeNodeData(est,dir+'/'+e);
}
stdio.close(fd);
if (!one && !long)
stdio.write(io.stdout,'\n');
});
return 0;
});
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');
var clite = io.include('clite');
function help() {
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
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'd':
download = true;
break;
case 'l':
remote = false;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
files.push(clite.resolvePath(args[i],false));
}
}
if (files.length < 1)
return 1;
pending = files.length;
// check if we're on a webserver
if (!remote) {
var u = stdlib.uname();
if (u && u.nodename != 'localhost')
remote = true;
}
function fcb(fd) {
var st = stdio.fstatat(fd,stdio.flags.AT_SYMLINK_NOFOLLOW);
// check if it's a directory or 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) {
stdio.fprintf(io.stderr,'not a normal file: %s\n',st.name);
}else{
stdio.write(io.stderr,'not a normal file\n');
}
}else{
var d = stdio.readAll(fd);
if (d != null) {
if (download) {
var ld = stdio.open('/dev/local',stdio.flags.O_WRONLY);
if (ld) {
var t = st.name+String.fromCharCode(2)+d;
stdio.write(ld,t);
stdio.close(ld);
}else{
stdio.write(io.stderr,'can not write to local device\n');
}
}else{
stdio.printf(d);
}
}
}
pending--;
stdio.close(fd);
if (pending <1)
io.exit(0);
}
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
|| st.type == stdio.types.FT_BINARY
|| st.type == stdio.types.FT_UNKOWN
|| st.type == stdio.types.FT_IMAGE
) {
stdio.fprintf(io.stderr,'not a normal file: %s\n',file);
pending--;
return;
}
if (!remote && st.type == stdio.types.FT_REMOTE) {
pending--;
return;
}
var fd = stdio.open(file,stdio.flags.O_RDONLY,fcb);
if (!fd) {
stdio.fprintf(io.stderr,'cannot open file: %s\n',file);
pending--;
return;
}
});
if (pending <1)
return 0;
return null;
});
clite.commands.load('touch',function(args,env,io) {
var file = null;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var clite = io.include('clite');
function help() {
stdio.printf(`
touch - create a new empty file
Usage: touch [OPTION] <FILE>
Options:
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (file == null) {
file = clite.resolvePath(args[i],false);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
stdio.write(io.stderr,'no file specified\n');
return 1;
}
function loadRemote(fd) {
if (!fd) {
stdio.fprintf(io.stderr,'unable to create file: %s\n',file);
io.exit(1);
return;
}
io.exit(0);
}
if (!stdio.creat(file)) {
var fd = stdio.open(file,stdio.flags.O_RDONLY,loadRemote);
return null;
}
return 0;
});
clite.commands.load('less',function(args,env,io) {
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var term = io.include('term');
var curses = io.include('curses');
var clite = io.include('clite');
var file = null;
function help() {
stdio.printf(`
less - text file viewer
Usage: less [OPTION] <FILE>
Options:
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (file == null) {
file = clite.resolvePath(args[i],false);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
var cols;
var rows;
var lines = [];
var topLine = 0;
var bottomLine = 0;
function showAt(line) {
var start = line;
var end = line+rows-1;
if (end > lines.length)
end = lines.length;
curses.clear();
for (var i=start; i<end; i++) {
curses.printw("%s\n",lines[i]);
}
}
function prepFile(fd) {
if (!fd) {
stdio.fprintf(io.stderr,'could not open file: %s\n',file);
io.exit(1);
return;
}
var st = stdio.fstatat(fd,0);
if ( !st || (st.type != stdio.types.FT_TEXT && st.type != stdio.types.FT_SCRIPT)) {
stdio.write(io.stderr,'can not read files of this type\n');
io.exit(1);
return;
}
var txt = stdio.readAll(fd);
stdio.close(fd);
var parts = txt.split('\n');
parts.forEach(function(line) {
if (line.length >= cols) {
var sects = line.match(new RegExp('(.{1,'+(cols-1)+'})','g'));
lines.push.apply(lines,sects);
return;
}
lines.push(line);
});
bottomLine = (lines.length-rows);
showAt(0);
}
var fd = null;
if (file == null) {
if (stdio.isatty(io.stdin)) {
stdio.write(io.stderr,'no file specified\n');
return 1;
}
fd = io.stdin;
io.stdin = stdio.open('/dev/tty',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
stdlib.sleep(2,function() {
prepFile(fd);
});
}else{
fd = stdio.open(file,stdio.flags.O_RDONLY,prepFile);
if (!fd) {
stdio.fprintf(io.stderr,'could not open file: %s\n',file);
return 1;
}
}
curses.initscr();
cols = curses.getmaxx();
rows = curses.getmaxy();
curses.cbreak();
curses.noecho();
curses.printw('Loading...');
function input(key) {
switch (key) {
case curses.key.KEY_ESCAPE:
case 'q':
curses.endwin();
io.exit(0);
return;
break;
case curses.key.KEY_UP:
if (topLine > 0) {
topLine--;
showAt(topLine);
}
break;
case curses.key.KEY_DOWN:
if (topLine < bottomLine) {
topLine++;
showAt(topLine);
}
break;
case curses.key.KEY_PPAGE:
if (topLine > 0) {
topLine -= rows-1;
if (topLine < 0)
topLine = 0;
showAt(topLine);
}
break;
case curses.key.KEY_NPAGE:
if (topLine < bottomLine) {
topLine += rows-1;
if (topLine >= bottomLine)
topLine = bottomLine;
showAt(topLine);
}
break;
case curses.key.KEY_HOME:
topLine = 0;
showAt(topLine);
break;
case curses.key.KEY_END:
topLine = bottomLine;
showAt(topLine);
break;
}
curses.getch(input);
}
curses.getch(input);
return null;
});
clite.commands.load('rm',function(args,env,io) {
var short = null;
var file = null;
var stdio = io.include('stdio');
var clite = io.include('clite');
var recurse = false;
var force = false;
function help() {
stdio.printf(`
rm - remove files or directories
Usage: rm [OPTION] <FILE>
Options:
-r Remove directories and their contents recusively
-f Ignore nonexistant files and arguments
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case 'r':
recurse = true;
break;
case 'f':
force = true;
break;
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (file == null) {
short = args[i];
file = clite.resolvePath(args[i],false);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
stdio.fprintf(io.stderr,'no file specified\n');
return 1;
}
function removeFile(path) {
var st = stdio.lstat(path);
if (!st) {
if (force)
return 0;
stdio.fprintf(io.stderr,'no such file or directory: %s\n',path);
return 1;
}
var fd = stdio.open(path,stdio.flags.O_RDONLY|stdio.flags.O_NOFOLLOW|stdio.flags.O_SYNC);
if (!fd) {
stdio.fprintf(io.stderr,'permission denied: %s\n',path);
return 1;
}
if (st.type == stdio.types.FT_DIR) {
if (!recurse) {
var i = stdio.read(fd);
if (i) {
stdio.close(fd);
stdio.fprintf(io.stderr,'cannot remove non-empty directory: %s\n',path);
return 1;
}
}else{
var f;
while ((f = stdio.read(fd)) != null) {
if (removeFile(path+'/'+f)) {
stdio.close(fd);
return 1;
}
}
}
}
stdio.close(fd);
if (st.type == stdio.types.FT_DEV) {
stdio.fprintf(io.stderr,'cannot remove device files: %s\n',path);
return 1;
}
if (!stdio.remove(path)) {
stdio.fprintf(io.stderr,'permission denied: %s\n',path);
return 1;
}
return 0;
}
return removeFile(file);
});
clite.commands.load('mkdir',function(args,env,io) {
var short = null;
var file = null;
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var clite = io.include('clite');
var recurse = false;
function help() {
stdio.printf(`
mkdir - remove files or directories
Usage: mkdir [OPTION] <DIRECTORY>
Options:
-p Make the full path, not just the final directory
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case 'p':
recurse = true;
break;
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (file == null) {
short = args[i];
file = clite.resolvePath(args[i],false);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
stdio.fprintf(io.stderr,'no path specified\n');
return 1;
}
var st = stdio.lstat(file);
if (st) {
stdio.fprintf(io.stderr,'already exists: %s\n',short);
return 1;
}
if (!stdio.mkdir(file)) {
if (!recurse) {
stdio.fprintf(io.stderr,'persmission denied: %s\n',short);
return 1;
}
var parts = file.split('/');
var path = '';
for (var i=0; i<parts.length; i++) {
path += '/'+parts[i];
st = stdio.stat(path);
if (st) {
if (st.type != stdio.types.FT_DIR) {
stdio.fprintf(io.stderr,'permission denied: %s\n',path);
return 1;
}
continue;
}
if (!stdio.mkdir(path)) {
stdio.fprintf(io.stderr,'permission denied: %s\n',path);
return 1;
}
}
}
return 0;
});
clite.commands.load('chmod',function(args,env,io) {
var short = '';
var file = null;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var clite = io.include('clite');
var recurse = false;
var modmask = null;
function help() {
stdio.printf(`
chmod - change file mode bits
Usage: chmod [OPTION] <MODE> <FILE>
Options:
-? Print this help information
`);
}
function getModMask(str) {
var parts = str.split(',');
var modmask = ['???','???','???'];
if (parts.length == 1 && (str.length == 3 || str.length == 4)) {
var iv = parseInt(str,10);
if (iv > 0) {
if (str.length == 4)
str = str.substring(1);
for (var i=0; i<str.length; i++) {
switch(str[i]) {
case '0':
modmask[i] = '---';
break;
case '1':
modmask[i] = '--x';
break;
case '2':
modmask[i] = '-w-';
break;
case '3':
modmask[i] = '-wx';
break;
case '4':
modmask[i] = 'r--';
break;
case '5':
modmask[i] = 'r-x';
break;
case '6':
modmask[i] = 'rw-';
break;
case '7':
modmask[i] = 'rwx';
break;
}
}
return modmask.join('');
}
}
parts.forEach(function(p) { // [who]op[perm]
var u = false;
var g = false;
var o = false;
var op = null;
var s = 0;
for (var i=0; i<p.length; i++) {
if (s == 0) {
switch (p[i]) {
case 'u':
u = true;
break;
case 'g':
g = true;
break;
case 'o':
o = true;
break;
case 'a':
u = true;
g = true;
o = true;
break;
case '=':
case '+':
case '-':
op = p[i];
s = 1;
if (!u && !g && !o) {
u = true;
g = true;
o = true;
}
if (op == '=') {
if (u)
modmask[0] = '---';
if (g)
modmask[1] = '---';
if (o)
modmask[2] = '---';
}
break;
}
}else if (s == 1) {
switch (p[i]) {
case 'r':
if (u) {
if (op == '=' || op == '+') {
modmask[0] = 'r'+modmask[0][1]+modmask[0][2];
}else if (op = '-') {
modmask[0] = '-'+modmask[0][1]+modmask[0][2];
}
}
if (g) {
if (op == '=' || op == '+') {
modmask[1] = 'r'+modmask[1][1]+modmask[1][2];
}else if (op = '-') {
modmask[1] = '-'+modmask[1][1]+modmask[1][2];
}
}
if (o) {
if (op == '=' || op == '+') {
modmask[2] = 'r'+modmask[2][1]+modmask[2][2];
}else if (op = '-') {
modmask[2] = '-'+modmask[2][1]+modmask[2][2];
}
}
break;
case 'w':
if (u) {
if (op == '=' || op == '+') {
modmask[0] = modmask[0][0]+'w'+modmask[0][2];
}else if (op = '-') {
modmask[0] = modmask[0][0]+'-'+modmask[0][2];
}
}
if (g) {
if (op == '=' || op == '+') {
modmask[1] = modmask[1][0]+'w'+modmask[1][2];
}else if (op = '-') {
modmask[1] = modmask[1][0]+'-'+modmask[1][2];
}
}
if (o) {
if (op == '=' || op == '+') {
modmask[2] = modmask[2][0]+'w'+modmask[2][2];
}else if (op = '-') {
modmask[2] = modmask[2][0]+'-'+modmask[2][2];
}
}
break;
case 'x':
if (u) {
if (op == '=' || op == '+') {
modmask[0] = modmask[0][0]+modmask[0][1]+'x';
}else if (op = '-') {
modmask[0] = modmask[0][1]+modmask[0][1]+'-';
}
}
if (g) {
if (op == '=' || op == '+') {
modmask[1] = modmask[1][0]+modmask[1][1]+'x';
}else if (op = '-') {
modmask[1] = modmask[1][0]+modmask[1][1]+'-';
}
}
if (o) {
if (op == '=' || op == '+') {
modmask[2] = modmask[2][0]+modmask[2][1]+'x';
}else if (op = '-') {
modmask[2] = modmask[2][0]+modmask[2][1]+'-';
}
}
break;
case 'X':
if (u) {
if (op == '=' || op == '+') {
modmask[0] = modmask[0][0]+modmask[0][1]+'X';
}else if (op = '-') {
modmask[0] = modmask[0][1]+modmask[0][1]+'Y';
}
}
if (g) {
if (op == '=' || op == '+') {
modmask[1] = modmask[1][0]+modmask[1][1]+'X';
}else if (op = '-') {
modmask[1] = modmask[1][0]+modmask[1][1]+'Y';
}
}
if (o) {
if (op == '=' || op == '+') {
modmask[2] = modmask[2][0]+modmask[2][1]+'X';
}else if (op = '-') {
modmask[2] = modmask[2][0]+modmask[2][1]+'Y';
}
}
break;
case 'u':
if (g)
modmask[1] = modmask[0];
if (o)
modmask[2] = modmask[0];
s = 0;
break;
case 'g':
if (u)
modmask[0] = modmask[1];
if (o)
modmask[2] = modmask[1];
s = 0;
break;
case 'o':
if (u)
modmask[0] = modmask[2];
if (g)
modmask[1] = modmask[2];
s = 0;
break;
}
}else{ // ?
return;
}
}
});
return modmask.join('');
}
function getMode(mode,isdir) {
if (modmask[0] == 'r') {
mode |= stdio.modes.S_IRUSR;
}else if (modmask[0] == '-') {
mode &= ~stdio.modes.S_IRUSR;
}
if (modmask[1] == 'w') {
mode |= stdio.modes.S_IWUSR;
}else if (modmask[1] == '-') {
mode &= ~stdio.modes.S_IWUSR;
}
if (modmask[2] == 'x' || (isdir && modmask[2] == 'X')) {
mode |= stdio.modes.S_IXUSR;
mode &= ~stdio.modes.S_ISUID;
}else if (modmask[2] == 's') {
mode |= stdio.modes.S_IXUSR;
mode |= stdio.modes.S_ISUID;
}else if (modmask[2] == 'S') {
mode &= ~stdio.modes.S_IXUSR;
mode |= stdio.modes.S_ISUID;
}else if (modmask[2] == '-' || (isdir && modmask[2] == 'Y')) {
mode &= ~stdio.modes.S_IXUSR;
mode &= ~stdio.modes.S_ISUID;
}
if (modmask[3] == 'r') {
mode |= stdio.modes.S_IRGRP;
}else if (modmask[3] == '-') {
mode &= ~stdio.modes.S_IRGRP;
}
if (modmask[4] == 'w') {
mode |= stdio.modes.S_IWGRP;
}else if (modmask[4] == '-') {
mode &= ~stdio.modes.S_IWGRP;
}
if (modmask[5] == 'x' || (isdir && modmask[5] == 'X')) {
mode |= stdio.modes.S_IXGRP;
mode &= ~stdio.modes.S_ISGID;
}else if (modmask[5] == 's') {
mode |= stdio.modes.S_IXGRP;
mode |= stdio.modes.S_ISGID;
}else if (modmask[5] == 'S') {
mode &= ~stdio.modes.S_IXGRP;
mode |= stdio.modes.S_ISGID;
}else if (modmask[5] == '-' || (isdir && modmask[5] == 'Y')) {
mode &= ~stdio.modes.S_IXGRP;
mode &= ~stdio.modes.S_ISGID;
}
if (modmask[6] == 'r') {
mode |= stdio.modes.S_IROTH;
}else if (modmask[6] == '-') {
mode &= ~stdio.modes.S_IROTH;
}
if (modmask[7] == 'w') {
mode |= stdio.modes.S_IWOTH;
}else if (modmask[7] == '-') {
mode &= ~stdio.modes.S_IWOTH;
}
if (!isdir) {
if (modmask[8] == 'x') {
mode |= stdio.modes.S_IXOTH;
}else if (modmask[8] == '-') {
mode &= ~stdio.modes.S_IXOTH;
}
}else{
if (modmask[8] == 'x' || modmask[8] == 'X') {
mode |= stdio.modes.S_IXOTH;
mode &= ~stdio.modes.S_ISVTX;
}else if (modmask[8] == 't') {
mode |= stdio.modes.S_IXOTH;
mode |= stdio.modes.S_ISVTX;
}else if (modmask[8] == 'T') {
mode &= ~stdio.modes.S_IXOTH;
mode |= stdio.modes.S_ISVTX;
}else if (modmask[8] == '-' || modmask[8] == 'Y') {
mode &= ~stdio.modes.S_IXOTH;
mode &= ~stdio.modes.S_ISVTX;
}
}
return mode;
}
function getPerms(str,isdir) {
var n = str.substring(1);
for (var i=0; i<9; i++) {
if (modmask[i] == '?')
continue;
if (modmask[i] == n[i])
continue;
if (modmask[i] == 'X') {
if (isdir)
n = n.substring(0,i)+'x'+n.substring(i+1);
}else if (modmask[i] == 'Y') {
if (isdir)
n = n.substring(0,i)+'-'+n.substring(i+1);
}else{
n = n.substring(0,i)+modmask[i]+n.substring(i+1);
}
}
return n;
}
if (args.length == 3) { // name mode file
modmask = getModMask(args[1]);
short = args[2];
file = clite.resolvePath(short);
}else if (args.length == 4) { // name option mode file
if (args[1][0] != '-') {
stdio.write(io.stderr,'invalid arguments\n');
return 1;
}
for (var j=1; j<args[1].length; j++) {
switch (args[1][j]) {
case 'R':
recurse = true;
break;
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
modmask = getModMask(args[2]);
short = args[3];
file = clite.resolvePath(short);
}else if (args.length == 2 && args[1] == '-?') {
help();
return 0;
}else{
stdio.write(io.stderr,'invalid arguments\n');
return 1;
}
if (modmask == null || modmask == '?????????') {
stdio.write(io.stderr,'invalid mode\n');
return 1;
}
if (file == null) {
stdio.write(io.stderr,'no file specified\n');
return 1;
}
var st = stdio.lstat(file);
if (!st) {
stdio.fprintf(io.stderr,'cannot open file: %s\n',short);
return 1;
}
var mode = getMode(st.st_mode,(st.type == stdio.types.FT_DIR));
if (!stdio.chmod(file,mode)) {
stdio.fprintf(io.stderr,'cannot write file: %s\n',short);
return 1;
}
return 0;
});
clite.commands.load('file',function(args,env,io) {
var short = '';
var file = null;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var clite = io.include('clite');
function help() {
stdio.printf(`
file - determine the file type
Usage: file [OPTION] <FILE>
Options:
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (file == null) {
short = args[i];
file = clite.resolvePath(args[i],false);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
stdio.write(io.stderr,'no file specified\n');
return 1;
}
var st = stdio.lstat(file);
var txt = short+': ';
if (!st) {
stdio.fprintf(io.stderr,'cannot open file: %s\n',file);
return 1;
}else{
switch (st.type) {
case stdio.types.FT_TEXT:
txt += 'Plain Text';
break;
case stdio.types.FT_BINARY:
txt += 'CLIte Executable';
break;
case stdio.types.FT_DIR:
txt += 'Directory';
break;
case stdio.types.FT_LINK:
txt += 'Link';
break;
case stdio.types.FT_DEV:
txt += 'Device File';
break;
case stdio.types.FT_REMOTE:
txt += 'Unloaded Remote Data';
break;
case stdio.types.FT_SCRIPT:
txt += 'Shell Script';
break;
case stdio.types.FT_IMAGE:
txt += 'Image';
break;
case stdio.types.FT_LIBRARY:
txt += 'Shared Object';
break;
default:
txt += 'Unknown Data';
break;
}
}
stdio.printf('%s\n',txt);
return 0;
});
clite.commands.load('reboot',function(args,env,io) {
var stdio = io.include('stdio');
function help() {
stdio.printf(`
reboot - reboot the system, forcing reload of all code
Usage: reboot [OPTION]
Options:
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
var fd = stdio.open('/dev/initctl',stdio.flags.O_WRONLY|stdio.flags.O_SYNC);
if (!fd)
return 1;
stdio.write(fd,'6'); // switch to runlevel 6, reboot
stdio.close(fd);
return 0;
});
clite.commands.load('uname',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var sysname = false;
var nodename = false;
var release = false;
var version = false;
var machine = false;
function help() {
stdio.printf(`
uname - print system information
Usage: uname [OPTION]
Options:
-a All, equivalent to -mnrsv
-m Print the hardware info (User Agent)
-n Print the network name
-r Print the operating system release
-s Print the operating system name
-v Print the operating system version
-? Print this help information
`);
}
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'a':
machine = true;
nodename = true;
release = true;
sysname = true;
version = true;
break;
case 'm':
machine = true;
break;
case 'n':
nodename = true;
break;
case 'r':
release = true;
break;
case 's':
sysname = true;
break;
case 'v':
version = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (!machine && !nodename && !release && !sysname && !version)
sysname = true;
var ut = stdlib.uname();
var txt = '';
if (sysname)
txt += ut.sysname+' ';
if (nodename)
txt += ut.nodename+' ';
if (release)
txt += ut.release+' ';
if (version)
txt += ut.version+' ';
if (machine)
txt += ut.machine;
stdio.printf('%s\n',txt);
return 0;
});
clite.commands.load('date',function(args,env,io) {
var stdio = io.include('stdio');
var time = io.include('time');
function help() {
stdio.printf(`
date - print system time and date
Usage: date [OPTION] [FORMAT]
Options:
-u use UTC instead of local time
-? Print this help information
`);
}
//tm_sec:0, // seconds (0-60)
//tm_min:0, // minutes (0-59)
//tm_hour:0, // hour (0-23)
//tm_mday:0, // day of month (0-31)
//tm_mon:0, // month of year (0-11)
//tm_year:0, // years since 1900
//tm_wday:0, // day of week (0-6, sunday = 0)
//tm_yday:0, // day of year (0-365)
//tm_isdst:0 // 1 if daylight savings
function main(args) {
var utc = false;
var format = '%a %d %b %Y %T %Z';
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'u':
utc = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (args[i][0] == '+') {
format = args[i].substring(1);
}else{
// TODO: set time
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
var t = time.time();
var tm = null;
if (utc) {
tm = time.gmtime(t);
}else{
tm = time.localtime(t);
}
if (!t)
return 1;
var out = time.strftime(format,tm);
if (!out)
return 1;
stdio.printf('%s\n',out);
return 0;
}
return main(args);
});
clite.commands.load('head',function(args,env,io) {
var stdio = io.include('stdio');
var clite = io.include('clite');
var lines = 10;
function help() {
stdio.printf(`
head - copy the first part of files
Usage: head [OPTION] <FILE>
Options:
-n N the number of lines to print (default 10)
-? Print this help information
`);
}
function writeFile(fd) {
if (!fd) {
stdio.fprintf(io.stderr,'could not open file\n');
io.exit(1);
return;
}
var l;
for (var i=0; i<lines && (l = stdio.readLine(fd)) != null; i++) {
stdio.printf('%s\n',l);
}
stdio.close(fd);
io.exit(0);
}
function main(args) {
var lnext = false;
var short = null;
var file = null;
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'n':
lnext = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (lnext) {
lines = parseInt(args[i]);
if (lines < 1) {
stdio.fprintf(io.stderr,'invalid lines count "%d"\n',lines);
return 1;
}
lnext = false;
}else if (file == null) {
short = args[i];
file = clite.resolvePath(args[i]);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
if (!stdio.isatty(io.stdin)) {
writeFile(io.stdin);
return null;
}
stdio.write(io.stderr,'no file specified\n');
return 1;
}
var fd = stdio.open(file,stdio.flags.O_RDONLY,writeFile);
if (!fd) {
stdio.fprintf(io.stderr,'could not open file: %s\n',short);
return 1;
}
return null;
}
return main(args);
});
clite.commands.load('tail',function(args,env,io) {
var stdio = io.include('stdio');
var clite = io.include('clite');
var lines = 10;
var chars = 0;
function help() {
stdio.printf(`
tail - copy the last part of a file
Usage: tail [OPTION] <FILE>
Options:
-n N the number of lines to print (default 10)
-c N instead of lines, print the last N characters
-? Print this help information
`);
}
function writeFile(fd) {
if (!fd) {
stdio.fprintf(io.stderr,'could not open file\n');
io.exit(1);
return;
}
var d = stdio.readAll(fd);
if (chars > 0) {
if (d.length < chars) {
stdio.write(io.stdout,d);
}else{
stdio.write(io.stdout,d.substring(d.length-chars));
}
}else{
var ls = d.split('\n');
if (ls[ls.length-1] == '')
ls.pop();
while (ls.length > lines) {
ls.shift();
}
ls.forEach(function(l) {
stdio.printf('%s\n',l);
});
}
stdio.close(fd);
io.exit(0);
}
function main(args) {
var lnext = false;
var cnext = false;
var short = null;
var file = null;
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'c':
cnext = true;
break;
case 'n':
lnext = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else if (lnext) {
lines = parseInt(args[i]);
if (lines < 1) {
stdio.fprintf(io.stderr,'invalid lines count "%d"\n',lines);
return 1;
}
lnext = false;
}else if (cnext) {
chars = parseInt(args[i]);
if (chars < 1) {
stdio.fprintf(io.stderr,'invalid characters count "%d"\n',chars);
return 1;
}
cnext = false;
}else if (file == null) {
short = args[i];
file = clite.resolvePath(args[i]);
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
if (file == null) {
if (!stdio.isatty(io.stdin)) {
writeFile(io.stdin);
return null;
}
stdio.write(io.stderr,'no file specified\n');
return 1;
}
var fd = stdio.open(file,stdio.flags.O_RDONLY,writeFile);
if (!fd) {
stdio.fprintf(io.stderr,'could not open file: %s\n',short);
return 1;
}
return null;
}
return main(args);
});
clite.commands.load('strip',function(args,env,io) {
var stdio = io.include('stdio');
function help() {
stdio.printf(`
strip - remove unnecessary data from strippable files
Usage: strip [OPTION] <FILE> [FILE...]
Options:
-? Print this help information
`);
}
// this is a no op program, it always succeeds
// it exists solely because posix says it should
// but does nothing because there's nothing to strip from files
// "The strip utility shall remove from strippable files named by
// the file operands any information the implementor deems
// unnecessary for execution of those files" - doing nothing is
// compliant
function main(args) {
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',args[i]);
}
}
return 0;
}
return main(args);
});
clite.commands.load('sleep',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
function help() {
stdio.printf(`
sleep - suspend execution for a time
Usage: sleep [OPTION] <SECONDS>
Options:
-? Print this help information
`);
}
function scb(r) {
io.exit(0);
}
function main(args) {
var seconds = 0;
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
seconds = parseInt(args[i]);
}
}
if (seconds < 1)
return 0;
if (!stdlib.sleep(seconds,scb))
return 1;
return null;
}
return main(args);
});
clite.commands.load('test',function(args,env,io) {
var stdio = io.include('stdio');
var clite = io.include('clite');
function help() {
stdio.printf(`
test - evalutate expression
Usage: test [OPTION] [EXPRESSION]
Options:
-? Print this help information
`);
}
function main(args) {
var negate = false;
if (args.length == 1)
return 1;
if (args.length == 2) {
if (args[1] == '-?') {
help();
return 0;
}
if (args[1].length > 0)
return 0;
return 1;
}
if (args.length > 5)
return 1;
var uargs = Array.from(args);
uargs.shift();
if (args[0] == '[' && uargs[uargs.length-1] == ']')
uargs.pop();
if (uargs[0] == '!') {
negate = true;
uargs.shift();
}
if (uargs.length > 2 && uargs[0] == '(' && uargs[uargs.length-1] == ')') {
uargs.shift();
uargs.pop();
if (uargs[0] == '!') {
negate = !negate;
uargs.shift();
}
}
if (uargs.length == 1) {
if (uargs[0].length > 0) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
}
// -primary_operator primary_operand
if (uargs.length == 2) {
switch (uargs[0]) {
case '-b': // test for a block file
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || (st.st_mode&stdio.modes.S_IFBLK) != stdio.modes.S_IFBLK) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-c':
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || st.type != stdio.types.FT_DEV) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-d':
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || st.type != stdio.types.FT_DIR) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-e':
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-f':
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || st.type == stdio.types.FT_DIR || st.type == stdio.types.FT_DEV || st.type == stdio.types.FT_LINK) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-g': // test for set-groud-id
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || (st.st_mode&stdio.modes.S_ISGID) != stdio.modes.S_ISGID) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-h':
case '-L':
var p = clite.resolvePath(uargs[1]);
var st = stdio.lstat(p);
if (!st || st.type != stdio.types.FT_LINK) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-n':
if (uargs[1].length == 0) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-p': // test for FIFO/pipe
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || (st.st_mode&stdio.modes.S_IFIFO) != stdio.modes.S_IFIFO) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-r':
var p = clite.resolvePath(uargs[1]);
var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (!fd || !stdio.isreadable(fd)) {
if (fd)
stdio.close(fd);
if (negate)
return 0;
return 1;
}
if (fd)
stdio.close(fd);
if (negate)
return 1;
return 0;
break;
case '-S': // test for socket
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || (st.st_mode&stdio.modes.S_IFSOCK) != stdio.modes.S_IFSOCK) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-s':
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || st.st_size == 0) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-t':
if (uargs[1] == '0') { // stdin
if (!stdio.isatty(io.stdin)) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
}
if (uargs[1] == '1') { // stdout
if (!stdio.isatty(io.stdin)) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
}
if (uargs[1] == '2') { // stderr
if (!stdio.isatty(io.stdin)) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-u': // test for set-user-id
var p = clite.resolvePath(uargs[1]);
var st = stdio.stat(p);
if (!st || (st.st_mode&stdio.modes.S_ISUID) != stdio.modes.S_ISUID) {
if (negate)
return 0;
return 1;
}
if (negate)
return 1;
return 0;
break;
case '-w':
var p = clite.resolvePath(uargs[1]);
var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (!fd || !stdio.iswritable(fd)) {
if (fd)
stdio.close(fd);
if (negate)
return 0;
return 1;
}
if (fd)
stdio.close(fd);
if (negate)
return 1;
return 0;
break;
case '-x':
var p = clite.resolvePath(uargs[1]);
var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (!fd || !stdio.isexecutable(fd)) {
if (fd)
stdio.close(fd);
if (negate)
return 0;
return 1;
}
if (fd)
stdio.close(fd);
if (negate)
return 1;
return 0;
break;
case '-z':
if (uargs[1].length == 0) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
default:
return 2;
}
}
// primary_operand -primary_operator primary_operand
// primary_operand primary_operator primary_operand
if (uargs.length == 3) {
switch (uargs[1]) {
case '=':
if (uargs[0] == uargs[2]) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '!=':
if (uargs[0] != uargs[2]) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-eq':
if (parseInt(uargs[0]) == parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-ne':
if (parseInt(uargs[0]) != parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-gt':
if (parseInt(uargs[0]) > parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-ge':
if (parseInt(uargs[0]) >= parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-lt':
if (parseInt(uargs[0]) < parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
case '-le':
if (parseInt(uargs[0]) <= parseInt(uargs[2])) {
if (negate)
return 1;
return 0;
}
if (negate)
return 0;
return 1;
break;
default:
return 3;
}
}
return 1;
}
return main(args);
});
clite.commands.load('load',function(args,env,io) {
var stdio = io.include('stdio');
var clite = io.include('clite');
var short = null;
var file = null;
function help() {
stdio.printf(`
load - load a text file from the local device
Usage: load [OPTION] <FILE>
Options:
-? Print this help information
`);
}
function fcb(data) {
if (data == null) {
stdio.write(io.stderr,'no file received\n');
io.exit(1);
return;
}
if (typeof data !== 'string') {
stdio.write(io.stderr,'not a normal file\n');
io.exit(1);
return;
}
var fd = stdio.open(file,stdio.flags.O_WRONLY|stdio.flags.O_CREAT|stdio.flags.O_EXCL|stdio.flags.O_SYNC);
if (!fd) {
stdio.write(io.stderr,'could not create file: %s\n',file);
io.exit(1);
return;
}
if (!stdio.write(fd,data)) {
stdio.close(fd);
stdio.write(io.stderr,'could not write file: %s\n',file);
io.exit(1);
return;
}
stdio.close(fd);
io.exit(0);
}
function main(args) {
for (var i=1; i<args.length; i++) {
if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
short = args[i];
file = clite.resolvePath(short);
}
}
if (!file) {
stdio.write(io.stderr,'no file specified\n');
return 1;
}
var fd = stdio.open('/dev/local',stdio.flags.O_RDWR|stdio.flags.O_SYNC);
if (!fd) {
stdio.write(io.stderr,'could not open local device for reading\n');
return 1;
}
if (!stdio.read(fd,fcb)) {
stdio.close(fd);
stdio.write(io.stderr,'could not read from local device\n');
return 1;
}
stdio.close(fd);
return null;
}
return main(args);
});
clite.commands.load('su',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var clite = io.include('clite');
var auth = io.include('auth');
var term = io.include('term');
var pw = null;
var preserve = true;
var shell = null;
function help() {
stdio.printf(`
su - switch users
Usage: su [OPTION]
Options:
-? Print this help information
-l Simulate a full login
-m Preserve the environment
-s <sh> Use the shell at <sh>
`);
}
function changeUser() {
if (!stdlib.setgid(pw.pw_gid)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
return;
}
if (!stdlib.setuid(pw.pw_uid)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
return;
}
var e = null;
if (preserve) {
e = structuredClone(env);
}else{
e = {};
e.USER = pw.pw_name;
e.PWD = pw.pw_dir;
e.HOME = pw.pw_dir;
e.SHELL = pw.pw_shell;
}
if (shell == null)
shell = e.SHELL;
var args = [shell];
var r = stdlib.exec(shell,args,e,io);
if (r == 0)
return;
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
function doLogin(str) {
term.ttyctrl('echo',true);
if (!auth.checkpassuid(pw.pw_uid,str)) {
stdio.printf('authentication error\n');
io.exit(1);
return;
}
changeUser();
}
function preLogin(str) {
if (str == 'no') {
io.exit(0);
return;
}
if (str != 'yes') {
cookies();
return;
}
if (stdlib.getuid() != 0) {
stdio.write(io.stdout,'password: ');
term.ttyctrl('echo',false);
if (!stdio.read(io.stdin,doLogin)) {
term.ttyctrl('echo',true);
stdio.write(io.stderr,'authentication error\n');
io.exit(1);
}
return;
}
changeUser();
}
function cookies() {
clite.cookienotice();
stdio.printf("Enter 'yes' to agree, or 'no' to cancel: ");
if (!stdio.read(io.stdin,preLogin)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function main(args) {
var user = 'root';
var shellnext = false;
var accept = false;
for (var i=1; i<args.length; i++) {
if (shellnext == true) {
shell = args[i];
shellnext = false;
}else if (args[i] == '-') {
preserve = false;
}else if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[i][j]) {
case '?':
help();
return 0;
break;
case 'l':
preserve = false;
break;
case 'm':
preserve = true;
break;
case 's':
shellnext = true;
break;
case 'c':
accept = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',args[i][j]);
}
}
}else{
user = args[i];
}
}
if (shellnext) {
stdio.write(io.stderr,'invalid arguments\n');
return 1;
}
if (!user) {
stdio.write(io.stderr,'no user specified\n');
return 1;
}
pw = stdlib.getpwnam(user);
if (!pw) {
stdio.fprintf(io.stderr,'invalid user: %s\n',user);
return 1;
}
if (!stdio.isatty(io.stdin)) {
stdio.write(io.stderr,'internal error\n');
return 1;
}
if (accept || user == 'root' || user == 'guest') {
preLogin('yes');
return null;
}
cookies();
return null;
}
return main(args);
},true);
if (window.location.protocol == 'file:')
clite.commands.load('exp',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var time = io.include('time');
var t = time.time();
stdio.printf('time is: %d\n',t);
var tm = time.gmtime(t);
stdio.printf('gmtime gives: %d %d %d %d %d %d %d %d %d\n',tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm.tm_wday,tm.tm_yday,tm.tm_isdst);
stdio.printf('%s\n',time.ctime(t));
stdio.printf('Hello world\n');
stdio.printf('%d %d\n',stdlib.getuid(),stdlib.getgid());
stdio.printf('%#15x:%15o:%15.5f:%0$15.5f:%%:\n',10,12,8.123456789);
function rcb(data) {
stdio.write(io.stdout,data);
var u = stdlib.getpwnam(data);
if (u)
stdio.printf('%s %d %d\n',u.pw_name,u.pw_uid,u.pw_gid);
io.exit(0);
}
stdio.read(io.stdin,rcb);
return null;
});
// insert commands above this line
}