Compare commits

...

104 Commits

Author SHA1 Message Date
Izaya ac27dc473c cleaned up modules and exec 2017-10-14 08:11:01 +11:00
Izaya 249b4c4614 more formatting fixes 2017-10-14 07:54:02 +11:00
Izaya 57a37f8a76 removed some stuff that shouldn't be in the kernel any more 2017-10-14 07:20:49 +11:00
Izaya 829f423dc2 formatting fixes 2017-10-14 07:15:13 +11:00
Izaya aeffadfff8 updated the userguide to be nicer to read 2017-10-14 07:13:52 +11:00
Izaya 0eb85d39e5 line wrapping works now 2017-10-13 04:22:36 +11:00
Izaya c347f6daa4 term_hack is only needed in ocvm. also now fastty clears the screen 2017-10-13 04:15:07 +11:00
Izaya d8d74fc627 fastty now has proper unicode character support 2017-10-12 16:13:51 +11:00
Izaya d37cc4a155 I 'fixed' the stupid fastty bug, get a faster display by setting _G.term_hack to false 2017-10-12 10:39:19 +11:00
Izaya dcf5cf7c35 added the start of a user guide 2017-10-11 18:42:38 +11:00
Izaya ecb0ae6b46 some work on a new tty driver, fastty, still pretty buggy but it works well enough for now 2017-10-11 14:20:50 +11:00
Izaya 8192e62ebd added some key combos to the install guide 2017-10-09 04:58:32 +11:00
Izaya 38f6982e39 wget can now be cancelled using ctrl-alt-c 2017-10-09 04:29:47 +11:00
Izaya e7f13d8767 added a note about using http instead of https 2017-10-09 03:32:23 +11:00
Izaya cdc655179a note about installing to /tmp 2017-10-08 14:51:16 +11:00
Izaya 5ef48aeb64 more permission checks 2017-10-08 14:50:03 +11:00
Izaya 0341a38a5b skipped a step 2017-10-08 14:40:05 +11:00
Izaya e27b9d08ee this is why I don't write documentation 2017-10-08 13:34:27 +11:00
Izaya 6ef7b422a1 I suck at formatting 2017-10-08 13:32:43 +11:00
Izaya 57a23dca35 more formatting 2017-10-08 13:31:46 +11:00
Izaya 699a88bc42 fixed some formatting 2017-10-08 13:29:55 +11:00
Izaya 72159fa124 added an installation guide 2017-10-08 13:28:12 +11:00
Izaya 9f3d5ab19a made minimal default to lush again, because lazy 2017-10-08 13:28:01 +11:00
Izaya 10ebeaefa9 updated documentation on building and cleaned up the configs 2017-10-08 12:09:13 +11:00
Izaya 325e540905 removed header.lua which breaks stuff 2017-10-08 08:25:33 +11:00
Izaya 275c50c10d wrote lmk, an more general lua build system 2017-10-08 08:22:35 +11:00
Izaya 83e26739a5 alias os.execute to run() 2017-10-08 08:10:31 +11:00
Izaya d242c38fcb fixed a link 2017-10-08 07:04:25 +11:00
Izaya 3e15ffa6ed updated the API docs and added some links 2017-10-08 07:02:47 +11:00
Izaya 110c3e5886 made a way better login system, you can now exit the shell after logging in and you don't need to reboot the machine 2017-10-08 01:35:51 +11:00
Izaya c5307a7433 lush no longer forks or calls login, has a configurable prompt 2017-10-08 01:35:18 +11:00
Izaya d736491628 added msh, the most minimal shell I could implement decently (just a lua prompt), added it to the minimal config, aliased lush to shell in the other versions 2017-10-08 01:30:37 +11:00
Izaya 83a84ea117 made passwordless login work 2017-10-08 00:30:26 +11:00
Izaya 0e3d368896 changed the user system to allow more flexible configuration 2017-10-08 00:24:42 +11:00
Izaya bbead5d252 moved the execute part of lush into shutil 2017-10-08 00:24:01 +11:00
Izaya 3a3e83691a made lush prefer functions/builtins rather than files where possible 2017-10-07 23:34:18 +11:00
Izaya 0bb3921781 wrote a new version of luash, lush, which is just nicer to use. 2017-10-07 23:33:00 +11:00
Izaya b9916c2b13 added a more flexible screen setup system and stuff 2017-10-07 07:16:22 +11:00
Izaya 0682c50879 Rebasing and stuff 2017-10-07 05:55:35 +00:00
Izaya bbe9d4ac51 added a bunch of escape codes to vt52.lua. 2017-10-07 05:54:51 +00:00
Izaya d58605431e possible fix for multi screen single GPU stuff 2017-10-07 05:54:51 +00:00
Izaya d320de1866 strip.lua no longer removes newlines after comments 2017-10-07 05:54:51 +00:00
Izaya af787e31e7 made luash set the session ID correctly 2017-10-07 05:54:51 +00:00
Izaya ada544d266 os.getuid() no longer fails outside of a process 2017-10-07 05:54:51 +00:00
Izaya 67363dcf92 made vt52 support actually setting the session ID 2017-10-07 05:54:51 +00:00
Izaya 76837876d6 made the VT52 driver theoretically capable of supporting multiple displays with one GPU. theoretically. 2017-10-07 05:54:51 +00:00
Izaya e9227ce08a sebios2 can load from internet cards now 2017-10-07 05:54:51 +00:00
Izaya e1f8f6697e cp may work properly on large files now, previous method was a horrid hack 2017-10-07 05:54:51 +00:00
Izaya a6e6bb5f6b made the automount feature a bit less obnoxious (fs00 -> uuid:sub(1,3) 2017-10-07 05:54:51 +00:00
Izaya 92a8066890 made forked programs output their end result to the log 2017-10-07 05:54:51 +00:00
Izaya 690101d41c made autorun not crash the system. kinda important 2017-10-07 05:54:51 +00:00
Izaya c9f64c00c7 added autorun to all the configs, added aliases for shutil to the minimal kernel 2017-10-07 05:54:51 +00:00
Izaya d63163df70 added remove and dir functionality to pkg 2017-10-07 05:54:51 +00:00
Izaya 31309f3d2d moved the run-related functions into the fs library 2017-10-07 05:54:51 +00:00
Izaya 9def569a2a made nbsrv log rather than print everything 2017-10-07 05:54:51 +00:00
Izaya 776dca5f27 added pkg to the everything kernel 2017-10-07 05:54:51 +00:00
Izaya 334f3a4d50 fixed a bunch of stuff with all the update/package related programs, added pkg, etc. 2017-10-07 05:54:51 +00:00
Izaya faac6621a5 made fs.cp fail if either handle fails to open. ??? 2017-10-07 05:54:51 +00:00
Izaya 599f685b8c wrote an updater script 2017-10-07 05:54:51 +00:00
Izaya cc7df2a95d added less severe failure conditions to shutil, luash should crash less now. 2017-10-07 05:54:51 +00:00
Izaya 1ffec30452 added some programs to manage permissions from the shell 2017-10-07 05:54:51 +00:00
Izaya ae083f57d9 the nobody UID is no longer allowed to read or write files 2017-10-07 05:54:51 +00:00
Izaya 4e3b65ad38 canwrite(p) actually works now 2017-10-07 05:54:51 +00:00
Izaya dcb37236af convinced the io.open stuff to work properly 2017-10-07 05:54:51 +00:00
Izaya cab958f677 moved checks to more generic canread() and canwrite() functions 2017-10-07 05:54:51 +00:00
Izaya ed7032c274 added the get/setattr functions to the API docs 2017-10-07 05:54:51 +00:00
Izaya d6b9b1db3a exposed parseacl as part of _G 2017-10-07 05:54:51 +00:00
Izaya 83ed6019cd made setattr() convert values to strings 2017-10-07 05:54:51 +00:00
Izaya 4b89084432 can only r/w attributes if you have r/w permissions in the attributes 2017-10-07 05:54:51 +00:00
Izaya 8458bf5fc7 made fs attribute loading spam the log less. 2017-10-07 05:54:51 +00:00
Izaya 10f7a53cdd added some basic fs attribute support, stored in memory. 2017-10-07 05:54:51 +00:00
Izaya bd6ff99818 added a bunch of escape codes to vt52.lua. 2017-10-07 05:14:30 +00:00
Izaya cd30afb56a possible fix for multi screen single GPU stuff 2017-10-07 06:10:57 +11:00
Izaya bec129c2fc strip.lua no longer removes newlines after comments 2017-09-26 13:59:08 +10:00
Izaya 124de18ed2 made luash set the session ID correctly 2017-09-26 13:57:00 +10:00
Izaya 8778b140a1 os.getuid() no longer fails outside of a process 2017-09-26 13:56:44 +10:00
Izaya 92eaeb4c46 made vt52 support actually setting the session ID 2017-09-26 13:56:15 +10:00
Izaya 337e9d7c9f made the VT52 driver theoretically capable of supporting multiple displays with one GPU. theoretically. 2017-09-24 02:19:51 +10:00
Izaya e2b315e5b3 sebios2 can load from internet cards now 2017-09-23 23:25:04 +10:00
Izaya 3774580806 cp may work properly on large files now, previous method was a horrid hack 2017-09-23 19:16:34 +10:00
Izaya b04d700f94 made the automount feature a bit less obnoxious (fs00 -> uuid:sub(1,3) 2017-09-23 19:13:25 +10:00
Izaya d60c10baa0 made forked programs output their end result to the log 2017-09-23 19:08:10 +10:00
Izaya 99b4bc3b71 made autorun not crash the system. kinda important 2017-09-23 18:52:09 +10:00
Izaya 0f08d6caa0 added autorun to all the configs, added aliases for shutil to the minimal kernel 2017-09-23 18:42:13 +10:00
Izaya 55eb012e16 added remove and dir functionality to pkg 2017-09-23 18:22:15 +10:00
Izaya 237b1c5e09 moved the run-related functions into the fs library 2017-09-23 18:19:01 +10:00
Izaya 0918704357 made nbsrv log rather than print everything 2017-09-23 14:26:37 +10:00
Izaya 519b63c627 added pkg to the everything kernel 2017-09-23 14:21:37 +10:00
Izaya ed8aca42e0 fixed a bunch of stuff with all the update/package related programs, added pkg, etc. 2017-09-23 11:24:37 +10:00
Izaya b271341b2b made fs.cp fail if either handle fails to open. ??? 2017-09-23 11:22:33 +10:00
Izaya a7a463c38d wrote an updater script 2017-09-23 09:52:31 +10:00
Izaya 3cf9a5e42a added less severe failure conditions to shutil, luash should crash less now. 2017-09-18 07:51:48 +10:00
Izaya 50d77f2904 added some programs to manage permissions from the shell 2017-09-15 19:57:11 +10:00
Izaya 3c6ac7db1a the nobody UID is no longer allowed to read or write files 2017-09-15 19:56:35 +10:00
Izaya 1e8c16e691 canwrite(p) actually works now 2017-09-15 19:52:56 +10:00
Izaya 8f80df31ea Merge branch 'master' into fsdev 2017-09-15 19:47:55 +10:00
Izaya 580f975263 convinced the io.open stuff to work properly 2017-09-15 19:30:04 +10:00
Izaya 3c84f6224b moved checks to more generic canread() and canwrite() functions 2017-09-15 17:40:34 +10:00
Izaya 3138eb29b8 added the get/setattr functions to the API docs 2017-09-15 16:28:10 +10:00
Izaya 5fcc09e03c exposed parseacl as part of _G 2017-09-15 16:04:19 +10:00
Izaya 67356aa589 made setattr() convert values to strings 2017-09-15 15:59:43 +10:00
Izaya 366a420930 can only r/w attributes if you have r/w permissions in the attributes 2017-09-15 15:58:42 +10:00
Izaya 016e4f2d58 made fs attribute loading spam the log less. 2017-09-15 15:40:08 +10:00
Izaya c1005e3ae6 added some basic fs attribute support, stored in memory. 2017-09-15 15:38:16 +10:00
39 changed files with 997 additions and 593 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
out/*
kernel.lua
skernel.lua
header.lua
*.swp

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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*

View File

@ -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.

View File

@ -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)).

78
docs/install.md Normal file
View File

@ -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.

74
docs/userguide.md Normal file
View File

@ -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
```

19
exec/addperm.lua Normal file
View File

@ -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

73
exec/lmk.lua Normal file
View File

@ -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()

View File

@ -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})

20
exec/lush.lua Normal file
View File

@ -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

5
exec/msh.lua Normal file
View File

@ -0,0 +1,5 @@
while true do
local line = readln()
if not line then break end
print(pcall(load(line)))
end

View File

@ -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.")

View File

@ -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)

73
exec/pkg.lua Normal file
View File

@ -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

19
exec/rmperm.lua Normal file
View File

@ -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

20
exec/update.lua Normal file
View File

@ -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

View File

@ -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

12
genheader.lua Executable file
View File

@ -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()

View File

@ -1,3 +0,0 @@
#!/usr/bin/env lua
require "modules/applications/genkernel"
print(genkernel(...))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -1 +1 @@
run("/boot/sys/init.lua")
spawn("autorun",function() log(run("/boot/sys/init.lua")) end)

View File

@ -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

View File

@ -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

172
sebios2.lua Normal file
View File

@ -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()

View File

@ -22,7 +22,7 @@ replacements={
{" %/ ","/"},
{" %* ","*"},
{" \n","\n"},
{"%-%-.-\n",""},
{"%-%-.-\n","\n"},
}
for k,v in ipairs(replacements) do
while ss:find(v[1]) ~= nil do