Compare commits
104 Commits
Author | SHA1 | Date |
---|---|---|
Izaya | ac27dc473c | |
Izaya | 249b4c4614 | |
Izaya | 57a37f8a76 | |
Izaya | 829f423dc2 | |
Izaya | aeffadfff8 | |
Izaya | 0eb85d39e5 | |
Izaya | c347f6daa4 | |
Izaya | d8d74fc627 | |
Izaya | d37cc4a155 | |
Izaya | dcf5cf7c35 | |
Izaya | ecb0ae6b46 | |
Izaya | 8192e62ebd | |
Izaya | 38f6982e39 | |
Izaya | e7f13d8767 | |
Izaya | cdc655179a | |
Izaya | 5ef48aeb64 | |
Izaya | 0341a38a5b | |
Izaya | e27b9d08ee | |
Izaya | 6ef7b422a1 | |
Izaya | 57a23dca35 | |
Izaya | 699a88bc42 | |
Izaya | 72159fa124 | |
Izaya | 9f3d5ab19a | |
Izaya | 10ebeaefa9 | |
Izaya | 325e540905 | |
Izaya | 275c50c10d | |
Izaya | 83e26739a5 | |
Izaya | d242c38fcb | |
Izaya | 3e15ffa6ed | |
Izaya | 110c3e5886 | |
Izaya | c5307a7433 | |
Izaya | d736491628 | |
Izaya | 83a84ea117 | |
Izaya | 0e3d368896 | |
Izaya | bbead5d252 | |
Izaya | 3a3e83691a | |
Izaya | 0bb3921781 | |
Izaya | b9916c2b13 | |
Izaya | 0682c50879 | |
Izaya | bbe9d4ac51 | |
Izaya | d58605431e | |
Izaya | d320de1866 | |
Izaya | af787e31e7 | |
Izaya | ada544d266 | |
Izaya | 67363dcf92 | |
Izaya | 76837876d6 | |
Izaya | e9227ce08a | |
Izaya | e1f8f6697e | |
Izaya | a6e6bb5f6b | |
Izaya | 92a8066890 | |
Izaya | 690101d41c | |
Izaya | c9f64c00c7 | |
Izaya | d63163df70 | |
Izaya | 31309f3d2d | |
Izaya | 9def569a2a | |
Izaya | 776dca5f27 | |
Izaya | 334f3a4d50 | |
Izaya | faac6621a5 | |
Izaya | 599f685b8c | |
Izaya | cc7df2a95d | |
Izaya | 1ffec30452 | |
Izaya | ae083f57d9 | |
Izaya | 4e3b65ad38 | |
Izaya | dcb37236af | |
Izaya | cab958f677 | |
Izaya | ed7032c274 | |
Izaya | d6b9b1db3a | |
Izaya | 83ed6019cd | |
Izaya | 4b89084432 | |
Izaya | 8458bf5fc7 | |
Izaya | 10f7a53cdd | |
Izaya | bd6ff99818 | |
Izaya | cd30afb56a | |
Izaya | bec129c2fc | |
Izaya | 124de18ed2 | |
Izaya | 8778b140a1 | |
Izaya | 92eaeb4c46 | |
Izaya | 337e9d7c9f | |
Izaya | e2b315e5b3 | |
Izaya | 3774580806 | |
Izaya | b04d700f94 | |
Izaya | d60c10baa0 | |
Izaya | 99b4bc3b71 | |
Izaya | 0f08d6caa0 | |
Izaya | 55eb012e16 | |
Izaya | 237b1c5e09 | |
Izaya | 0918704357 | |
Izaya | 519b63c627 | |
Izaya | ed8aca42e0 | |
Izaya | b271341b2b | |
Izaya | a7a463c38d | |
Izaya | 3cf9a5e42a | |
Izaya | 50d77f2904 | |
Izaya | 3c6ac7db1a | |
Izaya | 1e8c16e691 | |
Izaya | 8f80df31ea | |
Izaya | 580f975263 | |
Izaya | 3c84f6224b | |
Izaya | 3138eb29b8 | |
Izaya | 5fcc09e03c | |
Izaya | 67356aa589 | |
Izaya | 366a420930 | |
Izaya | 016e4f2d58 | |
Izaya | c1005e3ae6 |
|
@ -1,4 +1,5 @@
|
|||
out/*
|
||||
kernel.lua
|
||||
skernel.lua
|
||||
header.lua
|
||||
*.swp
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
lexec genheader.lua
|
||||
ofile out/everything.lua
|
||||
header.lua
|
||||
modules/base/loadlin.lua
|
||||
modules/debug/log.lua
|
||||
modules/base/header.lua
|
||||
modules/base/component.lua
|
||||
modules/lib/fs.lua
|
||||
modules/util/logflush.lua
|
||||
modules/lib/buffer.lua
|
||||
modules/lib/io.lua
|
||||
modules/drivers/vt52.lua
|
||||
modules/drivers/fastty.lua
|
||||
modules/lib/print.lua
|
||||
modules/drivers/kbd.lua
|
||||
modules/lib/cdlib.lua
|
||||
|
@ -16,7 +18,7 @@ modules/util/motd.lua
|
|||
modules/lib/readline.lua
|
||||
modules/lib/shutil.lua
|
||||
fwrap shutil.cat exec/cat.lua
|
||||
fwrap shutil.mem exec/free.lua
|
||||
fwrap shutil.free exec/free.lua
|
||||
fwrap shutil.ls exec/ls.lua
|
||||
fwrap shutil.ps exec/ps.lua
|
||||
alias shutil.cd fs.cd
|
||||
|
@ -25,15 +27,16 @@ alias shutil.mkdir fs.mkdir
|
|||
alias shutil.cp fs.cp
|
||||
alias shutil.mv fs.mv
|
||||
libwrap sha modules/lib/sha256.lua
|
||||
modules/net/net-ext.lua
|
||||
modules/applications/login.lua
|
||||
modules/applications/genkernel.lua
|
||||
fwrap luash exec/luash.lua
|
||||
fwrap lush exec/lush.lua
|
||||
alias shell lush
|
||||
fwrap skex exec/skex2.lua
|
||||
fwrap nshd exec/nshd.lua
|
||||
fwrap nsh exec/nsh.lua
|
||||
fwrap wget exec/wget.lua
|
||||
fwrap pkg exec/pkg.lua
|
||||
modules/util/fs-automount.lua
|
||||
modules/setup.lua
|
||||
modules/util/autorun.lua
|
||||
modules/base/footer.lua
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
lexec genheader.lua
|
||||
ofile out/headless.lua
|
||||
header.lua
|
||||
modules/base/loadlin.lua
|
||||
modules/debug/log.lua
|
||||
modules/base/header.lua
|
||||
|
@ -23,14 +26,15 @@ alias shutil.mkdir fs.mkdir
|
|||
alias shutil.cp fs.cp
|
||||
alias shutil.mv fs.mv
|
||||
modules/lib/sha256.lua
|
||||
modules/net/net-ext.lua
|
||||
modules/applications/login.lua
|
||||
fwrap luash exec/luash.lua
|
||||
fwrap lush exec/lush.lua
|
||||
alias shell lush
|
||||
modules/applications/genkernel.lua
|
||||
fwrap skex exec/skex2.lua
|
||||
fwrap nshd exec/nshd.lua
|
||||
fwrap nsh exec/nsh.lua
|
||||
modules/util/fs-automount.lua
|
||||
modules/setup.lua
|
||||
modules/util/autorun.lua
|
||||
modules/base/footer.lua
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
lexec genheader.lua
|
||||
ofile out/minimal.lua
|
||||
header.lua
|
||||
modules/base/loadlin.lua
|
||||
modules/debug/log.lua
|
||||
modules/base/header.lua
|
||||
|
@ -6,7 +9,7 @@ modules/lib/fs.lua
|
|||
modules/util/logflush.lua
|
||||
modules/lib/buffer.lua
|
||||
modules/lib/io.lua
|
||||
modules/drivers/vt52.lua
|
||||
modules/drivers/fastty.lua
|
||||
modules/lib/print.lua
|
||||
modules/drivers/kbd.lua
|
||||
modules/lib/cdlib.lua
|
||||
|
@ -15,12 +18,18 @@ modules/net/ncd.lua
|
|||
modules/util/motd.lua
|
||||
modules/lib/readline.lua
|
||||
modules/lib/shutil.lua
|
||||
alias shutil.cd fs.cd
|
||||
alias shutil.rm fs.rm
|
||||
alias shutil.mkdir fs.mkdir
|
||||
alias shutil.cp fs.cp
|
||||
alias shutil.mv fs.mv
|
||||
libwrap sha modules/lib/sha256.lua
|
||||
modules/net/net-ext.lua
|
||||
modules/applications/login.lua
|
||||
fwrap luash exec/luash.lua
|
||||
fwrap lush exec/lush.lua
|
||||
alias shell lush
|
||||
modules/applications/genkernel.lua
|
||||
modules/util/fs-automount.lua
|
||||
modules/setup.lua
|
||||
modules/util/autorun.lua
|
||||
modules/base/footer.lua
|
||||
|
||||
|
|
28
docs/api.md
28
docs/api.md
|
@ -27,6 +27,10 @@ Returns true or false if *pass* is the correct password for *user*.
|
|||
Generates *len* random printable characters and returns them.
|
||||
#### os.su(*user*,*pass*)
|
||||
Sets the user ID of the current process to *user* if *user* and *password* are verified by `os.verifyuser`.
|
||||
#### os.setuattr(*user*,*field*,*value*)
|
||||
Sets the *field* attribute of *user* to *value*.
|
||||
#### os.getuattr(*user*,*field*)
|
||||
Returns the value of *field* for *user*.
|
||||
|
||||
### event
|
||||
#### event.get()
|
||||
|
@ -75,6 +79,10 @@ Changes the current directory to either *path* or *os.getenv("PWD")*/*path*.
|
|||
Copies a file from *source* to *destination*.
|
||||
#### fs.mv(*source*, *destination*)
|
||||
Same as fs.cp but deletes *source* afterwards.
|
||||
#### fs.getattr(*path*,*key*)
|
||||
Returns the value of *path*'s extended attribute *key*, assuming your user ID is in the read attribute.
|
||||
#### fs.setattr(*path*,*key*,*value*)
|
||||
Set *path*'s extended attribute *key* to *value*, assuming your user ID is in the write attribute
|
||||
|
||||
### io
|
||||
#### write(...) or io.write(...)
|
||||
|
@ -93,6 +101,8 @@ Writes *data* to *fobj* (if in write mode)
|
|||
Closes *fobj*, flushing buffers and removing the object from memory.
|
||||
|
||||
### shutil
|
||||
#### exec(*command*)
|
||||
Executes *command* as if it had been typed into a shell (lush, specifically).
|
||||
#### cd(*path*)
|
||||
Alias to fs.cd
|
||||
#### rm(*path*)
|
||||
|
@ -155,15 +165,9 @@ This is triggered to make a tty driver attached to *session* write *text* to the
|
|||
|
||||
|
||||
## Applications
|
||||
### luash(*sI*)
|
||||
Spawns a luash instance for session *sI*
|
||||
### skex(*fname*)
|
||||
Launches an instance of the skex text editor, optionally reading *fname* at startup.
|
||||
May actually spawn skex2.
|
||||
### skex2(*fname*)
|
||||
Launches an instance of the skex2 text editor, optionally reading *fname* at startup.
|
||||
### nsh(*host*, *port*)
|
||||
Spawns the network shell client and attempts to connect to *host* on *port* for a remote login session.
|
||||
ctrl-shift-c to exit.
|
||||
### nshd(*port*)
|
||||
Spawns a networh shell server listening on *port.*
|
||||
### login()
|
||||
Displays a login screen allowing for changing user.
|
||||
### loginmanager(*sI*)
|
||||
Runs a program that will repeatedly display a login screen and spawn a shell on login.
|
||||
### lush(*sI*)
|
||||
Spawns a lush instance for session *sI*
|
||||
|
|
|
@ -6,36 +6,35 @@
|
|||
git clone https://github.com/XeonSquared/PsychOS.git
|
||||
```
|
||||
|
||||
### 2. Build source.
|
||||
### 2. Building on unix-like platforms
|
||||
You'll need Lua installed. It will probably work with anything from 5.1 onwards, but PsychOS is developed against 5.2.
|
||||
|
||||
```
|
||||
./genkernel.sh
|
||||
```
|
||||
|
||||
`genkernel.sh` is a wrapper script for genkernel.lua which is a wrapper program for the genkernel module that is actually used to generate the code.
|
||||
`genkernel.sh` is a wrapper script lmk that generates all the kernel configurations in config/ and places them in out/.
|
||||
|
||||
To change the modules included, modify build.cfg.
|
||||
Naturally, you can modify the configuration files or add new ones to change the modules included.
|
||||
|
||||
## Building on PsychOS
|
||||
### 1. Obtain source and relevant software.
|
||||
At present, the way to do this is "copy them onto the installation."
|
||||
**TODO: Write package recipes for the sources**
|
||||
|
||||
If genkernel() isn't included in your kernel you can run it as a program using luash's ! prefix.
|
||||
|
||||
### 2. Run genkernel()
|
||||
### 2. Build with lmk
|
||||
lmk is the Lua MaKe system used for PsychOS. The sources come with makefiles that you can use to generate a kernel.
|
||||
|
||||
```
|
||||
genkernel("/boot/PsychOS/build.cfg","custom")
|
||||
cd kernel_source_dir
|
||||
lmk configs/everything.lua
|
||||
```
|
||||
|
||||
This will generate a kernel from the files listed in /boot/PsychOS/build.cfg with "custom" as part of the kernel name and return the resulting kernel as a string. You can then write that string to a file or similar.
|
||||
This will build the "everything" kernel. You can use a different configuration file if you want to generate another kernel.
|
||||
|
||||
## Files
|
||||
### genkernel.sh
|
||||
genkernel.sh calls `genkernel.lua build.cfg`.
|
||||
### genkernel.lua
|
||||
Wrapper for modules/applications/genkernel.lua. Runs it with arguments.
|
||||
### modules/applications/genkernel.lua
|
||||
Both a PsychOS module and usable as a program.
|
||||
#### genkernel(*bp*, *kn*)
|
||||
Builds a kernel using the modules listed in *bp*, with \_OSNAME including *kn*.
|
||||
You can then try loading the new kernel to check for errors:
|
||||
|
||||
```
|
||||
=loadfile("out/everything.lua")
|
||||
```
|
||||
|
||||
If there are no errors, it's probably safe to move it to your /boot/init.lua.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## PsychOS
|
||||
|
||||
PsychOS is a single-user cooperative multitasking operating system for OpenComputers.
|
||||
PsychOS is a multi-user cooperative multitasking operating system for OpenComputers.
|
||||
|
||||
### System requirements:
|
||||
|
||||
|
@ -20,7 +20,16 @@ PsychOS is a single-user cooperative multitasking operating system for OpenCompu
|
|||
|
||||
### Documentation
|
||||
|
||||
- User guide (WIP)
|
||||
- [Installation guide](install.html)
|
||||
- [User guide](userguide.html)
|
||||
- [Building PsychOS](building.html)
|
||||
- [API documentation](api.html)
|
||||
- [Filesystem layout](fhs.html)
|
||||
|
||||
### Sources and contributing
|
||||
|
||||
PsychOS has its [source code on GitHub](https://github.com/XeonSquared/PsychOS) and is open to pull requests, bug reports and other forms of contribution.
|
||||
|
||||
In addition, some [extra PsychOS related projects](https://git.shadowkat.net/izaya/psychos-programs) can be found on the [SKS Gogs](https://git.shadowkat.net) instance
|
||||
|
||||
For support, discussion or general chat, you can use the [SKS IRC channel on EsperNet](irc://irc.esper.net/#SKS) ([webchat](https://webchat.esper.net/?channels=SKS)).
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
# Installing PsychOS
|
||||
|
||||
## Step 0: Information
|
||||
PsychOS requires the following hardware:
|
||||
|
||||
- 150K RAM
|
||||
- 40K storage, preferably on its own disk
|
||||
|
||||
In addition, this guide assumes the machine has an internet card to download files with. It's possible to install PsychOS from an existing copy but that is out of scope of this guide.
|
||||
|
||||
You will want to know the address of the disk you plan to install PsychOS onto.
|
||||
|
||||
### Useful key combinations:
|
||||
`ctrl-shift-c` inside PsychOS will cancel text input or stop certain programs.
|
||||
|
||||
`ctrl-shift-r` will soft-reboot the machine, preserving the content of */tmp*.
|
||||
|
||||
## Step 1: Obtaining and booting a copy of PsychOS
|
||||
From OpenOS:
|
||||
|
||||
```
|
||||
cd /tmp
|
||||
wget https://oc.shadowkat.net/PsychOS/build/fsdev/PsychOS-fsdev-latest/severything.lua init.lua
|
||||
init.lua
|
||||
```
|
||||
|
||||
If you are unable to donload the file, try http rather than https.
|
||||
The 'same file' error is normal.
|
||||
|
||||
These commands will reboot your machine into PsychOS running from the computer's temporary filesystem. Following this, you should see something like
|
||||
|
||||
```
|
||||
PsychOS 83e2673 on 404cf459, 256K memory
|
||||
lush v1/Lua 5.2
|
||||
[superuser@404cf459 /boot]#
|
||||
```
|
||||
|
||||
## Step 2: Downloading to a disk
|
||||
From your prompt, you'll want to invoke pkg to download a copy of PsychOS onto a disk. The path of the disk is `/<the first 3 characters of the disk address>/`
|
||||
You can also use /tmp/ if you want a full live system. At present this uses about 50k out of the 64k available on /tmp/
|
||||
|
||||
```
|
||||
[superuser@404cf459 /boot]# pkg install https://oc.shadowkat.net/PsychOS/build/fsdev/PsychOS-fsdev-latest/psychos-latest.pkr /<disk>/
|
||||
```
|
||||
|
||||
This will take a while, but will output progress.
|
||||
|
||||
If the machine hangs, use the http version of the recipe file:
|
||||
|
||||
```
|
||||
http://oc.shadowkat.net/PsychOS/build/fsdev/PsychOS-fsdev-latest/psychos-latest-http.pkr
|
||||
```
|
||||
|
||||
Once that has completed, power your machine off and take out all but the disk you installed PsychOS onto, then boot it up.
|
||||
|
||||
## Step 3: Configuration
|
||||
This step is optional.
|
||||
|
||||
Now that you have a working PsychOS system, you can set up users.
|
||||
|
||||
### superuser
|
||||
Superuser is the most powerful user on the system, and should have a strong password.
|
||||
|
||||
```
|
||||
[superuser@404cf459 /boot]# passwd superuser
|
||||
New password for superuser: ********
|
||||
```
|
||||
|
||||
### A non-superuser
|
||||
Running as superuser all the time is bad for security, so you should create a user for yourself.
|
||||
```
|
||||
[superuser@404cf459 /boot]# passwd username
|
||||
New password for username: ********
|
||||
```
|
||||
|
||||
Now, if you press ctrl-alt-c, it should bring up a login screen.
|
||||
|
||||
Congratulations, you now have a functional and configured PsychOS system.
|
|
@ -0,0 +1,74 @@
|
|||
# PsychOS user guide
|
||||
|
||||
## Useful key combinations:
|
||||
`ctrl-shift-c` inside PsychOS will cancel text input or stop certain programs.
|
||||
|
||||
`ctrl-shift-r` will soft-reboot the machine, preserving the content of */tmp*
|
||||
|
||||
## The lush shell
|
||||
lush is the default shell of PsychOS. It allows executing functions in memory, programs on disk and Lua typed directly into lush, in order of preference.
|
||||
|
||||
The default prompt is `[<user>@<hostname> <current directory>]$`
|
||||
|
||||
When you enter a command, lush will first check for functions with the given name.
|
||||
If there's no function with the name, it will check for a files with the name in every directory in the PATH environment variable.
|
||||
If lush can't find a file with that name, it will try to execute the line as Lua.
|
||||
|
||||
So, if one were to enter
|
||||
|
||||
```
|
||||
ps
|
||||
```
|
||||
|
||||
lush checks for a function called ps, which in this case, it finds, and executes:
|
||||
|
||||
```
|
||||
PID User Name
|
||||
3 superu logflushd
|
||||
4 superu ncd
|
||||
5 superu tty[randomstringabcd]: 8f01b7c7,89734f0
|
||||
6 superu kbd: 1f46ed58
|
||||
7 superu kbd-clibboard: 1f46ed58
|
||||
8 superu login manager: randomstringabcd
|
||||
```
|
||||
|
||||
Okay, but what if there was no function?
|
||||
You enter
|
||||
|
||||
```
|
||||
count
|
||||
```
|
||||
|
||||
and there's no function called count, but there is a file called count.lua in the current directory:
|
||||
|
||||
```
|
||||
for i = 1, 5 do
|
||||
print(i)
|
||||
end
|
||||
```
|
||||
|
||||
lush will look for the function, not find it, see the file, and try to execute it:
|
||||
|
||||
```
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
```
|
||||
|
||||
And last, if you enter the Lua code:
|
||||
|
||||
```
|
||||
for i = 1, 5 do print(i) end
|
||||
```
|
||||
|
||||
lush will look for a function called for and not find it (magic is involved to make this sane), a file named for or for.lua, not find it, then fall back to executing Lua:
|
||||
|
||||
```
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
local tA = {...}
|
||||
if #tA < 3 then return false, "not enough arguments" end
|
||||
local rwx = table.remove(tA,1):sub(1,1):lower()
|
||||
if rwx ~= "r" and rwx ~= "w" and rwx ~= "x" then return false, "not a valid mode" end
|
||||
local trwx = {r = "read", w = "write", x = "execute"}
|
||||
local nrwx = trwx[rwx]
|
||||
local un = table.remove(tA,1)
|
||||
for k,v in ipairs(tA) do
|
||||
local cacl = fs.parseacl(fs.getattr(v,nrwx)) or {}
|
||||
cacl[un] = true
|
||||
local sacl = ""
|
||||
for l,m in pairs(cacl) do
|
||||
if m then
|
||||
sacl = l .. ","
|
||||
end
|
||||
end
|
||||
print(v.."\t"..nrwx.." = "..sacl)
|
||||
fs.setattr(v,nrwx,sacl)
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
local tA = {...}
|
||||
local modlistf = tA[1]
|
||||
local nk = ""
|
||||
local oprint = print
|
||||
print(modlistf)
|
||||
function print(...)
|
||||
if tA[2] then
|
||||
oprint(...)
|
||||
end
|
||||
end
|
||||
f = io.open(modlistf,"rb")
|
||||
if not f then error("no input file") end
|
||||
local ofile = nil
|
||||
local c=f:read("*a")
|
||||
f:close()
|
||||
local n=1
|
||||
local function wcfile()
|
||||
if ofile then
|
||||
f=io.open(ofile,"wb")
|
||||
if f then
|
||||
oprint("writing file "..ofile)
|
||||
f:write(nk)
|
||||
f:close()
|
||||
else
|
||||
oprint("warning: unable to open file "..ofile.." to write")
|
||||
end
|
||||
end
|
||||
end
|
||||
local function apfile(fp)
|
||||
local f=io.open(fp,"rb")
|
||||
if f then
|
||||
nk=nk..f:read("*a")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
for line in c:gmatch("[^\r\n]+") do
|
||||
print(line)
|
||||
local tw = {}
|
||||
for w in line:gmatch("%S+") do
|
||||
tw[#tw+1] = w
|
||||
end
|
||||
n=n+1
|
||||
if tw[1] == "ofile" then
|
||||
wcfile()
|
||||
ofile = tw[2]
|
||||
nk=""
|
||||
elseif tw[1] == "exec" then
|
||||
os.execute(tw[2])
|
||||
elseif tw[1] == "lexec" then
|
||||
local f=io.open(tw[2],"rb")
|
||||
if f then
|
||||
local fc = f:read("*a")
|
||||
print(fc)
|
||||
print(pcall(load(fc)))
|
||||
end
|
||||
f:close()
|
||||
elseif tw[1] == "fwrap" then
|
||||
nk=nk.."function "..tw[2].."(...)\n"
|
||||
apfile(tw[3])
|
||||
nk=nk.."\nend\n"
|
||||
elseif tw[1] == "libwrap" then
|
||||
nk=nk.."function "..tw[2].."(...)\n"
|
||||
apfile(tw[3])
|
||||
nk=nk.."\nend\n_G."..tw[2].." = "..tw[2].."()\n"
|
||||
elseif tw[1] == "alias" then
|
||||
nk=nk..tw[2].."="..tw[3].."\n"
|
||||
elseif tw[1] == "include" then
|
||||
apfile(tw[2])
|
||||
elseif #tw == 1 then
|
||||
apfile(line)
|
||||
end
|
||||
end
|
||||
wcfile()
|
|
@ -1,48 +0,0 @@
|
|||
local tA = {...}
|
||||
local si = tA[1]
|
||||
spawn("lua shell",function()
|
||||
_ENV = shutil.genenv()
|
||||
coroutine.yield()
|
||||
log(pcall(login))
|
||||
print(_VERSION)
|
||||
while true do
|
||||
write((os.getenv("PWD") or "").."> ")
|
||||
local inp=readln()
|
||||
if not inp then break end
|
||||
if inp:sub(1,1) == "!" then
|
||||
local pth = os.getenv("PATH") or "."
|
||||
local s,ptt = inp:sub(2), {}
|
||||
for w in s:gmatch("%S+") do table.insert(ptt,w) end
|
||||
local prg = table.remove(ptt,1)
|
||||
for d in pth:gmatch("[^:]+") do
|
||||
_,lex = pcall(fs.exists,d.."/"..prg..".lua")
|
||||
_,nex = pcall(fs.exists,d.."/"..prg)
|
||||
if lex then
|
||||
run(d.."/"..prg..".lua",table.unpack(ptt))
|
||||
break
|
||||
elseif nex then
|
||||
run(d.."/"..prg,table.unpack(ptt))
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif inp:sub(1,1) == "$" then
|
||||
local s,ptt = inp:sub(2), {}
|
||||
for w in s:gmatch("%S+") do table.insert(ptt,w) end
|
||||
local prg = table.remove(ptt,1)
|
||||
local r={pcall(_ENV[prg],table.unpack(ptt))}
|
||||
if r[1] == true then
|
||||
table.remove(r,1)
|
||||
end
|
||||
print(table.unpack(r))
|
||||
else
|
||||
if inp:sub(1,1) == "=" then
|
||||
inp="return "..inp:sub(2)
|
||||
end
|
||||
local r={pcall(load(inp,"shell","bt",_ENV))}
|
||||
if r[1] == true then
|
||||
table.remove(r,1)
|
||||
end
|
||||
print(table.unpack(r))
|
||||
end
|
||||
end
|
||||
end,{sI=si})
|
|
@ -0,0 +1,20 @@
|
|||
local tA = {...}
|
||||
local si = tA[1] or os.getenv("sI")
|
||||
os.setenv("sI",si)
|
||||
_ENV = shutil.genenv()
|
||||
print("lush v1/".._VERSION)
|
||||
os.setenv("PSF",function()
|
||||
local ps = "["..os.getuid().."@"..net.id.." "..(os.getenv("PWD") or "").."]"
|
||||
if os.getuid() == "superuser" then ps = ps .. "# " else ps = ps .. "$ " end
|
||||
return ps end)
|
||||
while true do
|
||||
local didexec = false
|
||||
write(os.getenv("PSF")())
|
||||
local inp=readln()
|
||||
if not inp then break end
|
||||
local rt = {shutil.exec(inp)}
|
||||
if rt[1] == true then
|
||||
table.remove(rt,1)
|
||||
end
|
||||
print(table.unpack(rt))
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
while true do
|
||||
local line = readln()
|
||||
if not line then break end
|
||||
print(pcall(load(line)))
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
local tA = {...}
|
||||
local nport = tonumber(tA[1])
|
||||
local fpath = tostring(tA[2])
|
||||
for m in component.list("modem") do
|
||||
print("[nbsrv] opening port on "..m)
|
||||
component.invoke(m,"open",nport)
|
||||
end
|
||||
local f=io.open(fpath,"rb")
|
||||
local nbdata = f:read("*a")
|
||||
f:close()
|
||||
spawn("nbsrv: "..tostring(nport)..","..fpath,function() print(xpcall(function()
|
||||
while true do
|
||||
local _, laddress, raddress, port, _, payload = event.pull("modem_message")
|
||||
if port == nport and type(payload) == "string" then
|
||||
if payload:len() == 36 then
|
||||
local sraddress,spayload = raddress:sub(1,8),payload:sub(1,8)
|
||||
print("[nbsrv] request from "..sraddress.."/"..spayload.." on port "..tostring(port))
|
||||
for i = 1, nbdata:len(), 2048 do
|
||||
component.invoke(laddress,"send",raddress,port,nbdata:sub(i,i+2047))
|
||||
end
|
||||
component.invoke(laddress,"send",raddress,port,".")
|
||||
print("[nbsrv] served request from "..sraddress.."/"..spayload)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)) end)
|
||||
print("[nbsrv] nbsrv started.")
|
|
@ -1,4 +1,6 @@
|
|||
local tA = {...}
|
||||
local s=os.gensalt(16)
|
||||
tA[1] = tA[1] or os.getuid()
|
||||
io.write("New password for "..tA[1]..": ")
|
||||
os.setuser(tA[1],sha.sha256(io.read("*")..s),s)
|
||||
os.setuattr(tA[1],"hpass",sha.sha256(io.read("*")..s))
|
||||
os.setuattr(tA[1],"salt",s)
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
local tA = {...}
|
||||
local rf = tA[2]
|
||||
local wget = wget or loadfile("/boot/exec/wget.lua")
|
||||
if not wget then
|
||||
print("wget is required to run this program")
|
||||
elseif rf and pcall(fs.exists,rf) then
|
||||
local pref = tA[3] or "/boot/"
|
||||
local mode = "install"
|
||||
if tA[1]:sub(1,1) == "r" then
|
||||
mode = "remove"
|
||||
end
|
||||
local files = {}
|
||||
local lrf = "/tmp/rf.txt"
|
||||
|
||||
local function precipe(s)
|
||||
local t = {}
|
||||
for line in s:gmatch("[^\n\r]+") do
|
||||
t[#t+1] = {line:match("(.+)[ \t](.+)")}
|
||||
local S = t[#t][1]
|
||||
t[#t][1] = ""
|
||||
for c in S:gmatch(".") do
|
||||
if (string.byte(c) > 31 and string.byte(c) < 127) then
|
||||
t[#t][1] = t[#t][1]..c
|
||||
end
|
||||
local S = t[#t][2]
|
||||
t[#t][2] = ""
|
||||
for c in S:gmatch(".") do
|
||||
if (string.byte(c) > 31 and string.byte(c) < 127) then
|
||||
t[#t][2] = t[#t][2]..c
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
local function dl(p,u)
|
||||
if u:sub(1,8) == "https://" or u:sub(1,7) == "http://" then
|
||||
wget(u,pref..p)
|
||||
elseif u == "dir" then
|
||||
fs.mkdir(pref..p)
|
||||
else
|
||||
fs.cp(u,pref..p)
|
||||
end
|
||||
end
|
||||
|
||||
if rf:sub(1,8) == "https://" or rf:sub(1,7) == "http://" then
|
||||
wget(rf,"/tmp/rf.txt")
|
||||
else
|
||||
lrf = rf
|
||||
end
|
||||
|
||||
local f=io.open(lrf)
|
||||
if not f then return false, "no recipe" end
|
||||
files=precipe(f:read("*a"))
|
||||
f:close()
|
||||
local total = #files
|
||||
|
||||
print(mode.." the following files to "..pref.."?")
|
||||
for k,v in ipairs(files) do io.write(v[2].." ") end
|
||||
io.write("\n[yN] ")
|
||||
local c = io.read():lower():sub(1,1)
|
||||
if c ~= "y" then return false, "aborted" end
|
||||
|
||||
for k,v in ipairs(files) do
|
||||
print(tostring(k).."/"..tostring(total)..": "..pref..v[2])
|
||||
if mode == "install" then
|
||||
dl(v[2],v[1])
|
||||
elseif mode == "remove" then
|
||||
fs.rm(pref..v[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
local tA = {...}
|
||||
if #tA < 3 then return false, "not enough arguments" end
|
||||
local rwx = table.remove(tA,1):sub(1,1):lower()
|
||||
if rwx ~= "r" and rwx ~= "w" and rwx ~= "x" then return false, "not a valid mode" end
|
||||
local trwx = {r = "read", w = "write", x = "execute"}
|
||||
local nrwx = trwx[rwx]
|
||||
local un = table.remove(tA,1)
|
||||
for k,v in ipairs(tA) do
|
||||
local cacl = fs.parseacl(fs.getattr(v,nrwx)) or {}
|
||||
cacl[un] = false
|
||||
local sacl = ""
|
||||
for l,m in pairs(cacl) do
|
||||
if m then
|
||||
sacl = l .. ","
|
||||
end
|
||||
end
|
||||
print(v.."\t"..nrwx.." = "..sacl)
|
||||
fs.setattr(v,nrwx,sacl)
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
local tA = {...}
|
||||
local wget = wget or loadfile("/boot/exec/wget.lua")
|
||||
if not wget then
|
||||
print("wget is required to run this program")
|
||||
else
|
||||
local repo = tA[1] or "https://lain.shadowkat.net/~izaya/ocdoc/PsychOS-build/fsdev/PsychOS-fsdev-latest/"
|
||||
local fl = repo .. "files.txt"
|
||||
local pref = tA[1] or "/boot/"
|
||||
local files = {{"everything"},{"minimal"},{"headless"},{"severything"},{"sminimal"},{"sheadless"},{"exec/addperm"},{"exec/cat"},{"exec/free"},{"exec/ls"},{"exec/luash"},{"exec/nbsrv"},{"exec/nshd"},{"exec/nsh"},{"exec/passwd"},{"exec/ps"},{"exec/rmperm"},{"exec/skex2"},{"exec/su"},{"exec/wget"},{"exec/update.lua"},{"exec/pkg.lua"}}
|
||||
local count = 1
|
||||
local total = #files
|
||||
print(total)
|
||||
for k,v in ipairs(files) do
|
||||
print(tostring(count).."/"..tostring(total)..": "..pref..v[1]..".lua")
|
||||
print(repo..v[1]..".lua",pref..v[1]..".lua")
|
||||
wget(repo..v[1]..".lua",pref..v[1]..".lua")
|
||||
count=count+1
|
||||
end
|
||||
end
|
||||
|
|
@ -8,8 +8,14 @@ if not f then return false end
|
|||
repeat
|
||||
coroutine.yield()
|
||||
until R.finishConnect()
|
||||
local code, msg = R.response()
|
||||
if code ~= 200 then
|
||||
return false, code, msg
|
||||
end
|
||||
repeat
|
||||
coroutine.yield()
|
||||
local t,c,C = event.get()
|
||||
if t == "key" and c == 3 and C == 46 then break end
|
||||
ns = R.read(2048)
|
||||
f:write(ns or "")
|
||||
until not ns
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
local f = io.open("header.lua","wb")
|
||||
local kname = nil
|
||||
if not _OSNAME then
|
||||
local w,gn = pcall(io.popen,"git rev-parse HEAD")
|
||||
if w then
|
||||
kname = gn:read():sub(1,7)
|
||||
gn:close()
|
||||
end
|
||||
end
|
||||
f:write("_OSVERSION=\"PsychOS "..(kname or os.date("%Y/%m/%d %H:%M %z")).."\"\n")
|
||||
f:write("_BD=\""..os.date("%Y/%m/%d %H:%M %z").."\"\n")
|
||||
f:close()
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env lua
|
||||
require "modules/applications/genkernel"
|
||||
print(genkernel(...))
|
|
@ -2,6 +2,6 @@
|
|||
mkdir -p out/
|
||||
for f in `dir -d configs/*`; do
|
||||
kn=$(echo $f | cut -f 1 -d '.' | cut -f 2 -d "/")
|
||||
./genkernel.lua $f "$(git rev-parse --short HEAD)" > out/$kn.lua
|
||||
lua exec/lmk.lua $f
|
||||
lua strip.lua out/$kn.lua out/s$kn.lua
|
||||
done
|
||||
|
|
|
@ -4,11 +4,22 @@ function login()
|
|||
if #os.users() > 0 then
|
||||
repeat
|
||||
io.write(net.id.." login: ")
|
||||
un = io.read()
|
||||
un = io.read()
|
||||
io.write("Password: ")
|
||||
pw = io.read("*")
|
||||
cc = os.su(un,pw)
|
||||
pw = io.read("*")
|
||||
cc = os.su(un,pw)
|
||||
until cc
|
||||
return true
|
||||
end
|
||||
end
|
||||
function loginmanager(sI)
|
||||
spawn("login manager: "..sI or os.getenv("sI"), function()
|
||||
if sI then os.setenv("sI",sI) end
|
||||
while true do
|
||||
login()
|
||||
local _,nshell = pcall(loadfile,os.getuattr(os.getuid(),"shell"))
|
||||
if type(nshell) ~= "function" then nshell = shell end
|
||||
pcall(nshell,sI)
|
||||
print(" ")
|
||||
end
|
||||
end) end
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
function skex(s)
|
||||
local c,cs,cT,lT,lP="","",{},{},1
|
||||
local function lf(s)
|
||||
local f=io.open(s,"rb")
|
||||
c=f:read("*a")
|
||||
f:close()
|
||||
end
|
||||
local function wf(s)
|
||||
local f,c=io.open(s,"wb")
|
||||
for k,v in ipairs(lT) do f:write(v.."\n") end
|
||||
f:close()
|
||||
end
|
||||
if s then
|
||||
lf(s)
|
||||
for l in c:gmatch("[^\n]+") do lT[#lT+1]=l end
|
||||
end
|
||||
while true do
|
||||
cs=io.read()
|
||||
cT={}
|
||||
for w in cs:gmatch("%S+") do cT[#cT+1]=w end
|
||||
if cT[1] == "q" then break
|
||||
elseif cT[1] == "l" then
|
||||
for i = (tonumber(cT[2]) or 1), (tonumber(cT[3]) or #lT) do
|
||||
if lT[i] then
|
||||
print(tostring(i).."\t"..(lT[i] or ""))
|
||||
end
|
||||
end
|
||||
elseif cT[1] == "a" or cT[1] == "i" or cT[1] == "s" then
|
||||
if tonumber(cT[2]) then lP=tonumber(cT[2]) end
|
||||
if cT[1] == "s" then for i = 1,tonumber(cT[3]) do table.remove(lT,i+(tonumber(cT[2])-1)) end end
|
||||
if cT[1] == "a" then lP=lP+1 end
|
||||
while true do
|
||||
cs=io.read()
|
||||
if cs~="." then
|
||||
table.insert(lT,lP,cs)
|
||||
lP=lP+1
|
||||
else break end
|
||||
end
|
||||
elseif cT[1] == "f" then
|
||||
s=cT[2] or s
|
||||
print(s)
|
||||
elseif cT[1] == "e" then
|
||||
c=""
|
||||
for k,v in ipairs(lT) do c=c..v.."\n" end
|
||||
print(pcall(load(c)))
|
||||
elseif cT[1] == "r" then
|
||||
s=cT[2] or s
|
||||
wf(s)
|
||||
elseif cT[1] == "w" then
|
||||
s=cT[2] or s
|
||||
wf(s)
|
||||
elseif cT[1] == "d" then
|
||||
for i = 1, tonumber(cT[3])-tonumber(cT[2]) do
|
||||
table.remove(lT,cT[2])
|
||||
end
|
||||
elseif cT[1] == "p" then
|
||||
lP=tonumber(cT[2]) or lP
|
||||
print(lP)
|
||||
elseif cs:sub(1,1) == "!" then
|
||||
c=""
|
||||
for k,v in ipairs(lT) do c=c..v.."\n" end
|
||||
print(pcall(load(cs:sub(2))))
|
||||
else
|
||||
print("?")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -112,7 +112,9 @@ do -- so local works
|
|||
local f = fs.open("/boot/sys/users.dat","wb")
|
||||
if f then
|
||||
for k,v in pairs(ut) do
|
||||
fs.write(f,k.."\t"..v[1].."\t"..v[2].."\n")
|
||||
for l,m in pairs(v) do
|
||||
fs.write(f,k.."\t"..l.."\t"..m.."\n")
|
||||
end
|
||||
end
|
||||
fs.close(f)
|
||||
return true
|
||||
|
@ -125,9 +127,10 @@ do -- so local works
|
|||
local C=fs.readall(f)
|
||||
fs.close(f)
|
||||
for line in C:gmatch("[^\n]+") do
|
||||
local username,hpass,salt = line:match("(.+)\t(.+)\t(.+)")
|
||||
if username and hpass and salt then
|
||||
ut[username] = {hpass,salt}
|
||||
local username,field,val = line:match("(.+)\t(.+)\t(.+)")
|
||||
if username and field and val then
|
||||
if not ut[username] then ut[username] = {} end
|
||||
ut[username][field] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -140,6 +143,7 @@ do -- so local works
|
|||
end
|
||||
function os.getuid(pid)
|
||||
pid = pid or cT
|
||||
if not tT[pid] then return "superuser" end
|
||||
return tT[pid].u
|
||||
end
|
||||
function os.users()
|
||||
|
@ -152,7 +156,8 @@ do -- so local works
|
|||
function os.verifyuser(username,pass)
|
||||
if sha then
|
||||
if ut[username] then
|
||||
if sha.sha256(pass..ut[username][2]) == ut[username][1] then
|
||||
if not os.getuattr(username,"hpass") or not os.getuattr(username,"salt") then return true end
|
||||
if sha.sha256(pass..ut[username].salt) == ut[username].hpass then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -167,16 +172,24 @@ do -- so local works
|
|||
end
|
||||
return S
|
||||
end
|
||||
function os.setuser(username,hpass,salt,...)
|
||||
if tT[cT].u == "superuser" then
|
||||
if hpass == nil then
|
||||
function os.setuattr(username,field,val)
|
||||
if os.getuid() == "superuser" or os.getuid() == username then
|
||||
if not field then
|
||||
ut[username] = nil
|
||||
else
|
||||
ut[username] = {hpass, salt,...}
|
||||
if not ut[username] then ut[username] = {} end
|
||||
ut[username][field] = val
|
||||
log("set "..username.."."..field.." to "..val)
|
||||
flushut()
|
||||
end
|
||||
end
|
||||
end
|
||||
function os.getuattr(username,field)
|
||||
if os.getuid() == "superuser" or os.getuid() == username then
|
||||
local uT = ut[username] or {}
|
||||
return uT[field]
|
||||
end
|
||||
end
|
||||
function os.su(user,pass)
|
||||
if os.verifyuser(user,pass) then
|
||||
log(tT[cT].u .. " su'd to "..user,6,1,true)
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
if component then
|
||||
function log(...)
|
||||
for k,v in ipairs({...}) do
|
||||
component.invoke(component.list("ocemu")(),"log",v)
|
||||
end
|
||||
end
|
||||
print=log
|
||||
else log = print
|
||||
end
|
||||
do -- so local works
|
||||
-- task format:
|
||||
-- {
|
||||
-- ["n"] = "name",
|
||||
-- ["c"] = coroutine of task,
|
||||
-- ["e"] = { table, of, environment, variables },
|
||||
-- ["p"] = parent pid,
|
||||
-- ["u"] = user ID,
|
||||
-- ["ep"]= event queue pointer
|
||||
-- }
|
||||
local tT,nP,rg,eq,p = {},1,_G,{},1 -- taskTable,nextPid,real _G,event queue
|
||||
_G.cT,sbt,C,T = 0,{},coroutine,table -- currentTask,sandboxTable
|
||||
function _G.spawn(n,f,e)
|
||||
tT[nP] = {}
|
||||
sbt[nP] = {}
|
||||
setmetatable(sbt[nP],{__index=_G})
|
||||
_ENV = sbt[nP]
|
||||
tT[nP].c = coroutine.create(f)
|
||||
_ENV = rg
|
||||
tT[nP].n = n
|
||||
tT[nP].p = cT or -1
|
||||
if tT[cT] then
|
||||
tT[nP].u,tT[nP].ep,tT[nP].e = tT[cT].u,tT[cT].ep,e or tT[cT].e or {}
|
||||
else
|
||||
tT[nP].u,tT[nP].ep,tT[nP].e = 0,1,{}
|
||||
end
|
||||
nP = nP + 1
|
||||
end
|
||||
function _G.sched()
|
||||
_G.sched = nil
|
||||
while #tT > 0 do
|
||||
eq[#eq+1]={computer.pullSignal(p)} -- add the latest event to the eq
|
||||
if #eq > 16 then
|
||||
table.remove(eq,1) -- remove the earliest if the eq is full
|
||||
for pid,proc in ipairs(tT) do
|
||||
if proc.ep > 1 then
|
||||
proc.ep = proc.ep - 1 -- decrement pointers for tasks to keep them on the same ones
|
||||
end
|
||||
end
|
||||
end
|
||||
for pid,proc in ipairs(tT) do
|
||||
if coroutine.status(proc.c) == "dead" then
|
||||
tT[pid] = nil
|
||||
else
|
||||
cT=pid
|
||||
sbt[pid].ev = eq[#eq] -- make an ev for MultICE compat
|
||||
coroutine.resume(proc.c)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
_G.event = {}
|
||||
function event.get() -- get the next event in the queue, or nil
|
||||
if eq[tT[cT].ep] then
|
||||
tT[cT].ep = tT[cT].ep + 1
|
||||
if tT[cT].ep > 17 then
|
||||
tT[cT].ep = 17
|
||||
end
|
||||
return eq[tT[cT].ep - 1]
|
||||
end
|
||||
end
|
||||
function event.pull(t) -- return or wait for the next event, optionally with the first param matching t
|
||||
while true do
|
||||
local e = event.get()
|
||||
if e then
|
||||
if t then
|
||||
if e[1] == t then
|
||||
return table.unpack(e)
|
||||
end
|
||||
else
|
||||
return table.unpack(e)
|
||||
end
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
event.push = computer.pushSignal
|
||||
function os.getenv(k)
|
||||
if tT[cT] then
|
||||
return tT[cT].e[k]
|
||||
end
|
||||
end
|
||||
function os.setenv(k,v)
|
||||
if tT[cT] then
|
||||
tT[cT].e[k] = v
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,79 @@
|
|||
_G.term_hack = false
|
||||
function tty(gA,sA,sI,mx,my)
|
||||
spawn("fastty: "..gA:sub(1,8)..","..sA:sub(1,8)..","..sI,function()
|
||||
_G.nlog = ""
|
||||
local sb,lb,slb = {},{},{}
|
||||
local cx, cy = 1, 1
|
||||
local sI = sI or os.getenv("sI")
|
||||
local gpu = component.proxy(gA)
|
||||
gpu.bind(sA)
|
||||
local sx, sy = gpu.maxResolution()
|
||||
sx, sy = mx or sx, my or sy
|
||||
gpu.fill(1,1,sx,sy," ")
|
||||
|
||||
local function wl(s)
|
||||
s=tostring(s) or ""
|
||||
for i = 1,unicode.len(s) do
|
||||
local c = ""
|
||||
c=unicode.sub(s,i,i)
|
||||
if c == "\f" then
|
||||
for i = 1, sy do
|
||||
sb[i] = nil
|
||||
end
|
||||
cx,cy=1,1
|
||||
elseif c == "\n" then
|
||||
cx,cy=1,cy+1
|
||||
elseif c == "\t" then
|
||||
repeat
|
||||
cx=cx+1
|
||||
until cx%8 == 0
|
||||
elseif c == "\127" then
|
||||
cx=cx-1
|
||||
if cx<1 then cx=1 end
|
||||
sb[cy] = sb[cy]:sub(1,cx-1).." "..sb[cy]:sub(cx+2)
|
||||
else
|
||||
sb[cy] = sb[cy] or ""
|
||||
while cx > sb[cy]:len() do
|
||||
sb[cy]=sb[cy] .. " "
|
||||
end
|
||||
sb[cy] = sb[cy]:sub(1,cx-1)..c..sb[cy]:sub(cx)
|
||||
if sb[cy]:len() > sx then
|
||||
sb[cy] = sb[cy]:sub(1,sx)
|
||||
end
|
||||
cx=cx+unicode.charWidth(c)
|
||||
if cx > sx then
|
||||
cx,cy = 1, cy+1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local function rd()
|
||||
while #sb > sy do
|
||||
table.remove(sb,1)
|
||||
cy=cy-1
|
||||
end
|
||||
for i = 1, sy do
|
||||
if sb[i] and sb[i] ~= lb[i] then
|
||||
lb[i] = sb[i]
|
||||
local cs = sb[i]
|
||||
--nlog = nlog .. tostring(i) .. " " .. tostring(cs) .. "\n"
|
||||
while cs:len() < sx do
|
||||
cs=cs.." "
|
||||
end
|
||||
gpu.set(1,i,cs)
|
||||
if term_hack then
|
||||
gpu.set(1,i,cs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
while true do
|
||||
_,si,str = event.pull("display")
|
||||
if si == sI then
|
||||
wl(str)
|
||||
rd()
|
||||
gpu.set(cx,cy,"█")
|
||||
end
|
||||
end
|
||||
end,{sI=sI})
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
net = {}
|
||||
net.id = computer.address():sub(1,8)
|
||||
net.vlan = 1
|
||||
net.np = 4096
|
||||
net.tm = {}
|
||||
function net.send(id,po,msg) -- id, port, message
|
||||
event.push("sendmsg",id,po,msg)
|
||||
end
|
||||
spawn("network daemon",function ()
|
||||
for a,t in component.list("modem") do
|
||||
table.insert(net.tm,component.proxy(a))
|
||||
component.proxy(a).open(net.vlan)
|
||||
end
|
||||
while true do
|
||||
local ev = {event.pull()}
|
||||
if ev[1] == "sendmsg" then
|
||||
local eT = ev
|
||||
for k,v in ipairs(net.tm) do
|
||||
v.broadcast(net.vlan,net.np,eT[2],net.id,eT[3],eT[4])
|
||||
end
|
||||
elseif ev[1] == "modem_message" then
|
||||
if ev[7] == net.id then
|
||||
event.push("net_msg",ev[8],ev[9],ev[10])
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -1,48 +0,0 @@
|
|||
function tty(gA,sA,sI,fg,bg) -- gpuAddress,screenAddress,sessionID,foreground,background
|
||||
local gP,cx,cy,bg,fg = component.proxy(gA),1,1,bg or 0x000000, fg or 0xffffff -- basic setup from here
|
||||
gP.bind(sA)
|
||||
local sx, sy = gP.getResolution()
|
||||
gP.setResolution(sx,sy)
|
||||
gP.setForeground(fg)
|
||||
gP.setBackground(bg)
|
||||
gP.fill(1,1,sx,sy," ")
|
||||
gP.setDepth(gp.maxDepth())
|
||||
local function cv() -- check cursor position
|
||||
if cx > sx then cx,cy=1,cy+1 end
|
||||
if cx < 1 then cx,cy=sx,cy-1 end
|
||||
if cy < 1 then cx,cy=1,1 end
|
||||
if cy > sy then gP.copy(1,2,sx,sy-1,0,-1) gP.fill(1,sy,sx,1," ") cx,cy=1,sy end
|
||||
end
|
||||
local function ic(s)
|
||||
local cc,fg,bg=gP.get(cx,cy)
|
||||
if s then fG,bG = bg,fg else fG,bG = fg,bg end
|
||||
gP.setForeground(bG)
|
||||
gP.setBackground(fG)
|
||||
gP.set(cx,cy,cc)
|
||||
gP.setForeground(fG)
|
||||
gP.setBackground(bG)
|
||||
end
|
||||
local function wl(str) -- write line
|
||||
for c in str:gmatch(".") do
|
||||
if c == "\n" then cx,cy=1,cy+1
|
||||
elseif c == "\r" then cx=1
|
||||
elseif c == "\f" then cx=1 cy=1 gP.fill(1, 1, sx, sy, " ")
|
||||
elseif c == "\t" then cx=(cx+8-((cx+8)%8))+1
|
||||
elseif c == "\127" or c == "\008" then cx=cx-1 gP.set(cx,cy," ")
|
||||
else gP.set(cx,cy,c) cx=cx+1
|
||||
end cv()
|
||||
end
|
||||
end
|
||||
spawn("tty",function() log(pcall(function() -- spawns the listener
|
||||
local csi = os.getenv("sI")
|
||||
log(csi)
|
||||
while true do
|
||||
_,si,str=event.pull("display")
|
||||
if si == csi then
|
||||
wl(str)
|
||||
ic()
|
||||
end
|
||||
end
|
||||
end)) end)
|
||||
end
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
function tty(gA,sA,sI,fg,bg)
|
||||
local gP,cx,cy,bg,fg = component.proxy(gA),1,1,bg or 0x000000, fg or 0xffffff
|
||||
local sI = sI or 1
|
||||
local gP,cx,cy,bg,fg,Sx,Sy = component.proxy(gA),1,1,bg or 0x000000, fg or 0xffffff,1,1
|
||||
gP.bind(sA)
|
||||
local sx, sy = gP.getResolution()
|
||||
gP.setResolution(sx,sy)
|
||||
|
@ -23,11 +24,13 @@ function tty(gA,sA,sI,fg,bg)
|
|||
gP.setBackground(bG)
|
||||
end
|
||||
local function wl(str)
|
||||
if gP.getScreen() ~= sA then
|
||||
gP.bind(sA)
|
||||
end
|
||||
local cm = 0
|
||||
for c in str:gmatch(".") do
|
||||
if cm == 1 then
|
||||
cm = 0
|
||||
ic(true)
|
||||
if c == "A" then cy=cy-1
|
||||
elseif c == "B" then cy=cy+1
|
||||
elseif c == "C" then cx=cx+1
|
||||
|
@ -36,6 +39,19 @@ function tty(gA,sA,sI,fg,bg)
|
|||
elseif c == "Y" then cm=2
|
||||
elseif c == "b" then cm=4
|
||||
elseif c == "c" then cm=5
|
||||
elseif c == "j" then Sx,Sy = cx,cy
|
||||
elseif c == "k" then cx,cy = Sx,Sy
|
||||
elseif c == "l" then
|
||||
gP.fill(1,cy,sx,1," ")
|
||||
elseif c == "L" then
|
||||
gP.copy(1,2,sx,cy-1,0,-1)
|
||||
gP.fill(1,cy-1,sx,1," ")
|
||||
elseif c == "p" then
|
||||
gP.setForeground(bG)
|
||||
gP.setBackground(fG)
|
||||
elseif c == "q" then
|
||||
gP.setForeground(fG)
|
||||
gP.setBackground(bG)
|
||||
end
|
||||
elseif cm == 2 then
|
||||
cx,cm=string.byte(c)-31,3
|
||||
|
@ -60,16 +76,17 @@ function tty(gA,sA,sI,fg,bg)
|
|||
end
|
||||
end
|
||||
spawn("tty["..tostring(sI).."]: "..gA:sub(1,8)..","..sA:sub(1,8),function() log(pcall(function()
|
||||
while true do
|
||||
local csi = os.getenv("sI")
|
||||
log(csi)
|
||||
if sI then os.setenv("sI",sI) end
|
||||
while true do
|
||||
_,si,str=event.pull("display")
|
||||
if si == csi then
|
||||
wl(str)
|
||||
ic()
|
||||
local csi = os.getenv("sI")
|
||||
log(csi)
|
||||
while true do
|
||||
_,si,str=event.pull("display")
|
||||
if si == csi then
|
||||
wl(str)
|
||||
ic()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)) end)
|
||||
end
|
||||
|
|
|
@ -1,6 +1,60 @@
|
|||
do
|
||||
_G.fs = {}
|
||||
local dfsattr = {read = "*", write = "*"}
|
||||
local fsattr = {}
|
||||
local fT,hT = {},{["_c"]=0}
|
||||
local function parseacl(acl)
|
||||
acl = acl or ""
|
||||
local tacl = {}
|
||||
if acl == "*" then
|
||||
setmetatable(tacl,{__index = function() return true end})
|
||||
else
|
||||
for n in acl:gmatch("[^,]+") do
|
||||
tacl[n] = true
|
||||
log(n)
|
||||
end
|
||||
end
|
||||
return tacl
|
||||
end
|
||||
local function canread(fn)
|
||||
fn = fs.canonical(fn)
|
||||
if os.getuid() == "nobody" then return false end
|
||||
if os.getuid() ~= "superuser" and fsattr[fn] then
|
||||
if not parseacl(fsattr[fn].read or "")[os.getuid()] then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
local function canwrite(fn)
|
||||
fn = fs.canonical(fn)
|
||||
if os.getuid() == "nobody" then return false end
|
||||
if os.getuid() ~= "superuser" and fsattr[fn] then
|
||||
if not parseacl(fsattr[fn].write)[os.getuid()] then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
fs.parseacl = parseacl
|
||||
fs.canread = canread
|
||||
fs.canwrite = canwrite
|
||||
local function getattr(fn,k)
|
||||
fn = fs.canonical(fn)
|
||||
if not canread(fn) then return false end
|
||||
if fsattr[fn] then
|
||||
return fsattr[fn][k]
|
||||
else
|
||||
return dfsattr[k]
|
||||
end
|
||||
end
|
||||
local function setattr(fn,k,v)
|
||||
fn = fs.canonical(fn)
|
||||
if not canwrite(fn) then return false end
|
||||
if k:find("\t") or v:find("\t") then return false end
|
||||
log(parseacl(getattr(fn,"write"))[os.getuid()])
|
||||
if not fsattr[fn] then
|
||||
fsattr[fn] = {}
|
||||
setmetatable(fsattr[fn],{__index=dfsattr})
|
||||
end
|
||||
fsattr[fn][k] = tostring(v)
|
||||
end
|
||||
function fs.mount(mp,pr)
|
||||
fT[mp] = pr
|
||||
end
|
||||
|
@ -36,10 +90,19 @@ do
|
|||
end
|
||||
return pt, pt[1], spt
|
||||
end
|
||||
function fs.canonical(p)
|
||||
local _,d,rp = fs.resolve(p)
|
||||
return fs.simplify("/"..d.."/"..rp)
|
||||
end
|
||||
function fs.exec(fc,m,...)
|
||||
return fT[fc][m](...)
|
||||
end
|
||||
function fs.open(p,m)
|
||||
if m:sub(1,1) == "r" then
|
||||
if not canread(p) then return false end
|
||||
elseif m:sub(1,1) == "w" or m:sub(1,1) == "a" then
|
||||
if not canwrite(p) then return false end
|
||||
end
|
||||
local _,d,p = fs.resolve(p)
|
||||
local d = fT[d]
|
||||
if d then
|
||||
|
@ -80,6 +143,7 @@ do
|
|||
return false
|
||||
end
|
||||
function fs.list(s)
|
||||
if not canread(s) then return false end
|
||||
s=s or ""
|
||||
local _,d,p = fs.resolve(s)
|
||||
if not d then
|
||||
|
@ -96,6 +160,7 @@ do
|
|||
return fT[d].makeDirectory(p or "/")
|
||||
end
|
||||
function fs.rm(s)
|
||||
if not canwrite(s) then return false end
|
||||
local _,d,p = fs.resolve(s)
|
||||
return fT[d].remove(p)
|
||||
end
|
||||
|
@ -109,6 +174,55 @@ do
|
|||
local _,d,p = fs.resolve(s)
|
||||
return fT[d].isDirectory(p)
|
||||
end
|
||||
local function flushattr()
|
||||
local f = fs.open("/boot/sys/fsattr.dat","wb")
|
||||
if f then
|
||||
for k,v in pairs(fsattr) do
|
||||
fs.write(f,k.."\t")
|
||||
for l,m in pairs(v) do
|
||||
fs.write(f,"\t"..l.."="..m)
|
||||
end
|
||||
fs.write(f,"\n")
|
||||
end
|
||||
fs.close(f)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function readattr()
|
||||
local f=fs.open("/boot/sys/fsattr.dat","rb")
|
||||
if not f then return false end
|
||||
local C=fs.readall(f)
|
||||
fs.close(f)
|
||||
for line in C:gmatch("[^\n]+") do
|
||||
local ifn = true
|
||||
local fn = ""
|
||||
for kv in line:gmatch("[^\t]+") do
|
||||
if ifn then
|
||||
fn = kv
|
||||
ifn = false
|
||||
else
|
||||
local k,v = kv:match("(.+)%=(.+)")
|
||||
setattr(fn,k,v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
spawn("read fs attributes",readattr)
|
||||
function fs.getattr(fn,k)
|
||||
if fs.exists(fn) then
|
||||
return getattr(fn,k)
|
||||
end
|
||||
return false
|
||||
end
|
||||
function fs.setattr(fn,k,v)
|
||||
if fs.exists(fn) then
|
||||
local res={setattr(fn,k,v)}
|
||||
flushattr()
|
||||
return table.unpack(res)
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
function fs.cd(p)
|
||||
if p:sub(1,1) ~= "/" then
|
||||
|
@ -122,13 +236,46 @@ function fs.cd(p)
|
|||
end
|
||||
end
|
||||
function fs.cp(s,d)
|
||||
if not fs.canread(s) then return false end
|
||||
if not fs.canwrite(d) then return false end
|
||||
local df = fs.open(d,"wb")
|
||||
local sf = fs.open(s,"rb")
|
||||
fs.write(df,fs.readall(sf))
|
||||
fs.close(df)
|
||||
fs.close(sf)
|
||||
if df and sf then
|
||||
local c = ""
|
||||
while true do
|
||||
c=fs.read(sf,2048)
|
||||
if not c then break end
|
||||
fs.write(df,c)
|
||||
end
|
||||
fs.close(df)
|
||||
fs.close(sf)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
function fs.mv(s,d)
|
||||
fs.cp(s,d)
|
||||
fs.rm(s)
|
||||
end
|
||||
function loadfile(fn)
|
||||
local f=io.open(fn,"rb")
|
||||
if not f then return false, "cannot read file" end
|
||||
local S=f:read("*a")
|
||||
f:close()
|
||||
return load(S,"=("..fn..")","bt",os.genenv())
|
||||
end
|
||||
function run(fn,...)
|
||||
local lf = loadfile(fn)
|
||||
if not lf then return false, "cannot load file" end
|
||||
local r = {pcall(lf,...)}
|
||||
if r[1] == true then
|
||||
table.remove(r,1)
|
||||
end
|
||||
print(table.unpack(r))
|
||||
end
|
||||
function srun(fn,...)
|
||||
local lf = loadfile(fn)
|
||||
if not lf then return false, "cannot load file" end
|
||||
spawn(fn,log(pcall(lf,...)))
|
||||
end
|
||||
os.execute = run
|
||||
|
|
|
@ -8,19 +8,34 @@ function shutil.genenv()
|
|||
end
|
||||
return et
|
||||
end
|
||||
function loadfile(fn)
|
||||
local f=io.open(fn,"rb")
|
||||
local S=f:read("*a")
|
||||
f:close()
|
||||
return load(S,"=("..fn..")","bt",os.genenv())
|
||||
end
|
||||
function run(fn,...)
|
||||
local r = {pcall(loadfile(fn),...)}
|
||||
if r[1] == true then
|
||||
table.remove(r,1)
|
||||
function shutil.exec(line)
|
||||
local words = {}
|
||||
for w in line:gmatch("%S+") do table.insert(words,w) end
|
||||
if _ENV[words[1]] then
|
||||
local prg = table.remove(words,1)
|
||||
local r={pcall(_ENV[prg],table.unpack(words))}
|
||||
if r[1] == true then
|
||||
table.remove(r,1)
|
||||
end
|
||||
return table.unpack(r)
|
||||
end
|
||||
print(table.unpack(r))
|
||||
end
|
||||
function srun(fn,...)
|
||||
spawn(fn,print(pcall(loadfile(fn),...)))
|
||||
local pth = os.getenv("PATH") or "."
|
||||
for d in pth:gmatch("[^:]+") do
|
||||
local prg = words[1]
|
||||
_,lex = pcall(fs.exists,d.."/"..prg..".lua")
|
||||
_,nex = pcall(fs.exists,d.."/"..prg)
|
||||
if lex or nex then
|
||||
table.remove(words,1)
|
||||
end
|
||||
if lex then
|
||||
return pcall(loadfile(d.."/"..prg..".lua"),table.unpack(words))
|
||||
elseif nex then
|
||||
return pcall(loadfile(d.."/"..prg),table.unpack(words))
|
||||
end
|
||||
end
|
||||
if line:sub(1,1) == "=" then
|
||||
line="return "..line:sub(2)
|
||||
end
|
||||
local r={pcall(load(line,"shell","bt",_ENV))}
|
||||
return table.unpack(r)
|
||||
end
|
||||
|
|
|
@ -1,12 +1,31 @@
|
|||
_G.DEFAC = 1
|
||||
do
|
||||
if component.list("gpu")() and component.list("screen")() and component.list("keyboard")() and tty and kbd then
|
||||
tty(component.list("gpu")(),component.list("screen")())
|
||||
log(pcall(function()
|
||||
local ka = component.list("keyboard")()
|
||||
kbd(ka)
|
||||
end))
|
||||
luash()
|
||||
local ts = {}
|
||||
if fs.exists("/boot/sys/session.dat") then
|
||||
local f = io.open("/boot/sys/session.dat","rb")
|
||||
if f then
|
||||
S = f:read("*a")
|
||||
f:close()
|
||||
log(S)
|
||||
for line in S:gmatch("[^\n]+") do
|
||||
log(line)
|
||||
local ga, sa, ka = line:match("(.+)\t(.+)\t(.+)")
|
||||
ts[#ts+1] = {os.gensalt(16),ga,sa,ka}
|
||||
log()
|
||||
end
|
||||
end
|
||||
else
|
||||
ts[1] = {os.gensalt(16),component.list("gpu")(),component.list("screen")(),component.list("keyboard")()} -- session name, GPU address, screen address, keyboard address
|
||||
end
|
||||
for k,v in ipairs(ts) do
|
||||
log(v[1],v[2],v[3],v[4])
|
||||
tty(v[2],v[3],v[1])
|
||||
kbd(v[4],v[1])
|
||||
loginmanager(v[1])
|
||||
end
|
||||
elseif nshd then
|
||||
nshd(23)
|
||||
end
|
||||
end
|
||||
computer.beep()
|
||||
|
|
|
@ -1 +1 @@
|
|||
run("/boot/sys/init.lua")
|
||||
spawn("autorun",function() log(run("/boot/sys/init.lua")) end)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
do
|
||||
local C=0
|
||||
for c in component.list("filesystem") do
|
||||
if c == computer.tmpAddress() then
|
||||
fs.mount("tmp",component.proxy(c))
|
||||
|
@ -13,31 +12,11 @@ do
|
|||
fs.mount(component.invoke(c,"getLabel"),component.proxy(c))
|
||||
log(c:sub(1,8).." mounted as "..component.invoke(c,"getLabel"))
|
||||
end
|
||||
fs.mount("fs"..string.format("%02d",C),component.proxy(c))
|
||||
log(c:sub(1,8).." mounted as fs"..string.format("%02d",C))
|
||||
C=C+1
|
||||
fs.mount(c:sub(1,3),component.proxy(c))
|
||||
log(c:sub(1,8).." mounted as "..c:sub(1,3))
|
||||
end
|
||||
if component.type(computer.getBootAddress()) ~= "filesystem" then
|
||||
fs.mount("boot",component.proxy(computer.tmpAddress()))
|
||||
log(computer.tmpAddress():sub(1,8).." mounted as boot")
|
||||
end
|
||||
if component.type(computer.getBootAddress()) == "tape_drive" then
|
||||
if tape then
|
||||
tape.rewind()
|
||||
local pt = tape.records()
|
||||
for k,v in ipairs(pt) do
|
||||
if v[1] == "D" then
|
||||
print(tostring(k).."\t"..v[1].."\t/boot/"..tape.rrecord(k))
|
||||
fs.mkdir("/boot/"..tape.rrecord(k))
|
||||
elseif v[1] == "f" then
|
||||
local fn,fc = tape.parsefile(tape.rrecord(k))
|
||||
print(tostring(k).."\t"..v[1].."\t/boot/"..fn)
|
||||
local f=io.open("/boot/"..fn,"wb")
|
||||
f:write(fc)
|
||||
f:close()
|
||||
end
|
||||
computer.beep()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
tape = {}
|
||||
tape.types = {}
|
||||
tape.types["!"] = "executable"
|
||||
tape.types["t"] = "tar"
|
||||
tape.types["d"] = "data"
|
||||
tape.types["D"] = "directory"
|
||||
tape.types["f"] = "file"
|
||||
function tape.records(addr) -- { { type, start, end, length } }
|
||||
local tp,ct = {},0
|
||||
addr = addr or component.list("tape_drive")()
|
||||
local t = component.proxy(addr)
|
||||
local function read(n)
|
||||
n=n or 1
|
||||
ct=ct+n
|
||||
return t.read(n)
|
||||
end
|
||||
local function seek(n)
|
||||
n=n or 1
|
||||
ct=ct+n
|
||||
return t.seek(n)
|
||||
end
|
||||
while true do
|
||||
local ty = read()
|
||||
if not tape.types[ty] then break end
|
||||
tp[#tp+1] = {ty,ct+8} -- type, start,
|
||||
local ln = tonumber(read(8)) or 0
|
||||
tp[#tp][#tp[#tp]+1] = ct+ln -- end
|
||||
tp[#tp][#tp[#tp]+1] = ln -- length
|
||||
seek(ln)
|
||||
end
|
||||
return tp
|
||||
end
|
||||
function tape.precords(addr)
|
||||
tape.rewind(addr)
|
||||
local pt = tape.records(addr)
|
||||
for k,v in ipairs(pt) do
|
||||
print(k.."\t"..v[1].."\t"..v[2].."\t"..v[3].."\t"..v[4])
|
||||
end
|
||||
end
|
||||
function tape.drecord(n,addr)
|
||||
addr = addr or component.list("tape_drive")()
|
||||
tape.rewind(addr)
|
||||
local pt = tape.records(addr)
|
||||
tape.rewind(addr)
|
||||
local t = component.proxy(addr)
|
||||
print(pt[n][2]-9)
|
||||
t.seek(pt[n][2]-9)
|
||||
t.write("\0")
|
||||
tape.rewind()
|
||||
end
|
||||
function tape.wrecord(c,ty,s,addr)
|
||||
ty = ty or "!"
|
||||
addr = addr or component.list("tape_drive")()
|
||||
local t = component.proxy(addr)
|
||||
if s then
|
||||
t.seek(-math.huge)
|
||||
t.seek(s)
|
||||
end
|
||||
local fh=ty:sub(1,1)..string.format("%8d",c:len())
|
||||
print("Header: "..fh)
|
||||
t.write(fh)
|
||||
t.write(c)
|
||||
end
|
||||
function tape.rrecord(pn,addr)
|
||||
addr = addr or component.list("tape_drive")()
|
||||
pn = pn or 1
|
||||
local t = component.proxy(addr)
|
||||
local pP = t.seek(-math.huge)
|
||||
local pt = tape.records(addr)
|
||||
t.seek(-math.huge)
|
||||
local pstart,plen = pt[pn][2],pt[pn][4]
|
||||
t.seek(pstart)
|
||||
C=t.read(plen)
|
||||
t.seek(-math.huge)
|
||||
t.seek(pP)
|
||||
return C
|
||||
end
|
||||
function tape.nrecord(addr)
|
||||
addr = addr or component.list("tape_drive")()
|
||||
local t = component.proxy(addr)
|
||||
local pP = t.seek(-math.huge)
|
||||
local pt = tape.records(addr)
|
||||
t.seek(-math.huge)
|
||||
t.seek(pP)
|
||||
return pt[#pt][3]
|
||||
end
|
||||
function tape.rewind(addr)
|
||||
addr = addr or component.list("tape_drive")()
|
||||
local t = component.proxy(addr)
|
||||
t.seek(-math.huge)
|
||||
end
|
||||
function tape.parsefile(str)
|
||||
return str:sub(1,64):gsub("\0",""), str:sub(65)
|
||||
end
|
||||
function tape.unparsefile(fname,str)
|
||||
local nul = "\0"
|
||||
nul=nul:rep(64-#fname)
|
||||
fname=nul..fname
|
||||
return fname..str
|
||||
end
|
||||
function tape.mkdir(str,addr)
|
||||
tape.wrecord(str,"D",tape.nrecord(),addr)
|
||||
end
|
||||
function tape.wfile(fname,fcont,addr)
|
||||
tape.wrecord(str,"f",tape.nrecord(),addr)
|
||||
end
|
||||
function tape.wtree(addr)
|
||||
local ft = {""}
|
||||
local rft = {}
|
||||
addr = addr or component.list("tape_drive")()
|
||||
local t = component.proxy(addr)
|
||||
for _,d in ipairs(ft) do
|
||||
local ls = fs.list(d)
|
||||
for k,v in ipairs(ls) do
|
||||
v=d..v
|
||||
if fs.isdir(v) then
|
||||
ft[#ft+1] = v
|
||||
else
|
||||
rft[#rft+1] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
tape.rewind(addr)
|
||||
t.seek(tape.nrecord(addr))
|
||||
for k,v in ipairs(ft) do
|
||||
if v ~= "" then
|
||||
print(v)
|
||||
local fh="D"..string.format("%8d",v:len())
|
||||
t.write(fh)
|
||||
t.write(v)
|
||||
end
|
||||
end
|
||||
for k,v in ipairs(rft) do
|
||||
print(v)
|
||||
local f=io.open(v,"rb")
|
||||
local fc = f:read("*a")
|
||||
local fc = tape.unparsefile(v,fc)
|
||||
f:close()
|
||||
local fh="f"..string.format("%8d",fc:len())
|
||||
t.write(fh)
|
||||
t.write(fc)
|
||||
end
|
||||
end
|
||||
function tape.rtree(pref,addr)
|
||||
tape.rewind()
|
||||
local pt = tape.records()
|
||||
for k,v in ipairs(pt) do
|
||||
if v[1] == "D" then
|
||||
print(tostring(k).."\t"..v[1].."\t"..pref..tape.rrecord(k))
|
||||
fs.mkdir(pref..tape.rrecord(k))
|
||||
elseif v[1] == "f" then
|
||||
local fn,fc = tape.parsefile(tape.rrecord(k))
|
||||
print(tostring(k).."\t"..v[1].."\t"..pref..fn)
|
||||
local f=io.open(pref..fn,"wb")
|
||||
f:write(fc)
|
||||
f:close()
|
||||
end
|
||||
computer.beep()
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
|
@ -0,0 +1,172 @@
|
|||
local ci = component.invoke
|
||||
function bi(A, method, ...)
|
||||
local result = table.pack(pcall(ci, A, method, ...))
|
||||
if not result[1] then
|
||||
return nil, result[2]
|
||||
else
|
||||
return table.unpack(result, 2, result.n)
|
||||
end
|
||||
end
|
||||
|
||||
-- backwards compatibility, may remove later
|
||||
local E = component.list("eeprom")()
|
||||
computer.getBootAddress = function()
|
||||
return bi(E, "getData")
|
||||
end
|
||||
computer.setBootAddress = function(A)
|
||||
return bi(E, "setData", A)
|
||||
end
|
||||
|
||||
local tryLoadFrom = 0
|
||||
|
||||
do
|
||||
local S = component.list("S")()
|
||||
local G = component.list("G")()
|
||||
if G and S then
|
||||
bi(G, "bind", S)
|
||||
end
|
||||
end
|
||||
do
|
||||
local gA,sA = component.list("gpu")(),component.list("screen")()
|
||||
if gA and sA then
|
||||
local gP,cy = component.proxy(gA),1
|
||||
gP.bind(sA)
|
||||
local sx, sy = gP.getResolution()
|
||||
local function wl(s)
|
||||
gP.set(1,cy,s)
|
||||
cy=cy+1
|
||||
end
|
||||
function tryLoadFrom(A)
|
||||
if component.type(A) == "filesystem" then
|
||||
local H, R = bi(A, "open", "/init.lua")
|
||||
if not H then
|
||||
return nil, R
|
||||
end
|
||||
local buffer = ""
|
||||
repeat
|
||||
local data, R = bi(A, "read", H, math.huge)
|
||||
if not data and R then
|
||||
return nil, R
|
||||
end
|
||||
buffer = buffer .. (data or "")
|
||||
until not data
|
||||
bi(A, "close", H)
|
||||
return load(buffer, "=init")
|
||||
elseif component.type(A) == "tape_drive" then
|
||||
bi(A,"seek",-math.huge)
|
||||
local boottype = bi(A,"read",1)
|
||||
if boottype == "!" then
|
||||
local rl = tonumber(bi(A,"read",8))
|
||||
local buffer = bi(A,"read",rl)
|
||||
return load(buffer, "=init")
|
||||
end
|
||||
elseif component.type(A) == "modem" then
|
||||
bi(A,"open",9671)
|
||||
bi(A,"broadcast",9671,computer.A())
|
||||
s=""
|
||||
local bt = computer.uptime()
|
||||
while bt+10 > computer.uptime() do
|
||||
computer.beep()
|
||||
local ev={computer.pullSignal(0.5)}
|
||||
if ev[1] == "modem_message" and ev[4] == 9671 then
|
||||
bt=computer.uptime()
|
||||
if ev[6] == "." then break end
|
||||
s=s..ev[6]
|
||||
end
|
||||
end
|
||||
if s ~= "" then
|
||||
return load(s,"=init")
|
||||
end
|
||||
elseif component.type(A) == "internet" then
|
||||
local I = component.proxy(A)
|
||||
local S = ""
|
||||
wl("Paste an address to boot from - or wait for the default.")
|
||||
local T = 5
|
||||
local U = "https://lain.shadowkat.net/~izaya/ocdoc/PsychOS-build/fsdev/PsychOS-fsdev-latest/severything.lua"
|
||||
while computer.uptime() < T do
|
||||
t,_,c,C = computer.pullSignal(0.5)
|
||||
if t == "clipboard" then
|
||||
U = c
|
||||
end
|
||||
end
|
||||
local R=I.request(U)
|
||||
if not R then return false end
|
||||
repeat
|
||||
computer.pullSignal(0.5)
|
||||
until R.finishConnect()
|
||||
local code, msg = R.response()
|
||||
if code ~= 200 then
|
||||
return false, code, msg
|
||||
end
|
||||
repeat
|
||||
computer.pullSignal(0.5)
|
||||
ns = R.read(2048)
|
||||
S=S..(ns or "")
|
||||
computer.beep()
|
||||
until not ns
|
||||
return load(S,"=init")
|
||||
end
|
||||
end
|
||||
|
||||
local bd = {}
|
||||
for k,v in ipairs({"filesystem","tape_drive","modem","internet"}) do
|
||||
for A in component.list(v) do
|
||||
bd[#bd+1] = A
|
||||
end
|
||||
end
|
||||
|
||||
local cba = computer.getBootAddress()
|
||||
local S = (" "):rep(3)
|
||||
local function rdraw()
|
||||
gP.fill(1,1,sx,sy," ")
|
||||
cy=1
|
||||
wl("SKS Enhanced BIOS v2")
|
||||
wl("Memory: "..tostring(computer.totalMemory()/1024).."K")
|
||||
wl(" ")
|
||||
for k,v in ipairs(bd) do
|
||||
if v == cba then S = " ".."*".." " else S = (" "):rep(3) end
|
||||
local e,l = pcall(component.invoke,v,"getLabel")
|
||||
if not e then l = "" end
|
||||
wl(S..tostring(k).." "..v.." "..component.type(v).." "..(l or ""))
|
||||
end
|
||||
end
|
||||
rdraw()
|
||||
local T = 5
|
||||
local bhc = false
|
||||
while computer.uptime() < T do
|
||||
t,_,c,C = computer.pullSignal(0.5)
|
||||
if t == "key_down" and c > 48 and c < 58 then
|
||||
cba = bd[c-48]
|
||||
bhc = true
|
||||
rdraw()
|
||||
elseif t == "key_down" and c == 32 then
|
||||
T = T + 10
|
||||
elseif t == "key_down" and c == 13 and C == 28 then
|
||||
T = 0
|
||||
end
|
||||
end
|
||||
if bhc then
|
||||
computer.setBootAddress(cba)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local init, R
|
||||
if computer.getBootAddress() then
|
||||
init, R = tryLoadFrom(computer.getBootAddress())
|
||||
end
|
||||
if not init then
|
||||
computer.setBootAddress()
|
||||
for k,A in ipairs(bd) do
|
||||
init, R = tryLoadFrom(A)
|
||||
if init then
|
||||
computer.setBootAddress(A)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not init then
|
||||
error("no bootable medium found" .. (R and (": " .. tostring(R)) or ""), 0)
|
||||
end
|
||||
computer.beep(1000, 0.2)
|
||||
init()
|
Loading…
Reference in New Issue