Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/limbo/shfs2.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


# cd; limbo shfs.b; mount {shfs} /n/remote; cd /n/remote; echo date > new;  echo 'ls / | grep lib' > new; 
# % ls -l
# d-rwxrwxrwx M 84 inferno inferno 0 Jan 01  1970 0
# d-rwxrwxrwx M 84 inferno inferno 0 Jan 01  1970 1
# --rw-rw-rw- M 84 inferno inferno 0 Jan 01  1970 new
# % ls 0
# 0/cmd
# 0/stdout
# % cat 0/stdout
# Fri Jun 27 01:07:16 BST 2003
# % cat 0/stdout
# Fri Jun 27 01:07:16 BST 2003
# % rm 0/stdout
# % cat 0/stdout
# Fri Jun 27 01:07:30 BST 2003
# % cat 1/cmd
# ls / | grep lib
 
implement shfs2;
include "sys.m";
include "draw.m";
include "styx.m";
include "styxservers.m";
include "sh.m";
include "string.m";

sys: Sys;
sh: Sh;
styx : Styx;
str : String;
Context: import sh;
Rmsg : import styx;
styxservers: Styxservers;
Styxserver, Navigator: import styxservers;
nametree: Nametree;
Tree: import nametree;
tree : ref Tree;

bitshift : con 32;

shfs2: module
{
	init: fn(nil: ref Draw->Context, argv: list of string);

	shell_cmd: adt {
		cmd : string;
		stdout : array of byte;
		perform : fn (this : self shell_cmd) : array of byte;
	};
};

shell_cmd.perform(this : self shell_cmd) : array of byte {
# not quite how I wanted it
# I wanted to return void and set this.stdout but it seems to be working on a copy

	if (this.stdout != nil) return this.stdout;

	bchan := chan of array of byte;
   	spawn child(bchan, this.cmd);
    	stdout := <-bchan;

	return stdout;
}


Qroot, Qnew, Qfolder, Qcommand, Qstdout: con big iota;	# paths
commands : array of shell_cmd;
command_count := 0;

init(nil: ref Draw->Context, nil: list of string)
{
     	sys = load Sys Sys->PATH;
     	styx = load Styx Styx->PATH;
	sh = load Sh Sh->PATH;
	str = load String String->PATH;

	treeop : chan of ref Styxservers->Navop;

     	styx->init();
     	styxservers = load Styxservers Styxservers->PATH;
     	styxservers->init(styx);
     	nametree = load Nametree Nametree->PATH;
     	nametree->init();
     	sys->pctl(Sys->FORKNS, nil);
     	(tree, treeop) = nametree->start();
     	tree.create(Qroot, dir(".", 8r555|Sys->DMDIR, Qroot));
     	tree.create(Qroot, dir("new", 8r666, Qnew));
	
   	(tchan, srv) := Styxserver.new(sys->fildes(0),Navigator.new(treeop), Qroot);
	reply : ref Rmsg;

     	while((gm := <-tchan) != nil) {

		pick m := gm {
			Read => {
				f := srv.getfid(m.fid);
				qtype := big int(f.path);

				case (qtype) {
					Qstdout => {
						i := int(f.path >> bitshift);
						commands[i].stdout = commands[i].perform();
						reply = styxservers->readbytes(m, commands[i].stdout);
					}
					Qcommand => {
						i := int(f.path >> bitshift);
						reply = styxservers->readbytes(m, array of byte commands[i].cmd);
					}
				}
			}

			Write => {
				f := srv.getfid(m.fid);
				qtype := big int(f.path);
				

				case (qtype) {
				Qcommand => {
					i := int(f.path >> bitshift);
					commands[i].cmd = string m.data;
					commands[i].stdout = nil;
					reply = ref Rmsg.Write(m.tag, len m.data);
					}
				Qnew => {
					add_command(Qroot, string m.data);
					reply = ref Rmsg.Write(m.tag, len m.data);
					}
				}
			}

			Remove => {
				f := srv.getfid(m.fid);
				qtype := big int(f.path);
				

				case (qtype) {
				Qcommand => {
					i := int(f.path >> bitshift);
					commands[i].cmd ="";
					commands[i].stdout = nil;
					reply = ref Rmsg.Remove(m.tag);
					}
				Qstdout => {
					i := int(f.path >> bitshift);
					commands[i].stdout = nil;
					reply = ref Rmsg.Remove(m.tag);
					}
				}

				if (reply != nil) {
					srv.delfid(f);
				}

			}
		}

		if(reply == nil) {
			srv.default(gm);
		} else {
			srv.reply(reply);
			reply = nil;
		}
	}
	tree.quit();
}

extend_commands() { # grow the commands array
	quarter := 5 + len commands / 4;  # formula plucked from thin air

	new_commands := array[len commands + quarter] of shell_cmd;

	if (len commands > 0)
		new_commands[0:] = commands;

	commands = new_commands;
}

add_command (dir_qid : big, cmd : string) {
	if (command_count == len commands) 
		extend_commands();

	sh_cmd := shell_cmd (cmd, nil);

	f_qid := big command_count;
 	f_qid = f_qid << bitshift;
	f_qid += Qfolder;
	
	tree.create(dir_qid, dir(sys->sprint("%d", command_count), 8r777 | Sys->DMDIR, f_qid));

	qid := big command_count;
 	qid = qid << bitshift;
	qid += Qcommand;

	tree.create(f_qid, dir("cmd", 8r666, qid));

	qid = big command_count;
 	qid = qid << bitshift;
	qid += Qstdout;

	tree.create(f_qid, dir("stdout", 8r444, qid));
	commands[command_count++] = sh_cmd;
}

dir(name: string, perm: int, qid: big): Sys->Dir
{
	d := sys->zerodir;
     	d.name = name;
	d.uid = "inferno";
	d.gid = "inferno";
	d.qid.path = qid;
	if (perm & Sys->DMDIR)
		d.qid.qtype = Sys->QTDIR;
	else
		d.qid.qtype = Sys->QTFILE;
	d.mode = perm;
	return d;
}


child(pidc : chan of array of byte, cmd : string) {
    res := array [1024] of byte;

    fds := array[2] of ref Sys->FD;
    sys->pipe(fds);

    sync := chan of int;
    spawn async(sync, fds[1].fd, cmd);
    <- sync;
    fds[1] = nil;

    got := 0;
    for (;;) {
        n := sys->read(fds[0] , res[got:], len res - got);
        if (n <= 0)
             break;
        got += n;
        if (n == len res)
              res = (array [2* len res] of byte)[:] = res;
    }
    pidc <-= res[:got];
}

async(sync: chan of int, outfd: int, cmd: string)
{
    sys->pctl(Sys->NEWFD|Sys->FORKNS|Sys->NEWPGRP, outfd::nil);
    sys->dup(outfd, 1);
    sync <-= 1;
    sh->system(nil, cmd);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.