Compare commits
26
Commits
1.2.4-dev
...
4ed82a23a1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ed82a23a1 | ||
|
|
10aa0c62ff | ||
|
|
56646625c0 | ||
|
|
49c9e5e37c | ||
|
|
f7b64c11b7 | ||
|
|
59e09a5995 | ||
|
|
ab0a10105c | ||
|
|
22b5021e9d | ||
|
|
462c74686a | ||
|
|
0072547beb | ||
|
|
7deefc83ca | ||
|
|
df62414229 | ||
|
|
055dd4e606 | ||
|
|
5755dd9cbe | ||
|
|
8e11faf9ec | ||
|
|
0ea42f9454 | ||
|
|
d0f26a937f | ||
|
|
9b338328f0 | ||
|
|
4f9eebade2 | ||
|
|
d08935b68a | ||
|
|
45b46cf3c4 | ||
|
|
aeea68bc9b | ||
|
|
f983b13d56 | ||
|
|
03c5b106c4 | ||
|
|
08323e00ff | ||
|
|
5e3cdbe40c |
No files matched your search
Vendored
+5
-1
@@ -6,6 +6,10 @@
|
||||
"printf",
|
||||
"printInline",
|
||||
"toHex",
|
||||
"loadcstr"
|
||||
"loadcstr",
|
||||
"userinput"
|
||||
],
|
||||
"Lua.diagnostics.disable": [
|
||||
"need-check-nil"
|
||||
]
|
||||
}
|
||||
@@ -1,18 +1,202 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Astronand
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
1. Definitions.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -15,8 +15,10 @@ See `building.md`.
|
||||
|
||||
- Functionality is split into kernel modules (`.kmod`)
|
||||
- Task-based lightweight thread/task preemptive scheduler with process isolation and IPC support
|
||||
- Virtual filesystem unified interface for disk, RAM, and virtual filesystems
|
||||
- Virtual filesystem
|
||||
- TTY & Shell
|
||||
- Sockets
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
@@ -48,6 +50,12 @@ Add your name to `contributors.md` when your PR is merged.
|
||||
|
||||
---
|
||||
|
||||
## Information
|
||||
|
||||
Trello: https://trello.com/b/8dryrlMi
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the LICENSE file for details.
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1,18 @@
|
||||
--:Minify:--
|
||||
return {
|
||||
white=0xFFFFFF,
|
||||
red=0xFF0000,
|
||||
green=0x00FF00,
|
||||
blue=0x0000FF,
|
||||
cyan=0x00FFFF,
|
||||
yellow=0xFFFF00,
|
||||
purple=0xFF00FF,
|
||||
black=0x000000,
|
||||
gray=0x888888,
|
||||
lightgrey=0xBBBBBB,
|
||||
darkgrey=0x444444,
|
||||
orange=0xFF8800,
|
||||
mint=0x00FF88,
|
||||
brown=0xa52a2a,
|
||||
chocolate=0xd2691e
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
--:Minify:--
|
||||
local fs={}
|
||||
|
||||
-- "open" : open
|
||||
-- "read" : read
|
||||
-- "write" : write
|
||||
-- "close" : close
|
||||
|
||||
function fs.open(path, mode)
|
||||
local fd=syscall.open(path,mode)
|
||||
local ret={
|
||||
@@ -140,4 +135,12 @@ function fs.isDir(path)
|
||||
return syscall.type(path) == "directory"
|
||||
end
|
||||
|
||||
function fs.symlink(target, path)
|
||||
return syscall.syslink(target, path)
|
||||
end
|
||||
|
||||
function fs.readlink(path)
|
||||
return syscall.readlink(path)
|
||||
end
|
||||
|
||||
return fs
|
||||
@@ -0,0 +1,182 @@
|
||||
--:Minify:--
|
||||
local http = {}
|
||||
|
||||
local syscall = syscall
|
||||
|
||||
local function parseUrl(url)
|
||||
local proto, host, path =
|
||||
url:match(
|
||||
"^(https?://)([^/]+)(/.*)$"
|
||||
)
|
||||
|
||||
if not proto then
|
||||
proto, host =
|
||||
url:match(
|
||||
"^(https?://)([^/]+)$"
|
||||
)
|
||||
|
||||
path = "/"
|
||||
end
|
||||
|
||||
if not proto then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
|
||||
return host, path
|
||||
end
|
||||
|
||||
local function buildRequest(req)
|
||||
local host, path = parseUrl(req.url)
|
||||
|
||||
if not host then
|
||||
return nil, path
|
||||
end
|
||||
|
||||
local method =
|
||||
req.method or "GET"
|
||||
|
||||
local body =
|
||||
req.body or ""
|
||||
|
||||
local headers =
|
||||
table.deepcopy(
|
||||
req.headers or {}
|
||||
)
|
||||
|
||||
headers.Host =
|
||||
headers.Host or host
|
||||
|
||||
headers.Connection =
|
||||
headers.Connection or "close"
|
||||
|
||||
if body ~= "" then
|
||||
headers["Content-Length"] =
|
||||
tostring(#body)
|
||||
end
|
||||
|
||||
local out = {
|
||||
method ..
|
||||
" " ..
|
||||
path ..
|
||||
" HTTP/1.1"
|
||||
}
|
||||
|
||||
for k, v in pairs(headers) do
|
||||
out[#out + 1] =
|
||||
tostring(k) ..
|
||||
": " ..
|
||||
tostring(v)
|
||||
end
|
||||
|
||||
out[#out + 1] = ""
|
||||
out[#out + 1] = body
|
||||
|
||||
return table.concat(out, "\r\n")
|
||||
end
|
||||
|
||||
local function parseResponse(response)
|
||||
local headerBlock, body = response:match("^(.-)\r\n\r\n(.*)$")
|
||||
if not headerBlock then
|
||||
return nil, "invalid HTTP response"
|
||||
end
|
||||
|
||||
local headers = {}
|
||||
|
||||
-- Parse status line
|
||||
local statusLine, rest = headerBlock:match("^(.-)\r\n(.*)$")
|
||||
if not statusLine then
|
||||
statusLine = headerBlock
|
||||
rest = ""
|
||||
end
|
||||
|
||||
local version, code, message = statusLine:match("^(HTTP/%d+%.%d+)%s+(%d+)%s+(.*)$")
|
||||
|
||||
-- Parse headers
|
||||
for line in (rest .. "\r\n"):gmatch("(.-)\r\n") do
|
||||
local key, value = line:match("^([^:]+):%s*(.*)$")
|
||||
if key then
|
||||
headers[key:lower()] = value
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
code=tonumber(code),
|
||||
message=message,
|
||||
headers=headers,
|
||||
body=body
|
||||
}
|
||||
end
|
||||
|
||||
function http.request(req)
|
||||
local raw, err =
|
||||
buildRequest(req)
|
||||
|
||||
if not raw then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local fd =
|
||||
syscall.socket()
|
||||
|
||||
if not fd then
|
||||
return nil, "ESOCKET"
|
||||
end
|
||||
|
||||
local host, path = parseUrl(req.url)
|
||||
|
||||
if not host then
|
||||
syscall.close(fd)
|
||||
return nil, path
|
||||
end
|
||||
|
||||
local proto = req.url:match("^(https?://)")
|
||||
|
||||
local base = proto .. host
|
||||
|
||||
local ok, err = syscall.connect(fd, base)
|
||||
|
||||
if not ok then
|
||||
syscall.close(fd)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local ok2, err2 = syscall.write(fd, raw)
|
||||
|
||||
if not ok2 then
|
||||
syscall.close(fd)
|
||||
return nil, err2
|
||||
end
|
||||
|
||||
local out = {}
|
||||
|
||||
while true do
|
||||
local chunk = syscall.read(fd, 4096)
|
||||
if chunk == "" then
|
||||
break
|
||||
end
|
||||
|
||||
out[#out+1] = chunk
|
||||
end
|
||||
|
||||
syscall.close(fd)
|
||||
return parseResponse(table.concat(out))
|
||||
end
|
||||
|
||||
function http.get(url, headers)
|
||||
return http.request({
|
||||
url = url,
|
||||
method = "GET",
|
||||
headers = headers
|
||||
})
|
||||
end
|
||||
|
||||
function http.post(url, body, headers)
|
||||
return http.request({
|
||||
url = url,
|
||||
method = "POST",
|
||||
body = body,
|
||||
headers = headers
|
||||
})
|
||||
end
|
||||
|
||||
return http
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
Core library for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
GHXX (Advanced Computers)
|
||||
+130
-100
@@ -1,54 +1,39 @@
|
||||
-- :Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
local os = os
|
||||
--:Minify:--
|
||||
local args={...}
|
||||
local bootdrive=args[1]
|
||||
local gpu=components:getFirst("gpu")
|
||||
local screenTextBuffer=nil
|
||||
local cursorX,cursorY=0,0
|
||||
local screenSizeX,screenSizeY=128,25
|
||||
|
||||
|
||||
if gpu then
|
||||
screenTextBuffer=gpu:newBuffer(screenSizeX,screenSizeY)
|
||||
for t,v in components:list() do
|
||||
if t == "screen" then
|
||||
gpu:assignBuffer(screenTextBuffer, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function write(text)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
cursorX, cursorY = screenTextBuffer:pasteText(cursorX, cursorY, "SCROLL_SPILL_CLEAR", text)
|
||||
cursorY = cursorY + 1
|
||||
cursorX = 0
|
||||
if cursorY >= screenSizeY then
|
||||
cursorY = screenSizeY-1
|
||||
screenTextBuffer:newline()
|
||||
end
|
||||
end
|
||||
|
||||
local function displaySuperBadError(err)
|
||||
gpu:freeAllBuffers()
|
||||
screenTextBuffer=gpu:newBuffer(screenSizeX,screenSizeY)
|
||||
for t,v in components:list() do
|
||||
if t == "screen" then
|
||||
gpu:assignBuffer(screenTextBuffer, v)
|
||||
end
|
||||
end
|
||||
term.setBackgroundColor(0x1)
|
||||
term.setTextColor(0x4)
|
||||
term.clear()
|
||||
@@ -59,9 +44,8 @@ local function displaySuperBadError(err)
|
||||
while true do end
|
||||
end
|
||||
|
||||
term.setCursorBlink(false)
|
||||
local ok, err = xpcall(function()
|
||||
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
||||
local apis = {}
|
||||
|
||||
local lua = {
|
||||
coroutine = true,
|
||||
@@ -102,79 +86,125 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
|
||||
local acekeys={
|
||||
[apis.keys.enter]="\n",
|
||||
[apis.keys.tab]="\t",
|
||||
[apis.keys.backspace]="\b",
|
||||
[apis.keys.up]="\17",
|
||||
[apis.keys.down]="\18",
|
||||
[apis.keys.left]="\19",
|
||||
[apis.keys.right]="\20",
|
||||
}
|
||||
local function string_file(file)
|
||||
local str = file:read()
|
||||
local buf = {str or ""}
|
||||
local pos = 1
|
||||
local closed = false
|
||||
|
||||
function sleep(time)
|
||||
local stoptime = apis.os.clock() + (time)
|
||||
while stoptime > apis.os.clock() do end
|
||||
local function content()
|
||||
return table.concat(buf)
|
||||
end
|
||||
|
||||
local function set_content(s)
|
||||
buf = {s}
|
||||
end
|
||||
|
||||
local function flush()
|
||||
file.write(content())
|
||||
end
|
||||
|
||||
local file = {}
|
||||
|
||||
function file.read(n)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
if not n then
|
||||
local out = s:sub(pos)
|
||||
pos = len + 1
|
||||
return out
|
||||
end
|
||||
|
||||
local out = s:sub(pos, pos + n - 1)
|
||||
pos = pos + #out
|
||||
return out
|
||||
end
|
||||
|
||||
function file.write(data)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local before = s:sub(1, pos - 1)
|
||||
local after = s:sub(pos + #data)
|
||||
|
||||
set_content(before .. data .. after)
|
||||
pos = pos + #data
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function file.seek(whence, offset)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
whence = whence or "cur"
|
||||
offset = offset or 0
|
||||
|
||||
if whence == "set" then
|
||||
pos = offset + 1
|
||||
elseif whence == "cur" then
|
||||
pos = pos + offset
|
||||
elseif whence == "end" then
|
||||
pos = len + offset + 1
|
||||
else
|
||||
error("invalid whence")
|
||||
end
|
||||
|
||||
if pos < 1 then pos = 1 end
|
||||
if pos > len + 1 then pos = len + 1 end
|
||||
|
||||
return pos - 1
|
||||
end
|
||||
|
||||
function file:close()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
closed = true
|
||||
end
|
||||
|
||||
function file:flush()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
end
|
||||
|
||||
return file
|
||||
end
|
||||
|
||||
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
|
||||
local function getFile(path)
|
||||
local file = apis.fs.open(path, "r")
|
||||
local file = bootdrive:open(path, "r")
|
||||
if not file then
|
||||
displaySuperBadError("Could not open file: " .. path)
|
||||
end
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
local content = file:read()
|
||||
return content
|
||||
end
|
||||
|
||||
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
|
||||
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
|
||||
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
|
||||
local Kernel = load(getFile("/boot/kernel.lua"),"@Kernel")
|
||||
local initFs = load(getFile("/boot/ac/initdisks"),"@Init_disks")(apis)
|
||||
local fs = load(getFile("/boot/initfs"), "@InitFs")()
|
||||
|
||||
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local computercomp=apis.components:getFirst("computer")
|
||||
local uefi=apis.components:getFirst("uefi")
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
return computercomp:getMachineEvent()
|
||||
end,
|
||||
getEEPROM = function() return getFile("/startup.lua") end,
|
||||
getEEPROM = function() return uefi.data end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open("/startup.lua", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
uefi.data=text
|
||||
end
|
||||
}
|
||||
|
||||
@@ -213,7 +243,7 @@ local ok, err = xpcall(function()
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
@@ -0,0 +1 @@
|
||||
firmware for Advanced Computers
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,9 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
|
||||
local kbs = {kernel.cct.peripheral.find("tm_keyboard")}
|
||||
|
||||
|
||||
kernel.cct.eventhooks["tm_keyboard_char"]=function(...)
|
||||
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -1,155 +0,0 @@
|
||||
-- :Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.getType(name)
|
||||
if native.isPresent(name) then return native.getType(name) end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and
|
||||
native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getTypeRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getNames()
|
||||
local names = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then table.insert(names, side) end
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local hubSides = native.call(side, "getConnectedSides")
|
||||
for _, hubSide in ipairs(hubSides) do
|
||||
table.insert(names, hubSide)
|
||||
end
|
||||
end
|
||||
end
|
||||
return names
|
||||
end
|
||||
|
||||
local disks = {}
|
||||
local internal = {}
|
||||
|
||||
local function norm(path)
|
||||
if not path or path == "" then return "/" end
|
||||
return fs.combine("/", path)
|
||||
end
|
||||
|
||||
local function createDisk(id, basePath, readonly, periph)
|
||||
basePath = norm(basePath)
|
||||
|
||||
local disk = {address = id, isReadOnly = function() return readonly end}
|
||||
|
||||
function disk:spaceUsed()
|
||||
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
|
||||
end
|
||||
|
||||
function disk:spaceTotal() return fs.getCapacity(basePath) end
|
||||
|
||||
function disk:list(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) or not fs.isDir(p) then
|
||||
return nil, "not directory"
|
||||
end
|
||||
return fs.list(p)
|
||||
end
|
||||
|
||||
function disk:fileExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and not fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:directoryExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:type(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) then
|
||||
return nil
|
||||
elseif fs.isDir(p) then
|
||||
return "directory"
|
||||
else
|
||||
return "file"
|
||||
end
|
||||
end
|
||||
|
||||
function disk:makeDirectory(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
fs.makeDir(p)
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:remove(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if fs.exists(p) then fs.delete(p) end
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:setLabel(label) periph.setLabel(label) end
|
||||
|
||||
function disk:getLabel(label) return periph.getLabel() end
|
||||
|
||||
function disk:attributes(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.attributes(p)
|
||||
end
|
||||
|
||||
function disk:open(path, mode)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.open(p, mode)
|
||||
end
|
||||
|
||||
return disk
|
||||
end
|
||||
|
||||
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
setLabel = function(label)
|
||||
local h = fs.open("/.label", "w")
|
||||
h.write(label)
|
||||
h.close()
|
||||
end,
|
||||
getLabel = function()
|
||||
local h = fs.open("/.label", "r")
|
||||
if not h then return "$" end
|
||||
local label = h.readAll()
|
||||
h.close()
|
||||
return label
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
for id, _ in pairs(disks) do
|
||||
if not peripheral.getType(id) then disks[id] = nil end
|
||||
end
|
||||
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == "disk" then
|
||||
if not disks[name] then
|
||||
local mount = disk.getMountPath(name)
|
||||
if mount then
|
||||
disks[name] = createDisk(name, mount, false, disk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function iter()
|
||||
refresh()
|
||||
local combined = {}
|
||||
|
||||
for id, obj in pairs(internal) do combined[id] = obj end
|
||||
for id, obj in pairs(disks) do combined[id] = obj end
|
||||
|
||||
return pairs(combined)
|
||||
end
|
||||
|
||||
return {refresh = refresh, list = iter}
|
||||
+141
-70
@@ -1,4 +1,4 @@
|
||||
-- :Minify:--
|
||||
--:Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
@@ -71,7 +71,6 @@ local ok, err = xpcall(function()
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
gcinfo = true,
|
||||
getfenv = true,
|
||||
getmetatable = true,
|
||||
ipairs = true,
|
||||
__inext = true,
|
||||
@@ -85,7 +84,6 @@ local ok, err = xpcall(function()
|
||||
rawlen = true,
|
||||
rawset = true,
|
||||
select = true,
|
||||
setfenv = true,
|
||||
setmetatable = true,
|
||||
string = true,
|
||||
table = true,
|
||||
@@ -154,17 +152,106 @@ local ok, err = xpcall(function()
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
if not apis.fs.exists("/nvram.dat") then
|
||||
local file = apis.fs.open("/nvram.dat", "w")
|
||||
file.write("Hello, World!")
|
||||
file.close()
|
||||
end
|
||||
|
||||
local eeprom
|
||||
if apis.fs.exists("/startup.lua") then
|
||||
eeprom="/startup.lua"
|
||||
elseif apis.fs.exists("/eeprom") then
|
||||
eeprom="/eeprom"
|
||||
end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
local colors = {
|
||||
[0x000000]=0x0001,
|
||||
[0xFFFFFF]=0x0002,
|
||||
[0xFF0000]=0x0004,
|
||||
[0x00FF00]=0x0008,
|
||||
[0x0000FF]=0x0010,
|
||||
[0x00FFFF]=0x0020,
|
||||
[0xFF00FF]=0x0040,
|
||||
[0xFFFF00]=0x0080,
|
||||
[0xFF6D00]=0x0100,
|
||||
[0x6DFF55]=0x0200,
|
||||
[0x24FFFF]=0x0400,
|
||||
[0x924900]=0x0800,
|
||||
[0x6D6D55]=0x1000,
|
||||
[0xDBDBAA]=0x2000,
|
||||
[0x6D00FF]=0x4000,
|
||||
[0xB6FF00]=0x8000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local EFI = {
|
||||
getEpochMs = function() return apis.os.epoch("utc") end,
|
||||
getUptime = function() return apis.os.clock() * 1000 end,
|
||||
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
@@ -172,61 +259,15 @@ local ok, err = xpcall(function()
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
getEEPROM = function() return getFile("/startup.lua") end,
|
||||
getEEPROM = function() return getFile(eeprom) end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open("/startup.lua", "w")
|
||||
local h = apis.fs.open(eeprom, "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end
|
||||
}
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
|
||||
{
|
||||
end,
|
||||
initfs=fs,
|
||||
disks=initFs,
|
||||
screenCtl={
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
clear = function()
|
||||
@@ -239,25 +280,51 @@ local ok, err = xpcall(function()
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(colors[color])
|
||||
apis.term.setBackgroundColor(aprox(color))
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(colors[color])
|
||||
apis.term.setTextColor(aprox(color))
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return icolors[apis.term.getBackgroundColor()]
|
||||
return bg
|
||||
end,
|
||||
getTextColor = function()
|
||||
return icolors[apis.term.getTextColor()]
|
||||
end
|
||||
}, computer, fs, "$")
|
||||
if not ok then displaySuperBadError(err) end
|
||||
return fg
|
||||
end,
|
||||
enable=function() end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
getNvram = function() return getFile("/nvram.dat") end,
|
||||
setNvram = function(_, text)
|
||||
local h = apis.fs.open("/nvram.dat", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end,
|
||||
firmware=apis,
|
||||
reboot=false
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
||||
if not ok and not EFI.reboot then displaySuperBadError(err) end
|
||||
if err then
|
||||
apis.os.reboot()
|
||||
else
|
||||
apis.os.shutdown()
|
||||
end
|
||||
end)
|
||||
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = computer.time()
|
||||
local startTime = EFI.getEpochMs()
|
||||
debug.sethook(co, function()
|
||||
if computer.time() > startTime + timeout then
|
||||
if EFI.getEpochMs() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
@@ -306,11 +373,15 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
if EFI.reboot then
|
||||
apis.os.reboot()
|
||||
end
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
initFs:refresh()
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield() end
|
||||
while true do coroutine.yield("key") end
|
||||
File renamed without changes.
+11
-5
@@ -1,6 +1,6 @@
|
||||
-- :Minify:--
|
||||
--:Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
@@ -241,11 +241,17 @@ internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
for id, _ in pairs(disks) do
|
||||
if not peripheral.getType(id) then disks[id] = nil end
|
||||
internal["rom"] = createDisk("rom", "/rom", true, {
|
||||
setLabel = function(label)
|
||||
error("Device is read-only")
|
||||
end,
|
||||
getLabel = function()
|
||||
return "cctrom"
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
disks={}
|
||||
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||
if disk.isDiskPresent() then
|
||||
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
|
||||
@@ -0,0 +1,6 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
|
||||
if kernel.gfx then
|
||||
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
firmware for CraftOS PC
|
||||
@@ -1,394 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
local peripheral={}
|
||||
|
||||
function peripheral.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
kernel.devfs.data.tty={}
|
||||
local ctrl,alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
if bool then
|
||||
return "T"
|
||||
else
|
||||
return "F"
|
||||
end
|
||||
end
|
||||
|
||||
local function newtty(obj, id, ev)
|
||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
local rv=""
|
||||
for i=1, amount or 1 do
|
||||
local event = {ev()}
|
||||
if event[1] then
|
||||
rv=rv..event[1]
|
||||
end
|
||||
end
|
||||
if rv=="" then rv=nil end
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
write(content, obj)
|
||||
end,
|
||||
size=function()
|
||||
local s={obj.getSize()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
clear=function()
|
||||
obj.clear()
|
||||
obj.setCursorPos(1,1)
|
||||
end,
|
||||
gpos=function()
|
||||
local s={obj.getCursorPos()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
spos=function(x,y)
|
||||
return obj.setCursorPos(x,y)
|
||||
end,
|
||||
sfgc=function(c)
|
||||
return obj.setTextColor(colors[c])
|
||||
end,
|
||||
sbgc=function(c)
|
||||
return obj.setBackgroundColor(colors[c])
|
||||
end,
|
||||
gfgc=function()
|
||||
return icolors[obj.getTextColor()]
|
||||
end,
|
||||
gbgc=function()
|
||||
return icolors[obj.getBackgroundColor()]
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
return h
|
||||
elseif mode=="r" then
|
||||
h["write"]=nil
|
||||
return h
|
||||
elseif mode=="w" then
|
||||
h["read"]=nil
|
||||
return h
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local fifo = kernel.newFifo()
|
||||
|
||||
kernel.processes.cctmond = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.computer:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
local ctrlKeyMap = {
|
||||
[apis.keys.a]=1, [apis.keys.b]=2, [apis.keys.c]=3,
|
||||
[apis.keys.d]=4, [apis.keys.e]=5, [apis.keys.f]=6,
|
||||
[apis.keys.g]=7, [apis.keys.h]=8, [apis.keys.i]=9,
|
||||
[apis.keys.j]=10, [apis.keys.k]=11, [apis.keys.l]=12,
|
||||
[apis.keys.m]=13, [apis.keys.n]=14, [apis.keys.o]=15,
|
||||
[apis.keys.p]=16, [apis.keys.q]=17, [apis.keys.r]=18,
|
||||
[apis.keys.s]=19, [apis.keys.t]=20, [apis.keys.u]=21,
|
||||
[apis.keys.v]=22, [apis.keys.w]=23, [apis.keys.x]=24,
|
||||
[apis.keys.y]=25, [apis.keys.z]=26,
|
||||
}
|
||||
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = true
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = true
|
||||
end
|
||||
|
||||
if ctrl then
|
||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||
if ctrlByte then
|
||||
if ctrlByte == 3 then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1)
|
||||
end
|
||||
else
|
||||
fifo.push(string.char(ctrlByte))
|
||||
end
|
||||
end
|
||||
else
|
||||
local specialKeyMap = {
|
||||
[apis.keys.up] = "[A",
|
||||
[apis.keys.down] = "[B",
|
||||
[apis.keys.right] = "[C",
|
||||
[apis.keys.left] = "[D",
|
||||
[apis.keys.home] = "[H",
|
||||
[apis.keys["end"]] = "[F",
|
||||
[apis.keys.pageUp] = "[5~",
|
||||
[apis.keys.pageDown] = "[6~",
|
||||
[apis.keys.delete] = "[3~",
|
||||
}
|
||||
local special = specialKeyMap[charOrKey]
|
||||
if special then fifo.push(special) end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = false
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then fifo.push(charOrKey) end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newtty(apis.term, "1", fifo.pop)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
v.setTextScale(.5)
|
||||
v.write("Initializing...")
|
||||
newtty(v,tostring(i+1),function () end)
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1,589 @@
|
||||
--:Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local lterm = term
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
local function displaySuperBadError(err)
|
||||
lterm.setBackgroundColor(0x1)
|
||||
lterm.setTextColor(0x4)
|
||||
lterm.clear()
|
||||
lterm.setCursorPos(1, 1)
|
||||
lterm.write("A critical error occurred while loading the system:")
|
||||
lterm.setCursorPos(1, 3)
|
||||
write(err, lterm)
|
||||
coroutine.yield("key")
|
||||
end
|
||||
|
||||
term.setCursorBlink(false)
|
||||
local ok, err = xpcall(function()
|
||||
--p
|
||||
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
||||
|
||||
local lua = {
|
||||
coroutine = true,
|
||||
debug = true,
|
||||
_VERSION = true,
|
||||
assert = true,
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
gcinfo = true,
|
||||
getmetatable = true,
|
||||
ipairs = true,
|
||||
__inext = true,
|
||||
load = true,
|
||||
math = true,
|
||||
next = true,
|
||||
pairs = true,
|
||||
pcall = true,
|
||||
rawequal = true,
|
||||
rawget = true,
|
||||
rawlen = true,
|
||||
rawset = true,
|
||||
select = true,
|
||||
setmetatable = true,
|
||||
string = true,
|
||||
table = true,
|
||||
tonumber = true,
|
||||
tostring = true,
|
||||
type = true,
|
||||
xpcall = true,
|
||||
_G = true
|
||||
}
|
||||
|
||||
local debug = debug
|
||||
for i, v in pairs(_G) do
|
||||
if not lua[i] or lua[i] == nil then
|
||||
apis[i] = v
|
||||
_G[i] = nil
|
||||
end
|
||||
end
|
||||
--p
|
||||
|
||||
local acekeys={
|
||||
[apis.keys.enter]="\n",
|
||||
[apis.keys.tab]="\t",
|
||||
[apis.keys.backspace]="\b",
|
||||
[apis.keys.up]="\17",
|
||||
[apis.keys.down]="\18",
|
||||
[apis.keys.left]="\19",
|
||||
[apis.keys.right]="\20",
|
||||
}
|
||||
|
||||
function sleep(time)
|
||||
local stoptime = apis.os.clock() + (time)
|
||||
while stoptime > apis.os.clock() do end
|
||||
end
|
||||
|
||||
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
|
||||
local function getFile(path)
|
||||
local file = apis.fs.open(path, "r")
|
||||
if not file then
|
||||
displaySuperBadError("Could not open file: " .. path)
|
||||
end
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
return content
|
||||
end
|
||||
|
||||
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
|
||||
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
|
||||
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
|
||||
|
||||
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
if not apis.fs.exists("/nvram.dat") then
|
||||
local file = apis.fs.open("/nvram.dat", "w")
|
||||
file.write("Hello, World!")
|
||||
file.close()
|
||||
end
|
||||
|
||||
local eeprom
|
||||
if apis.fs.exists("/startup.lua") then
|
||||
eeprom="/startup.lua"
|
||||
elseif apis.fs.exists("/eeprom") then
|
||||
eeprom="/eeprom"
|
||||
end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local colors = {
|
||||
[0xFFFFFF]=0x0001,
|
||||
[0xFF0000]=0x0002,
|
||||
[0x00FF00]=0x0004,
|
||||
[0x0000FF]=0x0008,
|
||||
[0x00FFFF]=0x0010,
|
||||
[0xFF00FF]=0x0020,
|
||||
[0xFFFF00]=0x0040,
|
||||
[0xFF6D00]=0x0080,
|
||||
[0x6DFF55]=0x0100,
|
||||
[0x24FFFF]=0x0200,
|
||||
[0x924900]=0x0400,
|
||||
[0x6D6D55]=0x0800,
|
||||
[0xDBDBAA]=0x1000,
|
||||
[0x6D00FF]=0x2000,
|
||||
[0xB6FF00]=0x4000,
|
||||
[0x000000]=0x8000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
if k==target then return k end
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
--p
|
||||
local p={}
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function p.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function p.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function p.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function p.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function p.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function p.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function p.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function p.wrap(name)
|
||||
local methods = p.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { p.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return p.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function p.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(p.getNames()) do
|
||||
if p.hasType(name, ty) then
|
||||
local wrapped = p.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
--p
|
||||
local allscreens = {p.find("monitor")}
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setTextScale(.5)
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1,1)
|
||||
end
|
||||
|
||||
allscreens[#allscreens+1] = apis.term
|
||||
|
||||
local callAsyncQueue = {}
|
||||
local callAsyncReturn = {}
|
||||
apis.callAsyncReturn = callAsyncReturn
|
||||
local callidx=0
|
||||
|
||||
function apis.callAsync(func, ...)
|
||||
callidx=callidx+1
|
||||
callAsyncQueue[#callAsyncQueue+1] = {callidx, func, ...}
|
||||
return callidx
|
||||
end
|
||||
|
||||
local EFI = {
|
||||
getEpochMs = function() return apis.os.epoch("utc") end,
|
||||
getUptime = function() return apis.os.clock() * 1000 end,
|
||||
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
getEEPROM = function() return getFile(eeprom) end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open(eeprom, "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end,
|
||||
initfs=fs,
|
||||
disks=initFs,
|
||||
screenCtl={
|
||||
print = function(_, text)
|
||||
for i=1, #allscreens do
|
||||
write(text.."\n", allscreens[i])
|
||||
end
|
||||
end,
|
||||
printInline = function(_, text)
|
||||
for i=1, #allscreens do
|
||||
write(text, allscreens[i])
|
||||
end
|
||||
end,
|
||||
clear = function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
resetCursor = function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
setBackgroundColor = function(_, color)
|
||||
bg=color
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setBackgroundColor(aprox(color))
|
||||
end
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
fg=color
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setTextColor(aprox(color))
|
||||
end
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return bg
|
||||
end,
|
||||
getTextColor = function()
|
||||
return fg
|
||||
end,
|
||||
enable=function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
getNvram = function() return getFile("/nvram.dat") end,
|
||||
setNvram = function(_, text)
|
||||
local h = apis.fs.open("/nvram.dat", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end,
|
||||
firmware=apis,
|
||||
reboot=false,
|
||||
beep=function() end
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
--pf
|
||||
---@diagnostic disable-next-line: param-type-mismatch-
|
||||
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
||||
if not ok and not EFI.reboot then displaySuperBadError(err) end
|
||||
if err then
|
||||
apis.os.reboot()
|
||||
else
|
||||
apis.os.shutdown()
|
||||
end
|
||||
end)
|
||||
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = EFI.getEpochMs()
|
||||
debug.sethook(co, function()
|
||||
if EFI.getEpochMs() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
local ret = {coroutine.resume(co, ...)}
|
||||
if ret[1] and ret[2] == "timeout" then
|
||||
return "timeout"
|
||||
elseif ret[1] == false then
|
||||
return "error", ret[2]
|
||||
else
|
||||
debug.sethook(co)
|
||||
return "success", table.unpack(ret, 2)
|
||||
end
|
||||
end
|
||||
|
||||
EFI.screenCtl:print("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
--p
|
||||
|
||||
while true do
|
||||
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||
apis.os.queueEvent("NoSleep")
|
||||
local exit = false
|
||||
while not exit do
|
||||
local event = {coroutine.yield()}
|
||||
if event[1] == "key" then
|
||||
queueEvent(table.unpack(event))
|
||||
queueEvent("keyPressed", 1, event[2])
|
||||
if acekeys[event[2]] then
|
||||
queueEvent("keyTyped", 1, acekeys[event[2]])
|
||||
end
|
||||
elseif event[1] == "char" then
|
||||
queueEvent(table.unpack(event))
|
||||
queueEvent("keyTyped", 1, event[2])
|
||||
elseif event[1] == "key_up" then
|
||||
queueEvent(table.unpack(event))
|
||||
queueEvent("keyReleased", 1, event[2])
|
||||
elseif event[1] == "NoSleep" then
|
||||
exit = true
|
||||
else
|
||||
queueEvent(table.unpack(event))
|
||||
end
|
||||
end
|
||||
while #callAsyncQueue>0 do
|
||||
local bundle = table.remove(callAsyncQueue, 1)
|
||||
local ret = {xpcall(bundle[2], debug.traceback, table.unpack(bundle, 3))}
|
||||
if not ret[1] then
|
||||
callAsyncReturn[bundle[1]]={false, ret[2]}
|
||||
else
|
||||
callAsyncReturn[bundle[1]]={true, table.unpack(ret,2)}
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
if EFI.reboot then
|
||||
apis.os.reboot()
|
||||
end
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
elseif status == "success" then
|
||||
if EFI.reboot then
|
||||
apis.os.reboot()
|
||||
end
|
||||
displaySuperBadError("Kernel error: Attempted to yield main thread\n"..debug.traceback(kernelCoro, "Attempted to yield main thread"))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
initFs:refresh()
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield("key") end
|
||||
File renamed without changes.
@@ -0,0 +1,272 @@
|
||||
--:Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local disks = {}
|
||||
local internal = {}
|
||||
|
||||
local function norm(path)
|
||||
if not path or path == "" then return "/" end
|
||||
return fs.combine("/", path)
|
||||
end
|
||||
|
||||
local function createDisk(id, basePath, readonly, periph)
|
||||
basePath = norm(basePath)
|
||||
|
||||
local disk = {address = id, isReadOnly = function() return readonly end}
|
||||
|
||||
function disk:spaceUsed()
|
||||
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
|
||||
end
|
||||
|
||||
function disk:spaceTotal() return fs.getCapacity(basePath) end
|
||||
|
||||
function disk:list(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) or not fs.isDir(p) then
|
||||
return nil, "not directory"
|
||||
end
|
||||
return fs.list(p)
|
||||
end
|
||||
|
||||
function disk:fileExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and not fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:directoryExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:type(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) then
|
||||
return nil
|
||||
elseif fs.isDir(p) then
|
||||
return "directory"
|
||||
else
|
||||
return "file"
|
||||
end
|
||||
end
|
||||
|
||||
function disk:makeDirectory(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
fs.makeDir(p)
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:remove(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if fs.exists(p) then fs.delete(p) end
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:setLabel(label) periph.setLabel(label) end
|
||||
|
||||
function disk:getLabel(label) return periph.getLabel() end
|
||||
|
||||
function disk:attributes(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.attributes(p)
|
||||
end
|
||||
|
||||
function disk:open(path, mode)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.open(p, mode)
|
||||
end
|
||||
|
||||
return disk
|
||||
end
|
||||
|
||||
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
setLabel = function(label)
|
||||
local h = fs.open("/.label", "w")
|
||||
h.write(label)
|
||||
h.close()
|
||||
end,
|
||||
getLabel = function()
|
||||
local h = fs.open("/.label", "r")
|
||||
if not h then return "$" end
|
||||
local label = h.readAll()
|
||||
h.close()
|
||||
return label
|
||||
end
|
||||
})
|
||||
|
||||
internal["rom"] = createDisk("rom", "/rom", true, {
|
||||
setLabel = function(label)
|
||||
error("Device is read-only")
|
||||
end,
|
||||
getLabel = function()
|
||||
return "cctrom"
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
disks={}
|
||||
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||
if disk.isDiskPresent() then
|
||||
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function iter()
|
||||
refresh()
|
||||
local combined = {}
|
||||
|
||||
for id, obj in pairs(internal) do combined[id] = obj end
|
||||
for id, obj in pairs(disks) do combined[id] = obj end
|
||||
|
||||
return pairs(combined)
|
||||
end
|
||||
|
||||
return {refresh = refresh, list = iter}
|
||||
@@ -0,0 +1,195 @@
|
||||
--:Minify:--
|
||||
-- CCT driver peripheral helper
|
||||
local kernel=...
|
||||
kernel.cct={}
|
||||
kernel.cct.peripheral={}
|
||||
kernel.cct.callAsync=kernel.apis.callAsync
|
||||
local peripheral=kernel.cct.peripheral
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
local id = kernel.cct.callAsync(native.call, name, method, ...)
|
||||
kernel.currentTask.io=function()
|
||||
if kernel.apis.callAsyncReturn[id] then
|
||||
local r=kernel.apis.callAsyncReturn[id]
|
||||
if not r[1] then error(r[2]) end
|
||||
kernel.apis.callAsyncReturn[id]=nil
|
||||
return table.unpack(r,2)
|
||||
end
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
local id = kernel.cct.callAsync(native.call, side, "callRemote", name, method, ...)
|
||||
kernel.currentTask.io=function()
|
||||
if kernel.apis.callAsyncReturn[id] then
|
||||
local r=kernel.apis.callAsyncReturn[id]
|
||||
if not r[1] then error(r[2]) end
|
||||
kernel.apis.callAsyncReturn[id]=nil
|
||||
return table.unpack(r,2)
|
||||
end
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.callnative(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name, wrap)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
if wrap then
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
else
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.callnative(name, method, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local peripheral=kernel.cct.peripheral
|
||||
|
||||
local function wrap(p)
|
||||
return function(op, mode)
|
||||
if op=="type" then
|
||||
return "device"
|
||||
elseif op=="open" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
return peripheral.wrap(p, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local peripherals=peripheral.getNames()
|
||||
for i=1, #peripherals do
|
||||
local p=peripherals[i]
|
||||
local typ=peripheral.getType(p)
|
||||
local file=wrap(p)
|
||||
kernel.devfs.data["raw"][p]=file
|
||||
local typefolder=kernel.devfs.data["raw"]["by-type"][typ]
|
||||
if not typefolder then typefolder={} end
|
||||
typefolder[tostring(#table.keys(typefolder)+1)] = file
|
||||
kernel.devfs.data["raw"]["by-type"][typ]=typefolder
|
||||
end
|
||||
@@ -0,0 +1,207 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local handler = {}
|
||||
|
||||
local http = kernel.apis.http
|
||||
|
||||
kernel.cct.httpqueue = kernel.cct.httpqueue or {}
|
||||
kernel.cct.httpresponse = kernel.cct.httpresponse or {}
|
||||
kernel.cct.httperror = kernel.cct.httperror or {}
|
||||
|
||||
local function parseRawRequest(raw, address)
|
||||
local headerEnd = raw:find("\r\n\r\n", 1, true)
|
||||
|
||||
local headerPart
|
||||
local body = ""
|
||||
|
||||
if headerEnd then
|
||||
headerPart = raw:sub(1, headerEnd - 1)
|
||||
body = raw:sub(headerEnd + 4)
|
||||
else
|
||||
headerPart = raw
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
|
||||
for line in headerPart:gmatch("[^\r\n]+") do
|
||||
lines[#lines + 1] = line
|
||||
end
|
||||
|
||||
if #lines == 0 then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
|
||||
local split=string.split(lines[1], " ")
|
||||
if #split~=3 then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
local method, path, ver = table.unpack(split)
|
||||
|
||||
local headers = {}
|
||||
|
||||
for i = 2, #lines do
|
||||
local k, v = lines[i]:match("^([^:]+):%s*(.*)$")
|
||||
if k then
|
||||
headers[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
if path:sub(1,1)~="/" then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
local url = address..path
|
||||
|
||||
local req = {
|
||||
url = url,
|
||||
method = method,
|
||||
headers = headers
|
||||
}
|
||||
|
||||
if body ~= "" then
|
||||
req.body = body
|
||||
end
|
||||
|
||||
return req, url
|
||||
end
|
||||
|
||||
local function buildResponse(resp)
|
||||
if not resp then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
|
||||
local code, msg = resp.getResponseCode()
|
||||
local headers = resp.getResponseHeaders()
|
||||
local body = resp.readAll() or ""
|
||||
resp.close()
|
||||
|
||||
local out = {
|
||||
"HTTP/1.1 " ..
|
||||
tostring(code) ..
|
||||
" " ..
|
||||
tostring(msg or "")
|
||||
}
|
||||
|
||||
for i,v in pairs(headers) do
|
||||
out[#out+1] = i..": "..v
|
||||
end
|
||||
|
||||
out[#out + 1] = ""
|
||||
out[#out + 1] = body
|
||||
|
||||
return table.concat(out, "\r\n")
|
||||
end
|
||||
|
||||
function handler.connect(fd, address)
|
||||
local fdo = kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
fdo.handle.write = function(raw)
|
||||
local req, url = parseRawRequest(raw, address)
|
||||
|
||||
if not req then
|
||||
return nil, url
|
||||
end
|
||||
|
||||
kernel.cct.httpqueue[url] = true
|
||||
local ok, err = http.request(req)
|
||||
|
||||
if not ok then
|
||||
kernel.cct.httpqueue[url] = nil
|
||||
return nil, err
|
||||
end
|
||||
if fdo.socket.active then
|
||||
fdo.socket.content=nil
|
||||
fdo.socket.file.close()
|
||||
fdo.socket.file=nil
|
||||
end
|
||||
fdo.socket.active=true
|
||||
fdo.socket.url=url
|
||||
fdo.socket.loaded=false
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
fdo.handle.read = function(count)
|
||||
if not fdo.socket.active then
|
||||
return
|
||||
end
|
||||
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] and not fdo.socket.loaded then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
fdo.socket.loaded=true
|
||||
end
|
||||
|
||||
if not fdo.socket.file then
|
||||
kernel.currentTask.io=function()
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
fdo.socket.loaded=true
|
||||
return fdo.socket.file.read(count)
|
||||
end
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
else
|
||||
return fdo.socket.file.read(count)
|
||||
end
|
||||
end
|
||||
|
||||
fdo.handle.seek = function(whence, offset)
|
||||
if not fdo.socket.active then
|
||||
return
|
||||
end
|
||||
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] and not fdo.socket.loaded then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
fdo.socket.loaded=true
|
||||
end
|
||||
|
||||
if not fdo.socket.file then
|
||||
kernel.currentTask.io=function()
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
fdo.socket.loaded=true
|
||||
return fdo.socket.file.seek(whence, offset)
|
||||
end
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
else
|
||||
return fdo.socket.file.seek(whence, offset)
|
||||
end
|
||||
end
|
||||
|
||||
fdo.handle.close = function()
|
||||
fdo.socket.file.close()
|
||||
fdo.socket.active=false
|
||||
kernel.cct.httpqueue[fdo.socket.url] = nil
|
||||
kernel.cct.httpresponse[fdo.socket.url] = nil
|
||||
kernel.cct.httperror[fdo.socket.url] = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
kernel.socket.registerProtocal(
|
||||
"http://",
|
||||
handler
|
||||
)
|
||||
|
||||
kernel.socket.registerProtocal(
|
||||
"https://",
|
||||
handler
|
||||
)
|
||||
@@ -0,0 +1,283 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local peripheral=kernel.cct.peripheral
|
||||
|
||||
local colors = {
|
||||
[0xFFFFFF]=0x0001,
|
||||
[0xFF0000]=0x0002,
|
||||
[0x00FF00]=0x0004,
|
||||
[0x0000FF]=0x0008,
|
||||
[0x00FFFF]=0x0010,
|
||||
[0xFF00FF]=0x0020,
|
||||
[0xFFFF00]=0x0040,
|
||||
[0xFF6D00]=0x0080,
|
||||
[0x6DFF55]=0x0100,
|
||||
[0x24FFFF]=0x0200,
|
||||
[0x924900]=0x0400,
|
||||
[0x6D6D55]=0x0800,
|
||||
[0xDBDBAA]=0x1000,
|
||||
[0x6D00FF]=0x2000,
|
||||
[0xB6FF00]=0x4000,
|
||||
[0x000000]=0x8000
|
||||
}
|
||||
|
||||
local plt = {
|
||||
0xFFFFFF,
|
||||
0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0x00FFFF,
|
||||
0xFF00FF,
|
||||
0xFFFF00,
|
||||
0xFF6D00,
|
||||
0x6DFF55,
|
||||
0x24FFFF,
|
||||
0x924900,
|
||||
0x6D6D55,
|
||||
0xDBDBAA,
|
||||
0x6D00FF,
|
||||
0xB6FF00,
|
||||
0x000000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
if k==target then return k end
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
kernel.cct.ctrl,kernel.cct.alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
if bool then
|
||||
return "T"
|
||||
else
|
||||
return "F"
|
||||
end
|
||||
end
|
||||
|
||||
local function newtty(obj, id, ev)
|
||||
obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
obj.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
obj.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
obj.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
obj.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
obj.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
obj.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
obj.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
obj.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
obj.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
obj.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
obj.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
obj.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
obj.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "Terminal"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
local rv=""
|
||||
for i=1, amount or 1 do
|
||||
local event = {ev()}
|
||||
if event[1] then
|
||||
rv=rv..event[1]
|
||||
end
|
||||
end
|
||||
if rv=="" then rv=nil end
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
write(content, obj)
|
||||
end,
|
||||
size=function()
|
||||
local s={obj.getSize()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
clear=function()
|
||||
obj.clear()
|
||||
obj.setCursorPos(1,1)
|
||||
end,
|
||||
gpos=function()
|
||||
local s={obj.getCursorPos()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
spos=function(x,y)
|
||||
return obj.setCursorPos(x,y)
|
||||
end,
|
||||
sfgc=function(c)
|
||||
fg=c
|
||||
return obj.setTextColor(aprox(c))
|
||||
end,
|
||||
sbgc=function(c)
|
||||
bg=c
|
||||
return obj.setBackgroundColor(aprox(c))
|
||||
end,
|
||||
gfgc=function()
|
||||
return fg
|
||||
end,
|
||||
gbgc=function()
|
||||
return bg
|
||||
end,
|
||||
isvirt=function()
|
||||
return false
|
||||
end,
|
||||
gplt=function()
|
||||
return plt
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
return h
|
||||
elseif mode=="r" then
|
||||
h["write"]=nil
|
||||
return h
|
||||
elseif mode=="w" then
|
||||
h["read"]=nil
|
||||
return h
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local fifo = kernel.newFifo()
|
||||
kernel.cct.fifo=fifo
|
||||
|
||||
newtty(kernel.apis.term, "1", function() end)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
newtty(v,tostring(i+1),function () end)
|
||||
end
|
||||
|
||||
kernel.devfs.data["input"]["keyboard1"] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "Keyboard"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
local rv=""
|
||||
for i=1, amount or 1 do
|
||||
local event = {fifo.pop()}
|
||||
if event[1] then
|
||||
rv=rv..event[1]
|
||||
end
|
||||
end
|
||||
if rv=="" then rv=nil end
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
return h
|
||||
elseif mode=="r" then
|
||||
h["write"]=nil
|
||||
return h
|
||||
elseif mode=="w" then
|
||||
h["read"]=nil
|
||||
return h
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local keys=kernel.apis.keys
|
||||
kernel.cct.eventhooks={}
|
||||
|
||||
kernel.processes.cctdaemon = function()
|
||||
local timeout = false
|
||||
kernel.log("CCT daemon started")
|
||||
while true do
|
||||
local event = {kernel.EFI:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
local ctrlKeyMap = {
|
||||
[keys.a]=1, [keys.b]=2, [keys.c]=3,
|
||||
[keys.d]=4, [keys.e]=5, [keys.f]=6,
|
||||
[keys.g]=7, [keys.h]=8, [keys.i]=9,
|
||||
[keys.j]=10, [keys.k]=11, [keys.l]=12,
|
||||
[keys.m]=13, [keys.n]=14, [keys.o]=15,
|
||||
[keys.p]=16, [keys.q]=17, [keys.r]=18,
|
||||
[keys.s]=19, [keys.t]=20, [keys.u]=21,
|
||||
[keys.v]=22, [keys.w]=23, [keys.x]=24,
|
||||
[keys.y]=25, [keys.z]=26,
|
||||
}
|
||||
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||
kernel.cct.ctrl = true
|
||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||
kernel.cct.alt = true
|
||||
end
|
||||
|
||||
if kernel.cct.ctrl then
|
||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||
if ctrlByte then
|
||||
if ctrlByte == 3 then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1)
|
||||
end
|
||||
else
|
||||
kernel.cct.fifo.push(string.char(ctrlByte))
|
||||
end
|
||||
end
|
||||
else
|
||||
local specialKeyMap = {
|
||||
[keys.up] = "[A",
|
||||
[keys.down] = "[B",
|
||||
[keys.right] = "[C",
|
||||
[keys.left] = "[D",
|
||||
[keys.home] = "[H",
|
||||
[keys["end"]] = "[F",
|
||||
[keys.pageUp] = "[5~",
|
||||
[keys.pageDown] = "[6~",
|
||||
[keys.delete] = "[3~",
|
||||
}
|
||||
local special = specialKeyMap[charOrKey]
|
||||
if special then kernel.cct.fifo.push(special) end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||
kernel.cct.ctrl = false
|
||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||
kernel.cct.alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then kernel.cct.fifo.push(charOrKey) end
|
||||
elseif eventType == "mouse_scroll" then
|
||||
if event[2] == 1 then
|
||||
kernel.cct.fifo.push("[nS")
|
||||
else
|
||||
kernel.cct.fifo.push("[nT")
|
||||
end
|
||||
elseif eventType == "http_success" then
|
||||
if kernel.cct.httpqueue[event[2]] then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httpresponse[event[2]]=event[3]
|
||||
end
|
||||
elseif eventType == "http_failure" then
|
||||
if kernel.cct.httpqueue[event[2]] then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httperror[event[2]]=event[3]
|
||||
kernel.cct.httpresponse[event[2]]=event[4]
|
||||
end
|
||||
else
|
||||
if kernel.cct.eventhooks[eventType] then
|
||||
local ok,err = xpcall(kernel.cct.eventhooks[eventType], debug.traceback, table.unpack(event))
|
||||
if not ok then
|
||||
kernel.log("Error on eventhook "..eventType.."\n"..err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("CCT daemon queued for execution")
|
||||
@@ -0,0 +1,25 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local rs=kernel.apis.rs
|
||||
local sides = {top=1, bottom=2, left=3, right=4, front=5, back=6}
|
||||
local function newGPIO(side)
|
||||
return function(mode, data)
|
||||
if mode=="w" then
|
||||
if type(data)~="boolean" then error("data: expected bool") end
|
||||
rs.setOutput(side, data)
|
||||
elseif mode=="wa" then
|
||||
if type(data)~="number" then error("data: expected bool") end
|
||||
rs.setAnalogOutput(side, data)
|
||||
elseif mode=="r" then
|
||||
return rs.getInput(side)
|
||||
elseif mode=="ra" then
|
||||
return rs.getAnalogInput(side)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for side, alt in pairs(sides) do
|
||||
local func=newGPIO(side)
|
||||
kernel.gpio[side]=func
|
||||
kernel.gpio[alt]=func
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
firmware for ComputerCraft Tweaked
|
||||
@@ -1,411 +0,0 @@
|
||||
--:Minify:--
|
||||
|
||||
local kernel = ...
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
local peripheral={}
|
||||
|
||||
function peripheral.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
kernel.devfs.data.tty={}
|
||||
local ctrl,alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
if bool then
|
||||
return "T"
|
||||
else
|
||||
return "F"
|
||||
end
|
||||
end
|
||||
|
||||
local function newtty(obj, id, ev)
|
||||
obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
obj.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
obj.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
obj.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
obj.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
obj.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
obj.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
obj.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
obj.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
obj.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
obj.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
obj.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
obj.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
obj.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
local rv=""
|
||||
for i=1, amount or 1 do
|
||||
local event = {ev()}
|
||||
if event[1] then
|
||||
rv=rv..event[1]
|
||||
end
|
||||
end
|
||||
if rv=="" then rv=nil end
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
write(content, obj)
|
||||
end,
|
||||
size=function()
|
||||
local s={obj.getSize()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
clear=function()
|
||||
obj.clear()
|
||||
obj.setCursorPos(1,1)
|
||||
end,
|
||||
gpos=function()
|
||||
local s={obj.getCursorPos()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
spos=function(x,y)
|
||||
return obj.setCursorPos(x,y)
|
||||
end,
|
||||
sfgc=function(c)
|
||||
return obj.setTextColor(colors[c])
|
||||
end,
|
||||
sbgc=function(c)
|
||||
return obj.setBackgroundColor(colors[c])
|
||||
end,
|
||||
gfgc=function()
|
||||
return icolors[obj.getTextColor()]
|
||||
end,
|
||||
gbgc=function()
|
||||
return icolors[obj.getBackgroundColor()]
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
return h
|
||||
elseif mode=="r" then
|
||||
h["write"]=nil
|
||||
return h
|
||||
elseif mode=="w" then
|
||||
h["read"]=nil
|
||||
return h
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local fifo = kernel.newFifo()
|
||||
|
||||
kernel.processes.cctmond = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.computer:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
local ctrlKeyMap = {
|
||||
[apis.keys.a]=1, [apis.keys.b]=2, [apis.keys.c]=3,
|
||||
[apis.keys.d]=4, [apis.keys.e]=5, [apis.keys.f]=6,
|
||||
[apis.keys.g]=7, [apis.keys.h]=8, [apis.keys.i]=9,
|
||||
[apis.keys.j]=10, [apis.keys.k]=11, [apis.keys.l]=12,
|
||||
[apis.keys.m]=13, [apis.keys.n]=14, [apis.keys.o]=15,
|
||||
[apis.keys.p]=16, [apis.keys.q]=17, [apis.keys.r]=18,
|
||||
[apis.keys.s]=19, [apis.keys.t]=20, [apis.keys.u]=21,
|
||||
[apis.keys.v]=22, [apis.keys.w]=23, [apis.keys.x]=24,
|
||||
[apis.keys.y]=25, [apis.keys.z]=26,
|
||||
}
|
||||
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = true
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = true
|
||||
end
|
||||
|
||||
if ctrl then
|
||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||
if ctrlByte then
|
||||
if ctrlByte == 3 then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1)
|
||||
end
|
||||
else
|
||||
fifo.push(string.char(ctrlByte))
|
||||
end
|
||||
end
|
||||
else
|
||||
local specialKeyMap = {
|
||||
[apis.keys.up] = "[A",
|
||||
[apis.keys.down] = "[B",
|
||||
[apis.keys.right] = "[C",
|
||||
[apis.keys.left] = "[D",
|
||||
[apis.keys.home] = "[H",
|
||||
[apis.keys["end"]] = "[F",
|
||||
[apis.keys.pageUp] = "[5~",
|
||||
[apis.keys.pageDown] = "[6~",
|
||||
[apis.keys.delete] = "[3~",
|
||||
}
|
||||
local special = specialKeyMap[charOrKey]
|
||||
if special then fifo.push(special) end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = false
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then fifo.push(charOrKey) end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newtty(apis.term, "1", fifo.pop)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
v.setTextScale(.5)
|
||||
v.write("Initializing...")
|
||||
newtty(v,tostring(i+1),function () end)
|
||||
end
|
||||
@@ -1,26 +0,0 @@
|
||||
local args={...}
|
||||
local kernel=args[1]
|
||||
local driver={}
|
||||
|
||||
driver.name="CCT Term Module"
|
||||
driver.version="0.1.0"
|
||||
driver.type="gpio"
|
||||
driver.description="CCT redstone Module Kernel Module"
|
||||
driver.arch="cct"
|
||||
driver.author="HyperionOS Dev Team"
|
||||
driver.license="MIT"
|
||||
driver.api={}
|
||||
|
||||
function driver.load()
|
||||
-- will
|
||||
end
|
||||
|
||||
function driver.unload()
|
||||
-- Nothing to unload
|
||||
end
|
||||
|
||||
function driver.main()
|
||||
-- Nothing to run
|
||||
end
|
||||
|
||||
-- kernel.drivers.register(driver)
|
||||
@@ -0,0 +1 @@
|
||||
1.3.0
|
||||
@@ -0,0 +1 @@
|
||||
Hyperion
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1 @@
|
||||
firmware for Opencomputers
|
||||
@@ -0,0 +1 @@
|
||||
0.1.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
Spsf
|
||||
@@ -1,287 +0,0 @@
|
||||
--:Minify:--
|
||||
local args = {...}
|
||||
local apis = args[1]
|
||||
local disks = args[2]
|
||||
local arch = args[3]
|
||||
local screen = args[5]
|
||||
local computer = args[6]
|
||||
local ifs = args[7]
|
||||
local kernel = {}
|
||||
kernel.LOG_Text=""
|
||||
kernel.version="HyperionOS V1.2.3"
|
||||
kernel.process = "Kernel"
|
||||
kernel.users={[0]="root",[1]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
kernel.groups = {}
|
||||
kernel.uid = 0
|
||||
kernel.gid = 0
|
||||
kernel.status = "start"
|
||||
kernel.key = {}
|
||||
kernel.cache = {}
|
||||
kernel.cache.preload = {}
|
||||
kernel._G=_G
|
||||
kernel.sleep=sleep
|
||||
|
||||
_G.sleep=nil
|
||||
local windowsExp = false
|
||||
|
||||
function kernel.log(msg, level, c)
|
||||
c=c or 12
|
||||
kernel.LOG_Text = kernel.LOG_Text..string.format("%X",c-1).." "..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||
if kernel.status == "start" then
|
||||
screen:setTextColor(c)
|
||||
screen:print(tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||
elseif kernel.status == "term" then
|
||||
kernel.standbyTask=kernel.currentTask
|
||||
kernel.currentTask=kernel.kernelTask
|
||||
kernel.vfs.devctl(1,"sfgc",c)
|
||||
kernel.vfs.write(1,tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||
kernel.currentTask=kernel.standbyTask
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.PANIC(msg)
|
||||
if kernel.status~="Panic" then
|
||||
kernel.log("PANIC: "..msg, "PANIC")
|
||||
pcall(kernel["saveLog"])
|
||||
kernel.status="Panic"
|
||||
kernel.reason=msg
|
||||
screen:setTextColor(2)
|
||||
screen:setBackgroundColor(16)
|
||||
screen:clear()
|
||||
screen:setCursorPos(1,1)
|
||||
screen:print(kernel.LOG_Text)
|
||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||
screen:print("Press any key to continue...")
|
||||
kernel.exitMain = true
|
||||
end
|
||||
while true do
|
||||
local event={computer:getMachineEvent()}
|
||||
if event[1]=="keyPressed" then
|
||||
break
|
||||
end
|
||||
end
|
||||
computer:reboot()
|
||||
end
|
||||
kernel.panic=kernel.PANIC
|
||||
|
||||
if windowsExp then
|
||||
screen:setTextColor(1)
|
||||
screen:setBackgroundColor(4)
|
||||
screen:clear()
|
||||
local w,h = screen:getSize()
|
||||
screen:setCursorPos(3,5)
|
||||
screen:print(":(")
|
||||
screen:setCursorPos(3,7)
|
||||
screen:print("Your PC ran into a problem and needs to restart. We're just collecting some error")
|
||||
screen:setCursorPos(3,8)
|
||||
screen:print("info, and then we'll restart for you.\n")
|
||||
screen:setCursorPos(3,h-5)
|
||||
screen:print("Stop code: average windows experience")
|
||||
screen:setCursorPos(1,h)
|
||||
screen:print("Press any key to continue... jk reboot it yourself lazy")
|
||||
while true do end
|
||||
end
|
||||
|
||||
kernel.log("Kernel loaded.")
|
||||
kernel.log("Mounting init disks...")
|
||||
disks.refresh()
|
||||
ifs.update(disks)
|
||||
kernel.disks={}
|
||||
for _,v in disks.list() do
|
||||
kernel.disks[v.address] = v
|
||||
end
|
||||
ifs.mount("$", "/")
|
||||
|
||||
local fstab=ifs.readAllText("/boot/fstab")
|
||||
local split = function(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
local c = string.sub(str,i,i)
|
||||
if #rv ~= maxResultCountOrNil and c == delim then
|
||||
table.insert(rv, buf)
|
||||
buf = ""
|
||||
else
|
||||
buf = buf..c
|
||||
end
|
||||
end
|
||||
table.insert(rv, buf)
|
||||
return rv
|
||||
end
|
||||
|
||||
if not ifs.isFile("/boot/boot.cfg") then
|
||||
kernel.log("First boot detected writing boot.cfg", "INFO", 3)
|
||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||
kernel.firstBoot=true
|
||||
end
|
||||
|
||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||
if not initCfgFunc then
|
||||
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local initCfgStatus, config = pcall(initCfgFunc)
|
||||
if not initCfgStatus then
|
||||
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
|
||||
end
|
||||
kernel.config = config
|
||||
|
||||
for i,v in ipairs(split(fstab,"\n")) do
|
||||
if v:sub(1,1)=="U" then
|
||||
local id=""
|
||||
for i=3,#v do
|
||||
if v:sub(i,i)==";" then
|
||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
|
||||
id=v:sub(3,i-1)
|
||||
end
|
||||
end
|
||||
local path=v:sub(#id+4)
|
||||
ifs.mount(id,path)
|
||||
::endline::
|
||||
end
|
||||
end
|
||||
kernel.log("Disks initialized")
|
||||
|
||||
function kernel.saveLog()
|
||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||
end
|
||||
|
||||
function kernel.newFifo()
|
||||
local fifo = {}
|
||||
fifo.push=function(data)
|
||||
table.insert(fifo, data)
|
||||
end
|
||||
fifo.pop=function()
|
||||
return table.remove(fifo,1)
|
||||
end
|
||||
return fifo
|
||||
end
|
||||
|
||||
function kernel.newUUID()
|
||||
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
local uuid = ""
|
||||
for i = 1, #template do
|
||||
local c = template:sub(i,i)
|
||||
if c == "x" then
|
||||
uuid = uuid .. string.format("%x", math.random(0, 15))
|
||||
elseif c == "y" then
|
||||
uuid = uuid .. string.format("%x", math.random(8, 11))
|
||||
else
|
||||
uuid = uuid .. c
|
||||
end
|
||||
end
|
||||
return uuid
|
||||
end
|
||||
|
||||
kernel.syscalls={}
|
||||
local modules={[0]={}}
|
||||
for i=0, 100 do
|
||||
modules[i]={}
|
||||
end
|
||||
|
||||
kernel.log("Gathering modules")
|
||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
local modlist = ifs.list("/lib/modules/"..i)
|
||||
if not modlist then
|
||||
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 8)
|
||||
else
|
||||
for _,v in ipairs(modlist) do
|
||||
local prior=tonumber(v:sub(1,2))
|
||||
if prior then
|
||||
modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.ifs=ifs
|
||||
kernel.apis=apis
|
||||
kernel.computer=computer
|
||||
kernel.arch=arch
|
||||
kernel.initdisks=disks
|
||||
kernel.screen=screen
|
||||
kernel.processes={}
|
||||
kernel.fstab=fstab
|
||||
|
||||
kernel.kernelTask = {
|
||||
name="kernel",
|
||||
status="R",
|
||||
pid=0,
|
||||
tgid=0,
|
||||
uid=0,
|
||||
fd={},
|
||||
exit="",
|
||||
sleep=0,
|
||||
ivs=0,
|
||||
vs=0,
|
||||
children={},
|
||||
syscallReturn={},
|
||||
cwd="/",
|
||||
timeSlice=0,
|
||||
lastTime=0,
|
||||
totalTime=0,
|
||||
numRuns=0
|
||||
}
|
||||
kernel.currentTask = kernel.kernelTask
|
||||
|
||||
function kernel.shutdown()
|
||||
kernel.computer:shutdown()
|
||||
end
|
||||
|
||||
function kernel.reboot()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
|
||||
kernel.syscalls["time"]=function() return kernel.computer:time() end
|
||||
kernel.syscalls["log"]=kernel.log
|
||||
kernel.syscalls["getUptime"]=function() return kernel.computer:clock() end
|
||||
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||
kernel.syscalls["version"]=function() return kernel.version end
|
||||
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
|
||||
kernel.syscalls["arch"]=function() return arch end
|
||||
kernel.syscalls["sysdump"]=function()
|
||||
local rv={}
|
||||
for i,v in pairs(kernel.syscalls) do
|
||||
rv[#rv+1] = i
|
||||
end
|
||||
return rv
|
||||
end
|
||||
kernel.syscalls["reboot"]=function()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
kernel.syscalls["shutdown"]=function()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
|
||||
kernel.log("Running modules")
|
||||
for _,p in ipairs(modules) do
|
||||
for _,v in ipairs(p) do
|
||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 5) end
|
||||
local code=ifs.readAllText(v)
|
||||
if not code then
|
||||
kernel.log("ModuReadErr: "..v, "WARN", 8)
|
||||
goto skip
|
||||
end
|
||||
local func,err=load(code,"@"..v)
|
||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
|
||||
local status, err = xpcall(func,debug.traceback, kernel)
|
||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 5) end
|
||||
::skip::
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Kernel initialized successfully.")
|
||||
kernel.saveLog()
|
||||
kernel.status="running"
|
||||
kernel.main()
|
||||
if kernel.status=="panic" then
|
||||
kernel.panic()
|
||||
end
|
||||
kernel.PANIC("Execution complete")
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,451 @@
|
||||
--:Minify:--
|
||||
local EFI=...
|
||||
--pf
|
||||
EFI.beep(440, 500)
|
||||
local screen=EFI.screenCtl
|
||||
local ifs=EFI.initfs
|
||||
local disks=EFI.disks
|
||||
local arch=EFI.architecture
|
||||
local kernel = {}
|
||||
kernel.LOG_Text=""
|
||||
kernel.version="HyperionOS V1.2.4"
|
||||
kernel.tag="1.2.4"
|
||||
kernel.process = "Kernel"
|
||||
kernel.users={[0]="root",[1000]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
kernel.groups = {}
|
||||
kernel.uid = 0
|
||||
kernel.gid = 0
|
||||
kernel.status = "start"
|
||||
kernel.key = {}
|
||||
kernel.cache = {}
|
||||
kernel.cache.preload = {}
|
||||
kernel.unixSockets={}
|
||||
kernel._G=_G
|
||||
kernel.sleep=sleep
|
||||
|
||||
_G.sleep=nil
|
||||
local windowsExp = false
|
||||
|
||||
function kernel.log(msg, level, c, nopanic)
|
||||
local f=function()
|
||||
c=c or 0x6D6D6D
|
||||
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||
if kernel.status == "start" then
|
||||
screen:setTextColor(c)
|
||||
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||
elseif kernel.status == "term" then
|
||||
kernel.standbyTask=kernel.currentTask
|
||||
kernel.currentTask=kernel.kernelTask
|
||||
local file=kernel.vfs.open("/dev/console", "w")
|
||||
kernel.vfs.devctl(file,"sfgc",c)
|
||||
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||
kernel.vfs.close(file)
|
||||
kernel.currentTask=kernel.standbyTask
|
||||
end
|
||||
end
|
||||
|
||||
local ok,err = xpcall(f,debug.traceback)
|
||||
if not ok and not nopanic then
|
||||
kernel.panic(err)
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.PANIC(msg)
|
||||
if kernel.status~="Panic" then
|
||||
kernel.log("PANIC: "..msg, "PANIC", 0xFF0000)
|
||||
pcall(kernel["saveLog"])
|
||||
kernel.status="Panic"
|
||||
kernel.reason=msg
|
||||
screen:enable()
|
||||
screen:setTextColor(0xFF0000)
|
||||
screen:setBackgroundColor(0x000000)
|
||||
screen:clear()
|
||||
screen:resetCursor()
|
||||
screen:print(kernel.LOG_Text)
|
||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||
screen:print("Press any key to continue...")
|
||||
kernel.exitMain = true
|
||||
end
|
||||
while true do
|
||||
local event={EFI:getMachineEvent()}
|
||||
if event[1]=="keyPressed" then
|
||||
break
|
||||
end
|
||||
end
|
||||
EFI.reboot=true
|
||||
error("KERNEL PANIC")
|
||||
end
|
||||
kernel.panic=kernel.PANIC
|
||||
|
||||
if windowsExp then
|
||||
screen:setTextColor(0xFFFFFF)
|
||||
screen:setBackgroundColor(0x0000FF)
|
||||
screen:clear()
|
||||
screen:resetCursor()
|
||||
screen:print("\n\n\n\n\n :(")
|
||||
screen:print("\n Your PC ran into a problem and needs to restart. We're just collecting some error")
|
||||
screen:print(" info, and then we'll restart for you.\n")
|
||||
screen:print("\n\n\n Stop code: average windows experience")
|
||||
while true do end
|
||||
end
|
||||
|
||||
kernel.log("Kernel loaded.")
|
||||
kernel.log("Mounting init disks...")
|
||||
disks.refresh()
|
||||
ifs.update(disks)
|
||||
kernel.disks={}
|
||||
for _,v in disks.list() do
|
||||
kernel.disks[v.address] = v
|
||||
end
|
||||
ifs.mount("$", "/")
|
||||
|
||||
local fstab=ifs.readAllText("/boot/fstab")
|
||||
local split = function(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
local c = string.sub(str,i,i)
|
||||
if #rv ~= maxResultCountOrNil and c == delim then
|
||||
table.insert(rv, buf)
|
||||
buf = ""
|
||||
else
|
||||
buf = buf..c
|
||||
end
|
||||
end
|
||||
table.insert(rv, buf)
|
||||
return rv
|
||||
end
|
||||
|
||||
if not ifs.isFile("/boot/boot.cfg") then
|
||||
kernel.log("First boot detected writing boot.cfg", "INFO", 0x00FF00)
|
||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||
kernel.firstBoot=true
|
||||
end
|
||||
|
||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||
if not initCfgFunc then
|
||||
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local initCfgStatus, config = pcall(initCfgFunc)
|
||||
if not initCfgStatus then
|
||||
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
|
||||
end
|
||||
kernel.config = config
|
||||
|
||||
local skip=false
|
||||
for i,v in ipairs(split(fstab,"\n")) do
|
||||
if v:sub(1,1)=="U" then
|
||||
local id=""
|
||||
for i=3,#v do
|
||||
if v:sub(i,i)==";" then
|
||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 0xFF8800) skip = true break end
|
||||
id=v:sub(3,i-1)
|
||||
end
|
||||
end
|
||||
if not skip then
|
||||
local path=v:sub(#id+4)
|
||||
ifs.mount(id,path)
|
||||
else
|
||||
skip=false
|
||||
end
|
||||
end
|
||||
end
|
||||
kernel.log("Disks initialized")
|
||||
|
||||
function kernel.saveLog()
|
||||
if kernel.status=="running" then
|
||||
local file = kernel.vfs.open("/var/log/syslog.log", "w")
|
||||
kernel.vfs.write(file, kernel.LOG_Text)
|
||||
kernel.vfs.close(file)
|
||||
else
|
||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.newFifo()
|
||||
local fifo = {}
|
||||
fifo.push=function(data)
|
||||
table.insert(fifo, data)
|
||||
end
|
||||
fifo.pop=function()
|
||||
return table.remove(fifo,1)
|
||||
end
|
||||
return fifo
|
||||
end
|
||||
|
||||
function kernel.newUUID()
|
||||
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
local uuid = ""
|
||||
for i = 1, #template do
|
||||
local c = template:sub(i,i)
|
||||
if c == "x" then
|
||||
uuid = uuid .. string.format("%x", math.random(0, 15))
|
||||
elseif c == "y" then
|
||||
uuid = uuid .. string.format("%x", math.random(8, 11))
|
||||
else
|
||||
uuid = uuid .. c
|
||||
end
|
||||
end
|
||||
return uuid
|
||||
end
|
||||
|
||||
function kernel.sfile(str, writeable)
|
||||
local buf = {str or ""}
|
||||
local pos = 1
|
||||
local closed = false
|
||||
|
||||
local function content()
|
||||
return table.concat(buf)
|
||||
end
|
||||
|
||||
local function set_content(s)
|
||||
buf = {s}
|
||||
end
|
||||
|
||||
local function flush()
|
||||
str=content()
|
||||
end
|
||||
|
||||
local file = {}
|
||||
|
||||
function file.read(n)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
if not n then
|
||||
local out = s:sub(pos)
|
||||
pos = len + 1
|
||||
return out
|
||||
end
|
||||
|
||||
local out = s:sub(pos, pos + n - 1)
|
||||
pos = pos + #out
|
||||
return out
|
||||
end
|
||||
|
||||
if writeable then
|
||||
function file.write(data)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local before = s:sub(1, pos - 1)
|
||||
local after = s:sub(pos + #data)
|
||||
|
||||
set_content(before .. data .. after)
|
||||
pos = pos + #data
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function file.seek(whence, offset)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
whence = whence or "cur"
|
||||
offset = offset or 0
|
||||
|
||||
if whence == "set" then
|
||||
pos = offset + 1
|
||||
elseif whence == "cur" then
|
||||
pos = pos + offset
|
||||
elseif whence == "end" then
|
||||
pos = len + offset + 1
|
||||
else
|
||||
error("invalid whence")
|
||||
end
|
||||
|
||||
if pos < 1 then pos = 1 end
|
||||
if pos > len + 1 then pos = len + 1 end
|
||||
|
||||
return pos - 1
|
||||
end
|
||||
|
||||
function file.close()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
closed = true
|
||||
end
|
||||
|
||||
function file.flush()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
end
|
||||
|
||||
function file.content()
|
||||
return str
|
||||
end
|
||||
|
||||
return file
|
||||
end
|
||||
|
||||
kernel.syscalls={}
|
||||
local modules={[0]={}}
|
||||
for i=0, 100 do
|
||||
modules[i]={}
|
||||
end
|
||||
|
||||
kernel.log("Gathering modules")
|
||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
local modlist = ifs.list("/lib/modules/"..i)
|
||||
if not modlist then
|
||||
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 0xFF8800)
|
||||
else
|
||||
for _,v in ipairs(modlist) do
|
||||
local prior=tonumber(v:sub(1,2))
|
||||
if prior then
|
||||
modules[prior+1][#modules[prior+1]+1]=i.."/"..v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.ifs=ifs
|
||||
--pf
|
||||
kernel.apis=EFI.firmware
|
||||
--pf
|
||||
kernel.EFI=EFI
|
||||
kernel.arch=arch
|
||||
kernel.initdisks=disks
|
||||
kernel.screen=screen
|
||||
kernel.processes={}
|
||||
kernel.fstab=fstab
|
||||
kernel.denied={}
|
||||
kernel.loadingModule="kernel"
|
||||
|
||||
kernel.kernelTask = {
|
||||
name="kernel",
|
||||
status="R",
|
||||
pid=0,
|
||||
tgid=0,
|
||||
uid=0,
|
||||
fd={},
|
||||
exit="",
|
||||
sleep=0,
|
||||
ivs=0,
|
||||
vs=0,
|
||||
children={},
|
||||
syscallReturn={},
|
||||
cwd="/",
|
||||
timeSlice=0,
|
||||
lastTime=0,
|
||||
totalTime=0,
|
||||
numRuns=0
|
||||
}
|
||||
kernel.currentTask = kernel.kernelTask
|
||||
|
||||
function kernel.shutdown()
|
||||
kernel.exitMain=true
|
||||
kernel.status="shutdown"
|
||||
end
|
||||
|
||||
function kernel.reboot()
|
||||
kernel.exitMain=true
|
||||
kernel.status="reboot"
|
||||
end
|
||||
|
||||
function kernel.halt()
|
||||
kernel.exitMain=true
|
||||
kernel.status="halt"
|
||||
end
|
||||
|
||||
function kernel.asyncReturn(...)
|
||||
kernel.currentTask.syscallReturn = {...}
|
||||
end
|
||||
|
||||
function kernel.deny(moduleid)
|
||||
kernel.denied[moduleid]=true
|
||||
if kernel.config.showModLoad then kernel.log("Module "..kernel.loadingModule.." denied "..moduleid, "DBUG", 0xFF0000) end
|
||||
end
|
||||
|
||||
kernel.syscalls["time"]=function() return kernel.EFI:getEpochMs() end
|
||||
kernel.syscalls["date"]=function() return kernel.EFI:date() end
|
||||
kernel.syscalls["log"]=kernel.log
|
||||
kernel.syscalls["tag"]=function() return kernel.tag end
|
||||
kernel.syscalls["getUptime"]=function() return kernel.EFI:getUptime() end
|
||||
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||
kernel.syscalls["version"]=function() return kernel.version end
|
||||
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
|
||||
kernel.syscalls["arch"]=function() return arch end
|
||||
kernel.syscalls["sysdump"]=function()
|
||||
local rv={}
|
||||
for i,v in pairs(kernel.syscalls) do
|
||||
rv[#rv+1] = i
|
||||
end
|
||||
return rv
|
||||
end
|
||||
kernel.syscalls["reboot"]=function()
|
||||
if kernel.uid==0 or kernel.groups.wheel then
|
||||
kernel.reboot()
|
||||
end
|
||||
end
|
||||
kernel.syscalls["shutdown"]=function()
|
||||
if kernel.uid==0 or kernel.groups.wheel then
|
||||
kernel.shutdown()
|
||||
end
|
||||
end
|
||||
kernel.syscalls["halt"]=function()
|
||||
if kernel.uid==0 or kernel.groups.wheel then
|
||||
kernel.halt()
|
||||
end
|
||||
end
|
||||
kernel.syscalls["saveLog"]=function()
|
||||
if kernel.uid==0 or kernel.groups.wheel then
|
||||
kernel.saveLog()
|
||||
end
|
||||
end
|
||||
|
||||
kernel.saveLog()
|
||||
kernel.log("Running modules")
|
||||
for _,p in ipairs(modules) do
|
||||
for _,v in ipairs(p) do
|
||||
kernel.loadingModule=v
|
||||
if not kernel.denied[v] then
|
||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 0x00FFFF) end
|
||||
local code=ifs.readAllText("/lib/modules/"..v)
|
||||
if not code then
|
||||
kernel.panic("Failed to read module "..v)
|
||||
end
|
||||
local func,err=load(code,"@"..v)
|
||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end
|
||||
local status, err = xpcall(func,debug.traceback, kernel)
|
||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
||||
if kernel.config.moreLogsaves then kernel.saveLog() end
|
||||
else
|
||||
if kernel.config.showModLoad then kernel.log("Denied module "..v, "DBUG", 0xFF0000) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Kernel initialized successfully.")
|
||||
kernel.saveLog()
|
||||
kernel.status="running"
|
||||
kernel.loadingModule=nil
|
||||
screen:disable()
|
||||
local ok,err = xpcall(kernel.main, debug.traceback)
|
||||
if not ok then
|
||||
kernel.panic(err)
|
||||
end
|
||||
if kernel.status=="panic" then
|
||||
kernel.panic(kernel.reason)
|
||||
end
|
||||
if kernel.status=="reboot" then
|
||||
EFI.reboot=true
|
||||
return true
|
||||
elseif kernel.status=="halt" then
|
||||
kernel.log("System halted.")
|
||||
kernel.saveLog()
|
||||
while true do end
|
||||
end
|
||||
@@ -7,5 +7,5 @@ return {
|
||||
initPath = "/sbin/init",
|
||||
maxOpenFiles = 128,
|
||||
maxFilesPerTask = 16,
|
||||
preempt=true
|
||||
preempt = true,
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+18
@@ -23,6 +23,7 @@ function string.split(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
if not str then return false end
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
|
||||
if str == "" then return {} end
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
@@ -229,6 +230,23 @@ function toHex(num)
|
||||
return string.format("%X", num)
|
||||
end
|
||||
|
||||
local st={
|
||||
push=function(self,...) table.insert(self.contents,{...}) end,
|
||||
pop=function(self) return table.unpack(table.remove(self.contents)) end,
|
||||
}
|
||||
local q={
|
||||
push=function(self,...) table.insert(self.contents,{...}) end,
|
||||
pop=function(self) return table.unpack(table.remove(self.contents,1)) end,
|
||||
}
|
||||
|
||||
function stack()
|
||||
return setmetatable({contents={}}, {__index=st})
|
||||
end
|
||||
|
||||
function queue()
|
||||
return setmetatable({contents={}}, {__index=q})
|
||||
end
|
||||
|
||||
local function makeSyscallProxy()
|
||||
local backing = {}
|
||||
return setmetatable(backing, {
|
||||
+184
-32
@@ -124,11 +124,13 @@ end
|
||||
|
||||
local function validateComponent(comp)
|
||||
local lower = comp:lower()
|
||||
if not lower:match(SAFE_COMPONENT_PATTERN) then
|
||||
if not comp:match(SAFE_COMPONENT_PATTERN) then
|
||||
error("EINVAL: illegal characters in path component: " .. comp, 3)
|
||||
end
|
||||
if lower == ".meta" then
|
||||
error("EINVAL: reserved path component: .meta", 3)
|
||||
elseif lower:sub(#lower) == "." then
|
||||
error("Cannot have empty name extention: " .. comp, 3)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -274,7 +276,7 @@ local function namei(path, noFollow, symDepth)
|
||||
|
||||
else
|
||||
validateComponent(comp)
|
||||
local lname = comp:lower()
|
||||
local lname = comp
|
||||
|
||||
local curPath = "/" .. table.concat(stack, "/")
|
||||
|
||||
@@ -372,7 +374,7 @@ local function normalizePath(path)
|
||||
table.remove(stack)
|
||||
end
|
||||
else
|
||||
table.insert(stack, comp:lower())
|
||||
table.insert(stack, comp)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -397,6 +399,10 @@ end
|
||||
local function getFileMeta(path, noFollow)
|
||||
local real = namei(path, noFollow)
|
||||
|
||||
if kernel.unixSockets[real] then
|
||||
return kernel.unixSockets[real].meta
|
||||
end
|
||||
|
||||
if real == "/" then
|
||||
return { etype = 0x00, owner = 0, group = 0, perms = 62, cmeta = "" }
|
||||
end
|
||||
@@ -499,7 +505,7 @@ local function checkperms(meta, mode)
|
||||
local bitmap = {
|
||||
r = {owner = 5, group = 3, everyone = 1},
|
||||
w = {owner = 4, group = 2, everyone = 0},
|
||||
a = {owner = 4, group = 2, everyone = 0},
|
||||
a = {owner = 4, group = 2, everyone = 0}
|
||||
}
|
||||
local m = bitmap[mode]
|
||||
if not m then error("EINVAL") end
|
||||
@@ -536,6 +542,7 @@ local function allocFD(task)
|
||||
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
||||
return fd
|
||||
end
|
||||
|
||||
local function checkSystemLimit()
|
||||
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
||||
end
|
||||
@@ -544,32 +551,93 @@ local function newFileObj(handle, mode, path, meta, ftype)
|
||||
end
|
||||
|
||||
function vfs.newfd(fdobj)
|
||||
checkSystemLimit(); total = total + 1
|
||||
local fd = allocFD(kernel.currentTask)
|
||||
kernel.currentTask.fd[fd] = fdobj
|
||||
return fd
|
||||
end
|
||||
|
||||
function vfs.mount(target, diskOrId)
|
||||
function vfs.mount(target, diskOrId, bind)
|
||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||
if _euid ~= 0 then error("EPERM") end
|
||||
if not target then error("EINVAL") end
|
||||
target = normalizeMountPoint(target)
|
||||
if not vfs.exists(target) then vfs.mkdir(target) end
|
||||
if vfs.type(target) ~= "directory" then error("EINVAL") end
|
||||
|
||||
local drive, path = resolvePath(target)
|
||||
if not drive:directoryExists(path) then
|
||||
drive:makeDirectory(path)
|
||||
end
|
||||
if drive:type(path) ~= "directory" then
|
||||
error("EINVAL")
|
||||
end
|
||||
local disk, id
|
||||
if type(diskOrId) == "string" then
|
||||
disk = kernel.disks[diskOrId]
|
||||
if not disk then error("ENODEV") end
|
||||
checkDisk(disk); id = diskOrId
|
||||
elseif type(diskOrId) == "table" then
|
||||
checkDisk(diskOrId); disk = diskOrId
|
||||
id = disk.address; vfs.disks[id] = disk
|
||||
else error("EINVAL") end
|
||||
|
||||
-- bind mount
|
||||
if bind then
|
||||
local src = normalizeMountPoint(diskOrId)
|
||||
local srcDrive = resolvePath(src)
|
||||
if not srcDrive then error("ENOENT") end
|
||||
id = "bind:" .. src
|
||||
disk = {
|
||||
address = id,
|
||||
isBind = true,
|
||||
source = srcDrive,
|
||||
exists = function(_, p)
|
||||
return srcDrive:exists(p)
|
||||
end,
|
||||
type = function(_, p)
|
||||
return srcDrive:type(p)
|
||||
end,
|
||||
list = function(_, p)
|
||||
return srcDrive:list(p)
|
||||
end,
|
||||
open = function(_, ...)
|
||||
return srcDrive:open(...)
|
||||
end,
|
||||
remove = function(_, p)
|
||||
return srcDrive:remove(p)
|
||||
end,
|
||||
makeDirectory = function(_, p)
|
||||
return srcDrive:makeDirectory(p)
|
||||
end,
|
||||
rename = function(_, a, b)
|
||||
return srcDrive:rename(a, b)
|
||||
end,
|
||||
size = function(_, p)
|
||||
return srcDrive:size(p)
|
||||
end,
|
||||
lastModified = function(_, p)
|
||||
return srcDrive:lastModified(p)
|
||||
end,
|
||||
isReadOnly = function()
|
||||
return srcDrive:isReadOnly()
|
||||
end,
|
||||
spaceTotal = function()
|
||||
return srcDrive:spaceTotal()
|
||||
end,
|
||||
spaceUsed = function()
|
||||
return srcDrive:spaceUsed()
|
||||
end
|
||||
}
|
||||
vfs.disks[id] = disk
|
||||
else
|
||||
if type(diskOrId) == "string" then
|
||||
disk = vfs.disks[diskOrId]
|
||||
if not disk then error("ENODEV") end
|
||||
checkDisk(disk)
|
||||
id = diskOrId
|
||||
elseif type(diskOrId) == "table" then
|
||||
checkDisk(diskOrId)
|
||||
disk = diskOrId
|
||||
id = disk.address
|
||||
vfs.disks[id] = disk
|
||||
else
|
||||
error("EINVAL")
|
||||
end
|
||||
end
|
||||
if vfs.mounts[id] then error("EBUSY") end
|
||||
for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
|
||||
for _, mp in pairs(vfs.mounts) do
|
||||
if mp == target then
|
||||
error("EBUSY")
|
||||
end
|
||||
end
|
||||
vfs.mounts[id] = target
|
||||
return true
|
||||
end
|
||||
@@ -582,7 +650,11 @@ function vfs.umount(target)
|
||||
for id, mp in pairs(vfs.mounts) do
|
||||
if mp == target then
|
||||
if id == "$" then error("EBUSY") end
|
||||
vfs.mounts[id] = nil; return true
|
||||
vfs.mounts[id] = nil
|
||||
if vfs.disks[id] and vfs.disks[id].isBind then
|
||||
vfs.disks[id] = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
error("EINVAL")
|
||||
@@ -594,6 +666,21 @@ function vfs.open(path, mode)
|
||||
local fd = allocFD(task)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if not disk then error("NODISK") end
|
||||
if (mode=="w" or mode=="a") and disk:isReadOnly() then error("ERDONLY") end
|
||||
|
||||
if kernel.unixSockets[namei(path)] then
|
||||
local meta = kernel.unixSockets[namei(path)].meta
|
||||
if kernel.uid~=0 or kernel.uid~=meta.owner then
|
||||
local groups = (task and task.groups) or kernel.groups or {}
|
||||
local access=false
|
||||
for _, gid in ipairs(groups) do
|
||||
if gid == meta.group then access=true end
|
||||
end
|
||||
if not access then error("EACCES") end
|
||||
end
|
||||
task[fd]=kernel.unixSockets[namei(path)]
|
||||
return fd
|
||||
end
|
||||
|
||||
local meta = getFileMeta(path)
|
||||
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
||||
@@ -603,7 +690,9 @@ function vfs.open(path, mode)
|
||||
local handle
|
||||
if disk:type(diskPath) ~= "directory" then
|
||||
handle = disk:open(diskPath, mode)
|
||||
if type(handle) ~= "table" then error("ENFILE") end
|
||||
if type(handle, true) ~= "table" then
|
||||
error("ENFILE")
|
||||
end
|
||||
end
|
||||
|
||||
if isNew then
|
||||
@@ -695,10 +784,17 @@ function vfs.sendfile(outfd, infd, count)
|
||||
end
|
||||
|
||||
function vfs.stat(path)
|
||||
local attrs
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
local ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||
if meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local ok
|
||||
ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -713,15 +809,15 @@ end
|
||||
|
||||
function vfs.lstat(path)
|
||||
local meta = getFileMeta(path, true)
|
||||
|
||||
local attrs
|
||||
if meta.etype == 0x01 then
|
||||
if meta.etype == 0x01 or meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(path, true)
|
||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -738,8 +834,15 @@ end
|
||||
function vfs.fstat(fd)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
local disk, diskPath = resolvePath(file.path)
|
||||
local attrs = disk:attributes(diskPath)
|
||||
local attrs
|
||||
if file.meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(file.path, true)
|
||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -768,6 +871,14 @@ function vfs.listdir(path)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(kernel.unixSockets) do
|
||||
local p=normalizePath(path)
|
||||
if k:match("^(.*)/[^/]+$")==p then
|
||||
seen[v.name]=true
|
||||
table.insert(out, v.name)
|
||||
end
|
||||
end
|
||||
|
||||
local mp
|
||||
if diskPath == "/" then
|
||||
mp = ".meta"
|
||||
@@ -796,6 +907,7 @@ function vfs.mkdir(path)
|
||||
local parentMeta = getFileMeta(parent)
|
||||
checkperms(parentMeta, "w")
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
disk:makeDirectory(diskPath)
|
||||
local task = kernel.currentTask
|
||||
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||
@@ -817,8 +929,13 @@ function vfs.remove(path)
|
||||
|
||||
local meta = getFileMeta(path, true)
|
||||
|
||||
if kernel.unixSockets and kernel.unixSockets[path] then
|
||||
kernel.unixSockets[path] = nil
|
||||
if kernel.unixSockets[namei(path)] then
|
||||
if kernel.uid ~= 0 then
|
||||
if kernel.unixSockets[namei(path)].meta.owner~=kernel.uid then
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
kernel.unixSockets[namei(path)] = nil
|
||||
end
|
||||
|
||||
if meta.etype == 0x01 then
|
||||
@@ -827,6 +944,7 @@ function vfs.remove(path)
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
local disk, parentDiskPath = resolveMount(parent)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local mp
|
||||
if parentDiskPath == "/" then mp = ".meta"
|
||||
else mp = parentDiskPath:gsub("^/+", "") .. "/.meta" end
|
||||
@@ -843,6 +961,7 @@ function vfs.remove(path)
|
||||
if f2.close then f2.close() end
|
||||
else
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
disk:remove(diskPath)
|
||||
end
|
||||
end
|
||||
@@ -851,6 +970,8 @@ function vfs.symlink(target, linkPath)
|
||||
if type(target) ~= "string" or type(linkPath) ~= "string" then error("EINVAL") end
|
||||
local norm = normalizePath(linkPath)
|
||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||
local disk = resolveMount(linkPath)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
if not name then error("EINVAL") end
|
||||
@@ -880,7 +1001,13 @@ function vfs.readlink(path)
|
||||
end
|
||||
|
||||
function vfs.access(path, mode)
|
||||
local meta = getFileMeta(path)
|
||||
local meta
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
meta = kernel.unixSockets[normalizePath(path)].meta
|
||||
else
|
||||
meta = getFileMeta(path)
|
||||
end
|
||||
|
||||
for i = 1, #mode do
|
||||
checkperms(meta, mode:sub(i,i))
|
||||
end
|
||||
@@ -891,6 +1018,8 @@ local function updateMeta(path, fn, noFollow)
|
||||
local real = namei(path, noFollow)
|
||||
local norm = real
|
||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
if not name then error("EINVAL") end
|
||||
@@ -917,6 +1046,9 @@ local function updateMeta(path, fn, noFollow)
|
||||
end
|
||||
|
||||
function vfs.chmod(path, perms)
|
||||
if kernel.unixSockets[namei(path)] then error("EINVAL") end
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local meta = getFileMeta(path)
|
||||
local euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||
if euid ~= 0 and euid ~= meta.owner then error("EACCES") end
|
||||
@@ -926,10 +1058,14 @@ end
|
||||
function vfs.fchmod(fd, perms)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.meta.etype==0x02 then error("EINVAL") end
|
||||
vfs.chmod(file.path, perms)
|
||||
end
|
||||
|
||||
function vfs.chown(path, uid, gid)
|
||||
if kernel.unixSockets[namei(path)] then error("EINVAL") end
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||
if _euid ~= 0 then error("EPERM") end
|
||||
updateMeta(path, function(e) e.owner = uid; e.group = gid end)
|
||||
@@ -938,20 +1074,29 @@ end
|
||||
function vfs.fchown(fd, uid, gid)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.meta.etype==0x02 then error("EINVAL") end
|
||||
vfs.chown(file.path, uid, gid)
|
||||
end
|
||||
|
||||
function vfs.exists(path)
|
||||
if kernel.unixSockets[namei(path)] then return true end
|
||||
local meta = getFileMeta(path, true)
|
||||
if meta.etype == 0x01 then return true end
|
||||
if meta.etype == 0x01 or meta.etype == 0x02 then return true end
|
||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||
if not ok then return false end
|
||||
return disk:fileExists(diskPath)
|
||||
if disk:type(diskPath) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function vfs.type(path)
|
||||
local meta = getFileMeta(path, true)
|
||||
if meta.etype == 0x01 then return "symlink" end
|
||||
if kernel.unixSockets[namei(path)] then
|
||||
return "socket"
|
||||
end
|
||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||
if not ok then return nil end
|
||||
return disk:type(diskPath)
|
||||
@@ -1004,6 +1149,12 @@ function vfs.devctl(fd, method, ...)
|
||||
return kernel.currentTask.fd[fd].handle[method](...)
|
||||
end
|
||||
|
||||
function vfs.devlst(fd)
|
||||
if not kernel.currentTask.fd[fd] then error("EBADF") end
|
||||
if not kernel.currentTask.fd[fd] then error("EINVAL") end
|
||||
return table.keys(kernel.currentTask.fd[fd].handle)
|
||||
end
|
||||
|
||||
vfs.resolveMount = resolveMount
|
||||
|
||||
local sys = kernel.syscalls
|
||||
@@ -1036,6 +1187,7 @@ sys["chroot"] = vfs.chroot
|
||||
sys["dup"] = vfs.dup
|
||||
sys["dup2"] = vfs.dup2
|
||||
sys["devctl"] = vfs.devctl
|
||||
sys["devlst"] = vfs.devlst
|
||||
sys["symlink"] = vfs.symlink
|
||||
sys["readlink"] = vfs.readlink
|
||||
sys["access"] = vfs.access
|
||||
@@ -0,0 +1,47 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local cache = {}
|
||||
kernel.searchpaths = {
|
||||
"?", "?.lua", "/lib/?", "/lib/?.lua", "/usr/lib/?", "/usr/lib/?.lua",
|
||||
"/usr/local/lib/?", "/usr/local/lib/?.lua"
|
||||
}
|
||||
kernel.reqcache = cache
|
||||
|
||||
local function require(module, ...)
|
||||
if cache[module] then return cache[module].ret end
|
||||
local args = {...}
|
||||
for _, path in ipairs(kernel.searchpaths) do
|
||||
local filepath = path:gsub("?", module)
|
||||
if kernel.vfs.exists(filepath) then
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
filepath = filepath .. "/init.lua"
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
error("Module not found: "..module)
|
||||
end
|
||||
end
|
||||
local fd = kernel.vfs.open(filepath, "r")
|
||||
local chunks = {}
|
||||
while true do
|
||||
local chunk = kernel.vfs.read(fd, 4096)
|
||||
if not chunk or chunk == "" then break end
|
||||
chunks[#chunks + 1] = chunk
|
||||
end
|
||||
kernel.vfs.close(fd)
|
||||
local data = table.concat(chunks)
|
||||
local func, err = load(data, "@"..module, "t", kernel._U)
|
||||
if not func then
|
||||
error("Error loading module "..module..": "..tostring(err))
|
||||
end
|
||||
local ok, ret = xpcall(func, debug.traceback, table.unpack(args))
|
||||
if not ok then
|
||||
error("Error running module "..module..": "..tostring(ret))
|
||||
end
|
||||
cache[module] = {ret = ret, expires = kernel.EFI:getEpochMs() + 120000}
|
||||
return ret
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
error("Module not found: "..module)
|
||||
end
|
||||
|
||||
_G.require = function(...) return require(...) end
|
||||
@@ -0,0 +1,309 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "devfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("EACCES") end
|
||||
proxy.remove = function() error("EACCES") end
|
||||
proxy.setLabel = function() error("EACCES") end
|
||||
proxy.getLabel = function() return "devfs" end
|
||||
proxy.attributes = function(path) return {
|
||||
size = 0,
|
||||
modified = 0,
|
||||
created = 0
|
||||
} end
|
||||
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("open", mode)
|
||||
end
|
||||
error("ENFILE")
|
||||
end
|
||||
|
||||
function proxy:type(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return "directory"
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("type", mode)
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return "directory"
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return table.keys(data)
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENOENT") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return table.keys(step[steps[#steps]])
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
local ok = pcall(function()
|
||||
return self:type(path)
|
||||
end)
|
||||
return ok
|
||||
end
|
||||
|
||||
function data.random(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(math.random(0, 255))
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.null(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount) end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.zero(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(0)
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function buildMeta(entries, opts)
|
||||
opts = opts or {}
|
||||
local uid = opts.uid or 0
|
||||
local gid = opts.gid or 0
|
||||
local perms = opts.perms or 0x3F -- default read/write for owner/group/world
|
||||
|
||||
local chunks = {}
|
||||
table.insert(chunks, string.char(0x02)) -- version header
|
||||
|
||||
for path, target in pairs(entries) do
|
||||
local name = path
|
||||
local nameLen = #name
|
||||
if nameLen > 255 then
|
||||
error("Filename too long (>255 bytes): "..name)
|
||||
end
|
||||
|
||||
-- Determine entry type: 0x01 = symlink if target ~= nil and target ~= ""
|
||||
local entryType = 0x00
|
||||
local cmeta = ""
|
||||
if target and target ~= "" then
|
||||
entryType = 0x01
|
||||
cmeta = target
|
||||
end
|
||||
local cmetaLen = #cmeta
|
||||
if cmetaLen > 255 then
|
||||
error("cmeta too long (>255 bytes) for "..name)
|
||||
end
|
||||
|
||||
-- Build entry as bytes
|
||||
table.insert(chunks, string.char(nameLen)) -- name length
|
||||
table.insert(chunks, name) -- name
|
||||
table.insert(chunks, string.char(entryType)) -- entry type
|
||||
table.insert(chunks, string.char(uid % 256, math.floor(uid/256) % 256)) -- uid
|
||||
table.insert(chunks, string.char(gid % 256, math.floor(gid/256) % 256)) -- gid
|
||||
table.insert(chunks, string.char(perms % 256, math.floor(perms/256) % 256)) -- perms
|
||||
table.insert(chunks, string.char(cmetaLen)) -- cmeta length
|
||||
if cmetaLen > 0 then
|
||||
table.insert(chunks, cmeta)
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(chunks)
|
||||
end
|
||||
|
||||
local function simpleFile(r,w)
|
||||
return function(op, mode)
|
||||
if op=="type" then
|
||||
return "file"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=r
|
||||
}
|
||||
elseif mode=="w" then
|
||||
return {
|
||||
write=w
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function strFile(str)
|
||||
local dat=tostring(str)
|
||||
local pos=1
|
||||
return simpleFile(function(amount)
|
||||
pos=pos+amount
|
||||
return dat:sub(pos-amount, pos)
|
||||
end,function() error("EACCES") end)
|
||||
end
|
||||
|
||||
data[".meta"]=strFile(buildMeta({
|
||||
stdin="/proc/self/fd/0",
|
||||
stdout="/proc/self/fd/1",
|
||||
stderr="/proc/self/2",
|
||||
fd="/proc/self/fd",
|
||||
log="/var/log/syslog.log"
|
||||
}))
|
||||
|
||||
if kernel.EFI.getEEPROM then
|
||||
function data.eeprom(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
if mode=="r" then
|
||||
local ptr,eeprom=1,kernel.EFI:getEEPROM()
|
||||
return {
|
||||
read=function(amount)
|
||||
ptr=ptr+amount
|
||||
return eeprom:sub(ptr-amount, ptr)
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
if firstwrite then
|
||||
kernel.EFI:setEEPROM(data)
|
||||
else
|
||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||
end
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||
end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI.getNvram then
|
||||
function data.nvram(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
if mode=="r" then
|
||||
local ptr,nvram=1,kernel.EFI:getNvram()
|
||||
return {
|
||||
read=function(amount)
|
||||
ptr=ptr+amount
|
||||
return nvram:sub(ptr-amount, ptr)
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
if firstwrite then
|
||||
kernel.EFI:setNvram(data)
|
||||
else
|
||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||
end
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||
end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data["disk"]={["by-id"]={}, ["by-path"]={}, ["by-label"]={}}
|
||||
-- disks
|
||||
for i,v in pairs(kernel.vfs.mounts) do
|
||||
|
||||
end
|
||||
|
||||
data["raw"]={["by-type"]={}}
|
||||
data["gfx"]={}
|
||||
data["input"]={}
|
||||
data["tty"]={}
|
||||
kernel.devfs={}
|
||||
kernel.devfs.data=data
|
||||
kernel.devfs.proxy=proxy
|
||||
kernel.disks["devfs0000"]=proxy
|
||||
+4
-3
@@ -6,7 +6,7 @@ local data = {}
|
||||
|
||||
proxy.address = "procfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
proxy.isReadOnly = function() return true end
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("EACCES") end
|
||||
@@ -114,7 +114,8 @@ local function newtaskproxy(task)
|
||||
},
|
||||
children={
|
||||
[".meta"]=strFile(buildMeta(children))
|
||||
}
|
||||
},
|
||||
pid=strFile(task.pid)
|
||||
}
|
||||
end
|
||||
|
||||
@@ -258,7 +259,7 @@ function proxy:fileExists(path)
|
||||
return ok
|
||||
end
|
||||
|
||||
data.uptime=simpleFile(function()return tostring(kernel.computer:getUptime())end,function()error("EACCES")end)
|
||||
data.uptime=simpleFile(function()return tostring(kernel.EFI:getUptime())end,function()error("EACCES")end)
|
||||
kernel.procfs={}
|
||||
kernel.procfs.data=data
|
||||
kernel.procfs.proxy=proxy
|
||||
@@ -0,0 +1,141 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
kernel.vfs.remove("/tmp")
|
||||
kernel.vfs.mkdir("/tmp")
|
||||
if not kernel.config.tmpToDisk then
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "tmpfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
|
||||
proxy.makeDirectory = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
if not step[steps[i]] then
|
||||
step[steps[i]] = {}
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
end
|
||||
|
||||
proxy.remove = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
step[steps[#steps]] = nil
|
||||
end
|
||||
|
||||
proxy.setLabel = function(_, label) end
|
||||
proxy.getLabel = function() return "tmpfs" end
|
||||
|
||||
proxy.attributes = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
return {
|
||||
size = type(step) == "string" and #step or 0,
|
||||
modified = 0,
|
||||
created = 0,
|
||||
}
|
||||
end
|
||||
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
if not step[steps[i]] then
|
||||
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
local filename = steps[#steps]
|
||||
|
||||
if mode == "r" then
|
||||
if type(step[filename]) ~= "string" then error("ENOENT") end
|
||||
local content = step[filename]
|
||||
local pos = 1
|
||||
return {
|
||||
read = function(amount)
|
||||
amount = amount or #content
|
||||
local chunk = content:sub(pos, pos+amount-1)
|
||||
pos = pos + #chunk
|
||||
return chunk
|
||||
end,
|
||||
close = function() end,
|
||||
}
|
||||
elseif mode == "w" then
|
||||
step[filename] = ""
|
||||
local buf = {}
|
||||
return {
|
||||
write = function(str)
|
||||
buf[#buf + 1] = str
|
||||
end,
|
||||
close = function()
|
||||
step[filename] = table.concat(buf)
|
||||
end,
|
||||
}
|
||||
elseif mode == "a" then
|
||||
if type(step[filename]) ~= "string" then step[filename] = "" end
|
||||
return {
|
||||
write = function(str)
|
||||
step[filename] = step[filename] .. str
|
||||
end,
|
||||
close = function() end,
|
||||
}
|
||||
else
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
|
||||
function proxy:type(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then return "directory" end
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then return false end
|
||||
end
|
||||
if type(step) == "table" then return "directory" end
|
||||
if type(step) == "string" then return "file" end
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
if type(step) ~= "table" then error("ENOTDIR") end
|
||||
local keys = {}
|
||||
for k,_ in pairs(step) do table.insert(keys, k) end
|
||||
return keys
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
local t = self:type(path)
|
||||
return t == "file" or t == "directory"
|
||||
end
|
||||
|
||||
kernel.disks["tmpfs0000"] = proxy
|
||||
else
|
||||
kernel.log("tmpToDisk enabled, skipping tmpfs module")
|
||||
kernel.log("tmpfs0000 will passthrough to /tmp on the disk")
|
||||
end
|
||||
File renamed without changes.
+3
-2
@@ -21,14 +21,15 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
||||
end
|
||||
|
||||
if not semicolon_pos or semicolon_pos == 3 then
|
||||
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 8)
|
||||
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 0xFF8800)
|
||||
else
|
||||
local id = line:sub(3, semicolon_pos - 1)
|
||||
local path = trim(line:sub(semicolon_pos + 1))
|
||||
kernel.log("Mounted "..id.." to "..path)
|
||||
kernel.log("Mounting '"..id.."' to '"..path.."'")
|
||||
if id ~= "$" then
|
||||
kernel.vfs.mount(path, id)
|
||||
end
|
||||
kernel.log("Mounted "..id.." to "..path)
|
||||
end
|
||||
end
|
||||
end
|
||||
+15
-4
@@ -12,13 +12,24 @@ function signal.sigsend(pid, sig)
|
||||
end
|
||||
|
||||
function signal.sigcatch(handler)
|
||||
kernel.currentTask.sigh=handler
|
||||
if not kernel.currentTask.sigq then kernel.currentTask.sigq={} end
|
||||
local task=kernel.currentTask
|
||||
task.sigh=handler
|
||||
if not task.sigq then task.sigq={} end
|
||||
local handle={
|
||||
error="",
|
||||
active=true
|
||||
}
|
||||
if task.sigd then task.sigd.active=false; end
|
||||
task.sigd=handle
|
||||
return handle
|
||||
end
|
||||
|
||||
function signal.sigignore()
|
||||
kernel.currentTask.sigh=nil
|
||||
kernel.currentTask.sigq=nil
|
||||
local task=kernel.currentTask
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
if task.sigd then task.sigd.active=false end
|
||||
task.sigd=nil
|
||||
end
|
||||
|
||||
local s=kernel.syscalls
|
||||
@@ -0,0 +1,199 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local socket = {}
|
||||
|
||||
socket.handlers = {}
|
||||
|
||||
kernel.socket = socket
|
||||
|
||||
local P = kernel.vfs.P
|
||||
local sys = kernel.syscalls
|
||||
|
||||
function socket.registerProtocal(proto, handler)
|
||||
socket.handlers[proto] = handler
|
||||
end
|
||||
|
||||
local function getHandler(address)
|
||||
for proto, handler in pairs(socket.handlers) do
|
||||
if string.hasPrefix(address, proto) then
|
||||
return handler
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function socket.socket()
|
||||
local fd = kernel.vfs.newfd({
|
||||
handle = {},
|
||||
|
||||
type = "socket",
|
||||
|
||||
refcount = 1,
|
||||
|
||||
socket = {
|
||||
connected = false,
|
||||
protocol = nil,
|
||||
address = nil
|
||||
},
|
||||
|
||||
meta = {
|
||||
owner = kernel.currentTask.uid,
|
||||
group = kernel.currentTask.uid,
|
||||
etype = 2,
|
||||
|
||||
perms =
|
||||
P.OWNER_R +
|
||||
P.OWNER_W +
|
||||
P.GROUP_R +
|
||||
P.GROUP_W
|
||||
},
|
||||
|
||||
isvirt = true
|
||||
})
|
||||
|
||||
local fdo = kernel.currentTask.fd[fd]
|
||||
|
||||
fdo.handle.read = function()
|
||||
return nil, "ENOTCONN"
|
||||
end
|
||||
|
||||
fdo.handle.write = function()
|
||||
return nil, "ENOTCONN"
|
||||
end
|
||||
|
||||
fdo.handle.close = function()
|
||||
fdo.socket.connected = false
|
||||
return true
|
||||
end
|
||||
|
||||
return fd
|
||||
end
|
||||
|
||||
function socket.connect(fd, address)
|
||||
local fdo = kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
if fdo.type ~= "socket" then
|
||||
return nil, "ENOTSOCK"
|
||||
end
|
||||
|
||||
local handler =
|
||||
getHandler(address)
|
||||
|
||||
if not handler then
|
||||
return nil, "EPROTONOSUPPORT"
|
||||
end
|
||||
|
||||
fdo.socket.protocol = handler
|
||||
fdo.socket.address = address
|
||||
|
||||
local ok, err =
|
||||
handler.connect(fd, address)
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
fdo.socket.connected = true
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function socket.listen(fd, backlog)
|
||||
local fdo =
|
||||
kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
if not fdo.handle.listen then
|
||||
return nil, "EOPNOTSUPP"
|
||||
end
|
||||
|
||||
return fdo.handle.listen(backlog)
|
||||
end
|
||||
|
||||
function socket.send(fd, data)
|
||||
local fdo =
|
||||
kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
if fdo.type ~= "socket" then
|
||||
return nil, "ENOTSOCK"
|
||||
end
|
||||
|
||||
if not fdo.socket.connected then
|
||||
return nil, "ENOTCONN"
|
||||
end
|
||||
|
||||
if not fdo.handle.write then
|
||||
return nil, "EOPNOTSUPP"
|
||||
end
|
||||
|
||||
return fdo.handle.write(data)
|
||||
end
|
||||
|
||||
function socket.recv(fd, amount)
|
||||
local fdo =
|
||||
kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
if fdo.type ~= "socket" then
|
||||
return nil, "ENOTSOCK"
|
||||
end
|
||||
|
||||
if not fdo.socket.connected then
|
||||
return nil, "ENOTCONN"
|
||||
end
|
||||
|
||||
if not fdo.handle.read then
|
||||
return nil, "EOPNOTSUPP"
|
||||
end
|
||||
|
||||
return fdo.handle.read(amount)
|
||||
end
|
||||
|
||||
function socket.sockshutdown(fd)
|
||||
local fdo =
|
||||
kernel.currentTask.fd[fd]
|
||||
|
||||
if not fdo then
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
if fdo.type ~= "socket" then
|
||||
return nil, "ENOTSOCK"
|
||||
end
|
||||
|
||||
if fdo.handle.close then
|
||||
return fdo.handle.close()
|
||||
end
|
||||
|
||||
fdo.socket.connected = false
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function socket.socketendpoints()
|
||||
return table.keys(socket.handlers)
|
||||
end
|
||||
|
||||
sys.socket = socket.socket
|
||||
sys.connect = socket.connect
|
||||
sys.listen = socket.listen
|
||||
sys.send = socket.send
|
||||
sys.recv = socket.recv
|
||||
sys.sockshutdown = socket.sockshutdown
|
||||
sys.socketendpoints = socket.socketendpoints
|
||||
|
||||
kernel.log("Loaded socket module")
|
||||
@@ -0,0 +1,4 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
kernel.unixSockets={}
|
||||
local socket=kernel.socket
|
||||
File renamed without changes.
@@ -0,0 +1,129 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local vterms = {}
|
||||
|
||||
local function createVt(id, width, height)
|
||||
local vt = {
|
||||
id = id,
|
||||
width = width,
|
||||
height = height,
|
||||
buffer = {},
|
||||
cursorX = 1,
|
||||
cursorY = 1,
|
||||
fgColor = 0xFFFFFF,
|
||||
bgColor = 0x000000,
|
||||
obj = {}
|
||||
}
|
||||
|
||||
for y = 1, height do
|
||||
vt.buffer[y] = {}
|
||||
for x = 1, width do
|
||||
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
end
|
||||
end
|
||||
|
||||
local function scroll(lines)
|
||||
for _ = 1, lines do
|
||||
table.remove(vt.buffer, 1)
|
||||
vt.buffer[vt.height] = {}
|
||||
for x = 1, vt.width do
|
||||
vt.buffer[vt.height][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vt.obj:write(content)
|
||||
local x, y = vt.cursorX, vt.cursorY
|
||||
if x>vt.width then return end
|
||||
if y>vt.height then return end
|
||||
for i = 1, #content do
|
||||
local c = content:sub(i, i)
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
for _ = 1, spaces do
|
||||
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
x = x + 1
|
||||
if x > vt.width then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
end
|
||||
else
|
||||
if x <= vt.width and y <= vt.height then
|
||||
vt.buffer[y][x] = {char = c, fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > vt.width then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y > vt.height then
|
||||
scroll(1)
|
||||
y = vt.height
|
||||
end
|
||||
end
|
||||
|
||||
vt.cursorX, vt.cursorY = x, y
|
||||
end
|
||||
|
||||
function vt.obj:spos(x, y)
|
||||
vt.cursorX = tonumber(x)
|
||||
vt.cursorY = tonumber(y)
|
||||
end
|
||||
|
||||
function vt.obj:gpos()
|
||||
return tostring(vt.cursorX)..";"..tostring(vt.cursorY)
|
||||
end
|
||||
|
||||
function vt.obj:sfgc(color)
|
||||
vt.fgColor = tonumber(color)
|
||||
end
|
||||
|
||||
function vt.obj:sbgc(color)
|
||||
vt.bgColor = tonumber(color)
|
||||
end
|
||||
|
||||
function vt.obj:gfgc()
|
||||
return vt.fgColor
|
||||
end
|
||||
|
||||
function vt.obj:gbgc()
|
||||
return vt.bgColor
|
||||
end
|
||||
|
||||
function vt.obj:gplt()
|
||||
return 24
|
||||
end
|
||||
|
||||
function vt.obj:clear()
|
||||
for y = 1, vt.height do
|
||||
for x = 1, vt.width do
|
||||
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||
end
|
||||
end
|
||||
vt.cursorX, vt.cursorY = 1, 1
|
||||
end
|
||||
|
||||
function vt.obj:isvirt()
|
||||
return true
|
||||
end
|
||||
|
||||
function vt.obj:gctrl()
|
||||
return serializeBool(vt.ctrl)..";"..serializeBool(vt.alt)
|
||||
end
|
||||
|
||||
return vt
|
||||
end
|
||||
+3
-8
@@ -139,7 +139,7 @@ end
|
||||
if not blake2s then error("Failed to load blake2s") end
|
||||
|
||||
if not kernel.vfs.exists("/etc/pam.d/secret") then
|
||||
kernel.log("PAM SECRET REGENERATING PLEASE USE ROOT")
|
||||
kernel.log("PAM SECRET REGENERATING PLEASE USE ROOT", "WARN", 0xFF8800)
|
||||
local key = ""
|
||||
for i = 1, 256 do key = key .. string.char(math.random(0, 255)) end
|
||||
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
|
||||
@@ -150,16 +150,11 @@ end
|
||||
local pepper = getFile("/etc/pam.d/secret")
|
||||
|
||||
local function genSalt()
|
||||
local chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
|
||||
local s = ""
|
||||
for i = 1, 16 do
|
||||
s = s .. chars:sub(math.random(1, #chars), math.random(1, #chars))
|
||||
end
|
||||
return s
|
||||
return toHex(math.random(0,2^32))
|
||||
end
|
||||
|
||||
local function hashPassword(password, salt)
|
||||
local key = (pepper .. salt):sub(1, 32)
|
||||
local key = (pepper .. salt)
|
||||
return blake2s(password, key)
|
||||
end
|
||||
|
||||
+133
-64
@@ -21,7 +21,7 @@ local function loadExecutable(path)
|
||||
local env = kernel.freshUserEnv()
|
||||
|
||||
local func, err = load(data, "@" .. path, "t", env)
|
||||
if not func then error("ENOEXEC: " .. tostring(err)) end
|
||||
if not func then kernel.log("Failed to load executable: " .. tostring(err).. " : ".. tostring(path)); error("ENOEXEC: " .. tostring(err)) end
|
||||
|
||||
local meta = kernel.vfs.lstat(path)
|
||||
local suid_set = bit_is_set(meta.perms, 6)
|
||||
@@ -41,11 +41,11 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid)
|
||||
|
||||
if kernel.config.logTaskExit then
|
||||
if not ok then
|
||||
kernel.log("Task " .. tostring(id) .. " exited with err: " .. tostring(err), "ERROR", 2)
|
||||
kernel.log("Task " .. tostring(id) .. " exited with err: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
elseif err then
|
||||
kernel.log("Task " .. tostring(id) .. " exited with code: " .. tostring(err), "INFO")
|
||||
kernel.log("Task " .. tostring(id) .. " exited with code: " .. tostring(err), "DBUG", 0x00FFFF)
|
||||
else
|
||||
kernel.log("Task " .. tostring(id) .. " exited without code", "INFO")
|
||||
kernel.log("Task " .. tostring(id) .. " exited without code", "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,7 +110,7 @@ function sys.execspawn(path, name, envars, args, tgid)
|
||||
kernel.log(
|
||||
"execspawn: suid exec '" .. path ..
|
||||
"' caller_uid=" .. tostring(real_uid) ..
|
||||
" -> euid=" .. tostring(euid), "INFO"
|
||||
" -> euid=" .. tostring(euid)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -136,9 +136,9 @@ function sys.exec(path, args, envars)
|
||||
local ok, err = xpcall(func, debug.traceback, table.unpack(task.args))
|
||||
if kernel.config.logTaskExit then
|
||||
if not ok then
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' err: " .. tostring(err), "ERROR", 2)
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' err: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' exited: " .. tostring(err), "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' exited: " .. tostring(err), "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
if type(err) == "number" then tasks[tostring(task.pid)].exit = err end
|
||||
@@ -150,13 +150,11 @@ function sys.exec(path, args, envars)
|
||||
tasks[tostring(task.pid)].status = "Z"
|
||||
end)
|
||||
task.syscallReturn = {}
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
function sys.sleep(s)
|
||||
kernel.currentTask.status = "S"
|
||||
kernel.currentTask.sleep = kernel.computer:time() + s * 1000
|
||||
coroutine.yield()
|
||||
kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000
|
||||
end
|
||||
|
||||
function sys.getTask(pid)
|
||||
@@ -204,12 +202,16 @@ function sys.collect(pid)
|
||||
end
|
||||
end
|
||||
|
||||
function sys.kill(pid)
|
||||
function sys.kill(pid, force)
|
||||
local task = tasks[tostring(pid)]
|
||||
if not task then
|
||||
return false, "Task does not exist"
|
||||
elseif task.status == "Z" then
|
||||
return false, "Task is already dead"
|
||||
elseif task.status == "D" and not force then
|
||||
return false, "Cannot kill task waiting for IO"
|
||||
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||
return false, "Different user"
|
||||
end
|
||||
local caller = kernel.currentTask
|
||||
local ceuid = caller and (caller.euid or caller.uid) or kernel.uid
|
||||
@@ -224,10 +226,16 @@ function sys.stop(pid)
|
||||
local task = tasks[tostring(pid)]
|
||||
if not task then
|
||||
return false, "Task does not exist"
|
||||
elseif task.status ~= "R" then
|
||||
elseif task.status ~= "R" and task.status ~= "S" then
|
||||
return false, "Cannot stop non-running task"
|
||||
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||
return false, "Different user"
|
||||
else
|
||||
task.status = "T"
|
||||
if task.status == "S" then
|
||||
task.status = "ST"
|
||||
else
|
||||
task.status = "T"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -236,10 +244,16 @@ function sys.continue(pid)
|
||||
local task = tasks[tostring(pid)]
|
||||
if not task then
|
||||
return false, "Task does not exist"
|
||||
elseif task.status ~= "T" then
|
||||
elseif task.status ~= "T" and task.status ~= "ST" then
|
||||
return false, "Task is not stopped"
|
||||
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||
return false, "Different user"
|
||||
else
|
||||
task.status = "R"
|
||||
if task.status == "ST" then
|
||||
task.status = "S"
|
||||
else
|
||||
task.status = "R"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -260,9 +274,9 @@ function sys.exit(code)
|
||||
local task = kernel.currentTask
|
||||
if kernel.config.logTaskExit then
|
||||
if code then
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited with code: " .. tostring(code), "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited with code: " .. tostring(code), "DBUG", 0x00FFFF)
|
||||
else
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
tasks[tostring(task.pid)].status = "Z"
|
||||
@@ -290,22 +304,23 @@ function sys.getuid() return kernel.currentTask.uid end
|
||||
local function reapDeadTasks()
|
||||
for pid, task in pairs(tasks) do
|
||||
if task.status == "Z" and not task.reapTime then
|
||||
task.coro = nil
|
||||
task.ivs = nil
|
||||
task.vs = nil
|
||||
task.args = nil
|
||||
task.envars = nil
|
||||
task.cwd = nil
|
||||
task.numRuns = nil
|
||||
task.totalTime = nil
|
||||
task.lastTime = nil
|
||||
task.timeSlice = nil
|
||||
if task.pid == 1 then kernel.panic("Attempted to gc init!") end
|
||||
task.coro = nil
|
||||
task.ivs = nil
|
||||
task.vs = nil
|
||||
task.args = nil
|
||||
task.envars = nil
|
||||
task.cwd = nil
|
||||
task.numRuns = nil
|
||||
task.totalTime = nil
|
||||
task.lastTime = nil
|
||||
task.timeSlice = nil
|
||||
task.syscallReturn = nil
|
||||
task.sleep = nil
|
||||
task.fd = nil
|
||||
task.reapTime = kernel.computer:time() + 30000
|
||||
task.sleep = nil
|
||||
task.fd = nil
|
||||
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
||||
|
||||
elseif task.reapTime and kernel.computer:time() > task.reapTime
|
||||
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
||||
and task.status == "Z" then
|
||||
for _, child in ipairs(task.children) do
|
||||
child.parent = tasks["1"]
|
||||
@@ -335,7 +350,23 @@ local k_max = 0.5
|
||||
local B = 0.01
|
||||
|
||||
function kernel.main()
|
||||
kernel.log("Starting main loop...")
|
||||
kernel.saveLog()
|
||||
local stopLog=5
|
||||
local logTasks=100
|
||||
|
||||
while not kernel.exitMain do
|
||||
if kernel.config.logTasks then
|
||||
if logTasks<0 then
|
||||
kernel.log("Active Tasks:")
|
||||
for i,v in pairs(tasks) do
|
||||
kernel.log(v.name.." : "..v.status.." : "..tostring(v.pid).." : "..tostring(v.exit))
|
||||
end
|
||||
kernel.log("[END BLOCK]")
|
||||
logTasks=100
|
||||
end
|
||||
logTasks=logTasks-1
|
||||
end
|
||||
local N = 0
|
||||
local Tmin_hit = 0
|
||||
local Tmax_hit = 0
|
||||
@@ -343,55 +374,88 @@ function kernel.main()
|
||||
local taskTimes = {}
|
||||
|
||||
for pid, task in pairs(tasks) do
|
||||
if task.status == "S" and kernel.computer:time() >= task.sleep then
|
||||
if kernel.exitMain then break end
|
||||
kernel.currentTask = task
|
||||
kernel.uid = task.euid or task.uid
|
||||
kernel.process = task.name
|
||||
|
||||
if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||
task.status = "R"
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
if task.status == "R" then
|
||||
kernel.currentTask = task
|
||||
if task.status == "ST" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||
task.status = "T"
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
kernel.uid = task.euid or task.uid
|
||||
kernel.process = task.name
|
||||
if task.status == "DS" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||
task.status = "D"
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
if task.status == "D" then
|
||||
if task.io then
|
||||
local ret = {xpcall(task.io, debug.traceback)}
|
||||
if not ret[1] then
|
||||
task.syscallReturn = {false, table.unpack(ret, 2)}
|
||||
task.status = "R"
|
||||
task.io=nil
|
||||
elseif #ret>1 then
|
||||
task.syscallReturn = {true, table.unpack(ret, 2)}
|
||||
task.status = "R"
|
||||
task.io=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if task.status == "R" then
|
||||
N = N + 1
|
||||
|
||||
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
||||
|
||||
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
||||
local coro = coroutine.create(task.sigh)
|
||||
local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) }
|
||||
while coroutine.status(coro) ~= "dead" do
|
||||
if sigret[1] == false then break end
|
||||
if sigret[2] == "syscall" then
|
||||
local scname = sigret[3]
|
||||
local sysret
|
||||
if kernel.syscalls[scname] then
|
||||
sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(sigret, 4)) }
|
||||
else
|
||||
sysret = { false, "Unknown syscall: " .. tostring(scname) }
|
||||
end
|
||||
if not sysret[1] then
|
||||
sigret = { coroutine.resume(coro, false, sysret[2]) }
|
||||
else
|
||||
sigret = { coroutine.resume(coro, true, table.unpack(sysret, 2)) }
|
||||
end
|
||||
else
|
||||
sigret = { coroutine.resume(coro) }
|
||||
local status,err
|
||||
if kernel.config.preempt then
|
||||
status,err=coroutine.resumeWithTimeout(coro, 100, table.remove(task.sigq, 1))
|
||||
else
|
||||
status,err=coroutine.resume(coro, table.remove(task.sigq, 1))
|
||||
end
|
||||
if status=="error" or status==false then
|
||||
task.sigd.error=err or "Unknown"
|
||||
task.sigd.active=false
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
task.sigd=nil
|
||||
elseif status=="success" or status==true then
|
||||
if err=="syscall" then
|
||||
task.sigd.error="Cannot execute syscalls from signals"
|
||||
task.sigd.active=false
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
task.sigd=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if task.status == "R" then
|
||||
local startTime = kernel.computer:time()
|
||||
local startTime = kernel.EFI:getEpochMs()
|
||||
local ret
|
||||
|
||||
if stopLog > 0 then
|
||||
kernel.log("Running task " .. tostring(task.pid) .. " (" .. task.name .. ") with time slice " .. string.format("%.3f", task.timeSlice) .. "s", "DBUG", 0x00FFFF)
|
||||
end
|
||||
if kernel.config.preempt then
|
||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||
if not task.debugger then
|
||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||
else
|
||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||
end
|
||||
else
|
||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||
end
|
||||
|
||||
local elapsed = kernel.computer:time() - startTime
|
||||
local elapsed = kernel.EFI:getEpochMs() - startTime
|
||||
task.lastTime = elapsed
|
||||
task.totalTime = (task.totalTime or 0) + elapsed
|
||||
task.numRuns = (task.numRuns or 0) + 1
|
||||
@@ -403,7 +467,7 @@ function kernel.main()
|
||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
||||
|
||||
if ret[1] == "error" or ret[1] == false then
|
||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 2)
|
||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 0xFF0000)
|
||||
task.status = "Z"
|
||||
task.exit = "processHandlerException: " .. tostring(ret[2])
|
||||
|
||||
@@ -418,9 +482,9 @@ function kernel.main()
|
||||
local scname = ret[3]
|
||||
if kernel.syscalls[scname] then
|
||||
if kernel.config.debugSyscalls then
|
||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 5)
|
||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 0x00FFFF)
|
||||
for i = 4, #ret do
|
||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 5)
|
||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -428,12 +492,12 @@ function kernel.main()
|
||||
|
||||
if kernel.config.debugSyscalls then
|
||||
if not sysret[1] then
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 2)
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 5)
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 0x00FFFF)
|
||||
for i = 2, #sysret do
|
||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 5)
|
||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -466,6 +530,11 @@ function kernel.main()
|
||||
end
|
||||
|
||||
reapDeadTasks()
|
||||
if stopLog > 0 then
|
||||
kernel.log("Executed " .. N .. " tasks, avg time: " .. string.format("%.2f", T_prev_avg) .. "ms, var: " .. string.format("%.2f", T_prev_var) .. ", B: " .. string.format("%.5f", B))
|
||||
stopLog = stopLog - 1
|
||||
kernel.saveLog()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File renamed without changes.
+12
@@ -9,8 +9,20 @@ sysc["gpio_write"]=function(pin, data)
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_writeAnalog"]=function(pin, data)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("wa", data)
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_read"]=function(pin)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("r")
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_readAnalog"]=function(pin)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("ra")
|
||||
end
|
||||
end
|
||||
+21
@@ -20,3 +20,24 @@ function printInline(...)
|
||||
output = output:sub(1, -2)
|
||||
syscall.write(1, output)
|
||||
end
|
||||
|
||||
function userinput(fd, helpstr, replacestr, fdo)
|
||||
local str = ""
|
||||
if helpstr then print(helpstr) end
|
||||
while true do
|
||||
local inp = syscall.read(fd)
|
||||
if inp~="" and inp~=nil then
|
||||
if inp~="\n" then
|
||||
if replacestr then
|
||||
syscall.write(fdo, replacestr)
|
||||
else
|
||||
syscall.write(fdo, inp)
|
||||
end
|
||||
str = inp
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
+4
-1
@@ -9,11 +9,13 @@ if not initOk then
|
||||
end
|
||||
|
||||
local handle = kernel.vfs.open(kernel.config.initPath, "r")
|
||||
if not handle then kernel.panic("Failed to open "..kernel.config.initPath) end
|
||||
local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
||||
if not handle then kernel.panic("Failed to read "..kernel.config.initPath) end
|
||||
kernel.vfs.close(handle)
|
||||
|
||||
local initFunc, err = load(data, "@sysinit", "t", kernel._U)
|
||||
if not initFunc then error("Failed to load init system: " .. err) end
|
||||
if not initFunc then kernel.PANIC("Failed to load init system: " .. err) end
|
||||
|
||||
kernel.tasks["1"] = {
|
||||
coro = coroutine.create(function()
|
||||
@@ -23,6 +25,7 @@ kernel.tasks["1"] = {
|
||||
else
|
||||
kernel.panic("Init system exited: " .. tostring(err))
|
||||
end
|
||||
kernel.saveLog()
|
||||
end),
|
||||
|
||||
name = "sysinit",
|
||||
@@ -0,0 +1,12 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
kernel.processes.kgc = function()
|
||||
while true do
|
||||
for i,v in pairs(kernel.reqcache) do
|
||||
if v.expires and kernel.EFI:getEpochMs() > v.expires then
|
||||
kernel.reqcache[i] = nil
|
||||
end
|
||||
end
|
||||
sleep(5)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,121 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
if kernel.firstBoot then
|
||||
local P = kernel.vfs.P
|
||||
local PERM = kernel.vfs.PERM
|
||||
|
||||
local RW_R_R = P.OWNER_R + P.OWNER_W + P.GROUP_R + P.WORLD_R
|
||||
local RWX_RX_RX = P.OWNER_R + P.OWNER_W + P.OWNER_X
|
||||
+ P.GROUP_R + P.GROUP_X
|
||||
+ P.WORLD_R + P.WORLD_X
|
||||
local RW_R__ = P.OWNER_R + P.OWNER_W + P.GROUP_R
|
||||
local RW____ = P.OWNER_R + P.OWNER_W
|
||||
local RWXRWXRWX = PERM.RWXRWXRWX
|
||||
local SUID_755 = PERM.SUID_755
|
||||
|
||||
local META_VERSION = 0x02
|
||||
local rootDisk = kernel.disks["$"]
|
||||
|
||||
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
||||
cmeta = cmeta or ""
|
||||
local plo = perms % 256
|
||||
local phi = math.floor(perms / 256) % 256
|
||||
local olo = (owner or 0) % 256
|
||||
local ohi = math.floor((owner or 0) / 256) % 256
|
||||
local glo = (group or 0) % 256
|
||||
local ghi = math.floor((group or 0) / 256) % 256
|
||||
return string.char(#name) .. name
|
||||
.. string.char(etype, olo, ohi, glo, ghi, plo, phi)
|
||||
.. string.char(#cmeta) .. cmeta
|
||||
end
|
||||
|
||||
local REG = 0x00
|
||||
|
||||
local function mergeMeta(dir, entries)
|
||||
local diskDir = dir
|
||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||
|
||||
local existing = {}
|
||||
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||
if rok and rf then
|
||||
local raw = rf.read(65535)
|
||||
if rf.close then rf.close() end
|
||||
existing = (kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw)) or {}
|
||||
end
|
||||
|
||||
for _, e in ipairs(entries) do
|
||||
local name = e[1]
|
||||
local etype = e[2] or REG
|
||||
local owner = e[3] or 0
|
||||
local group = e[4] or 0
|
||||
local perms = e[5] or RWX_RX_RX
|
||||
local cmeta = e[6] or ""
|
||||
existing[name] = {
|
||||
etype = etype,
|
||||
owner = owner,
|
||||
group = group,
|
||||
perms = perms,
|
||||
cmeta = cmeta,
|
||||
}
|
||||
end
|
||||
|
||||
local data = string.char(META_VERSION)
|
||||
for name, m in pairs(existing) do
|
||||
data = data .. makeEntry(
|
||||
name,
|
||||
m.etype or REG,
|
||||
m.owner or 0,
|
||||
m.group or 0,
|
||||
m.perms or RWX_RX_RX,
|
||||
m.cmeta or ""
|
||||
)
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
local f = rootDisk:open(metaPath, "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
end)
|
||||
if not ok then
|
||||
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 0xFF8800)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Seeding filesystem permissions...")
|
||||
|
||||
mergeMeta("/", {
|
||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||
{"dev", REG, 0, 0, RWXRWXRWX},
|
||||
{"etc", REG, 0, 0, RWX_RX_RX},
|
||||
{"home", REG, 0, 0, RWX_RX_RX},
|
||||
{"lib", REG, 0, 0, RWX_RX_RX},
|
||||
{"proc", REG, 0, 0, RWXRWXRWX},
|
||||
{"root", REG, 0, 0, RW____ },
|
||||
{"sbin", REG, 0, 0, RWX_RX_RX},
|
||||
{"tmp", REG, 0, 0, RWXRWXRWX},
|
||||
{"usr", REG, 0, 0, RWX_RX_RX},
|
||||
{"var", REG, 0, 0, RWXRWXRWX},
|
||||
{"opt", REG, 0, 0, RWX_RX_RX},
|
||||
})
|
||||
|
||||
mergeMeta("/bin", {
|
||||
{"login", REG, 0, 0, SUID_755 },
|
||||
{"su", REG, 0, 0, SUID_755 },
|
||||
{"sudo", REG, 0, 0, SUID_755 },
|
||||
})
|
||||
|
||||
mergeMeta("/etc", {
|
||||
{"passwd", REG, 0, 0, RW_R_R },
|
||||
{"shadow", REG, 0, 0, RW____ },
|
||||
{"pam.d", REG, 0, 0, RW____ },
|
||||
})
|
||||
|
||||
mergeMeta("/etc/pam.d", {
|
||||
{"secret", REG, 0, 0, RW____},
|
||||
})
|
||||
|
||||
kernel.log("Filesystem permissions seeded.")
|
||||
end
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
Hyperion kernel package
|
||||
@@ -1,40 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local cache = {}
|
||||
kernel.searchpaths = {
|
||||
"/lib/?.lua", "/lib/?", "/usr/lib/?.lua", "/usr/lib/?",
|
||||
"/usr/local/lib/?.lua", "/usr/local/lib/?", "?.lua", "?"
|
||||
}
|
||||
|
||||
function require(module, ...)
|
||||
if cache[module] then return cache[module] end
|
||||
local modpath = module:gsub("%.", "/")
|
||||
local failed = {}
|
||||
for _, path in ipairs(kernel.searchpaths) do
|
||||
local full_path = string.replace(path, "?", modpath)
|
||||
if full_path:sub(1, 1) ~= "/" then
|
||||
full_path = kernel.currentTask.cwd .. full_path
|
||||
end
|
||||
|
||||
if kernel.vfs.exists(full_path) then
|
||||
if kernel.vfs.type(full_path) == "directory" then
|
||||
full_path = full_path .. "/init"
|
||||
end
|
||||
|
||||
if kernel.vfs.exists(full_path) then
|
||||
local handle = kernel.vfs.open(full_path, "r")
|
||||
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
||||
kernel.vfs.close(handle)
|
||||
|
||||
return
|
||||
assert(load(file_content, full_path, "t", kernel._U))(...)
|
||||
else
|
||||
table.insert(failed, full_path)
|
||||
end
|
||||
else
|
||||
table.insert(failed, full_path)
|
||||
end
|
||||
end
|
||||
|
||||
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
|
||||
end
|
||||
@@ -1,147 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "devfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("EACCES") end
|
||||
proxy.remove = function() error("EACCES") end
|
||||
proxy.setLabel = function() error("EACCES") end
|
||||
proxy.getLabel = function() return "devfs" end
|
||||
proxy.attributes = function(path) return {
|
||||
size = 0,
|
||||
modified = 0,
|
||||
created = 0
|
||||
} end
|
||||
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("open", mode)
|
||||
end
|
||||
error("ENFILE")
|
||||
end
|
||||
|
||||
function proxy:type(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return "directory"
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("type", mode)
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return "directory"
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return table.keys(data)
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENOENT") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return table.keys(step[steps[#steps]])
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
local ok = pcall(function()
|
||||
return self:type(path)
|
||||
end)
|
||||
return ok
|
||||
end
|
||||
|
||||
function data.random(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(math.random(0, 255))
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.null(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount) end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.zero(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(0)
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data["disk"]={}
|
||||
kernel.devfs={}
|
||||
kernel.devfs.data=data
|
||||
kernel.devfs.proxy=proxy
|
||||
kernel.disks["devfs0000"]=proxy
|
||||
@@ -1,134 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "tmpfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
|
||||
proxy.makeDirectory = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
if not step[steps[i]] then
|
||||
step[steps[i]] = {}
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
end
|
||||
|
||||
proxy.remove = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
step[steps[#steps]] = nil
|
||||
end
|
||||
|
||||
proxy.setLabel = function(_, label) end
|
||||
proxy.getLabel = function() return "tmpfs" end
|
||||
|
||||
proxy.attributes = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
return {
|
||||
size = type(step) == "string" and #step or 0,
|
||||
modified = 0,
|
||||
created = 0,
|
||||
}
|
||||
end
|
||||
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
if not step[steps[i]] then
|
||||
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
local filename = steps[#steps]
|
||||
|
||||
if mode == "r" then
|
||||
if type(step[filename]) ~= "string" then error("ENOENT") end
|
||||
local content = step[filename]
|
||||
local pos = 1
|
||||
return {
|
||||
read = function(amount)
|
||||
amount = amount or #content
|
||||
local chunk = content:sub(pos, pos+amount-1)
|
||||
pos = pos + #chunk
|
||||
return chunk
|
||||
end,
|
||||
close = function() end,
|
||||
}
|
||||
elseif mode == "w" then
|
||||
step[filename] = ""
|
||||
local buf = {}
|
||||
return {
|
||||
write = function(str)
|
||||
buf[#buf + 1] = str
|
||||
end,
|
||||
close = function()
|
||||
step[filename] = table.concat(buf)
|
||||
end,
|
||||
}
|
||||
elseif mode == "a" then
|
||||
if type(step[filename]) ~= "string" then step[filename] = "" end
|
||||
return {
|
||||
write = function(str)
|
||||
step[filename] = step[filename] .. str
|
||||
end,
|
||||
close = function() end,
|
||||
}
|
||||
else
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
|
||||
function proxy:type(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then return "directory" end
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then return false end
|
||||
end
|
||||
if type(step) == "table" then return "directory" end
|
||||
if type(step) == "string" then return "file" end
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
if type(step) ~= "table" then error("ENOTDIR") end
|
||||
local keys = {}
|
||||
for k,_ in pairs(step) do table.insert(keys, k) end
|
||||
return keys
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
local t = self:type(path)
|
||||
return t == "file" or t == "directory"
|
||||
end
|
||||
|
||||
kernel.disks["tmpfs0000"] = proxy
|
||||
@@ -1,556 +0,0 @@
|
||||
--:Minify:--
|
||||
-- Supports:
|
||||
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
||||
-- AF_INET - network sockets with three backends:
|
||||
-- rednet://0.0.B.C or rednet+PROTO://0.0.B.C -> CC rednet (computer B*256+C)
|
||||
-- modem://0.0.B.C -> raw CC modem frames
|
||||
-- http://host/path or https://... -> HTTP via CC http API
|
||||
-- A.B.C.D (dotted quad, non-zero A) -> HTTP
|
||||
--
|
||||
-- Socket lifecycle:
|
||||
-- fd = syscall.socket(domain, socktype) -- "unix"/"inet", "stream"/"dgram"
|
||||
-- syscall.bind(fd, address) -- server: claim address
|
||||
-- syscall.listen(fd, backlog) -- server: mark as listening
|
||||
-- cfd = syscall.accept(fd) -- server: get connected client fd (blocking poll)
|
||||
-- syscall.connect(fd, address) -- client: connect to server
|
||||
-- syscall.send(fd, data) -- send bytes
|
||||
-- syscall.recv(fd, len) -- receive bytes (blocking poll, returns "" on nothing)
|
||||
-- syscall.sockshutdown(fd) -- half-close send side
|
||||
-- -- normal vfs.close(fd) closes the socket
|
||||
|
||||
local kernel = ...
|
||||
|
||||
local sockets = {}
|
||||
local unixSocks = {}
|
||||
local nextSockId = 1
|
||||
|
||||
local function allocSockId()
|
||||
local id = nextSockId
|
||||
nextSockId = nextSockId + 1
|
||||
return id
|
||||
end
|
||||
|
||||
local function parseAddress(addr)
|
||||
if not addr then error("EINVAL") end
|
||||
|
||||
if addr:sub(1,1) == "/" or addr:sub(1,5) == "unix:" then
|
||||
local path = addr:sub(1,5) == "unix:" and addr:sub(6) or addr
|
||||
return { backend="unix", path=path }
|
||||
end
|
||||
|
||||
local rproto, raddr = addr:match("^rednet%+?([^:/]*)://(.+)$")
|
||||
if raddr then
|
||||
local a,b,c,d = raddr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if not a then error("EINVAL: bad rednet address " .. raddr) end
|
||||
local compId = tonumber(c)*256 + tonumber(d)
|
||||
return { backend="rednet", compId=compId,
|
||||
protocol=(rproto ~= "" and rproto or "hyperion") }
|
||||
end
|
||||
|
||||
local maddr = addr:match("^modem://(.+)$")
|
||||
if maddr then
|
||||
local a,b,c,d = maddr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if not a then error("EINVAL: bad modem address " .. maddr) end
|
||||
local compId = tonumber(c)*256 + tonumber(d)
|
||||
local port = tonumber(maddr:match(":(%d+)$")) or 0
|
||||
return { backend="modem", compId=compId, port=port }
|
||||
end
|
||||
|
||||
local scheme, rest = addr:match("^(https?)://(.+)$")
|
||||
if scheme then
|
||||
return { backend=scheme, url=addr }
|
||||
end
|
||||
|
||||
local a,b,c,d = addr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)")
|
||||
if a and tonumber(a) ~= 0 then
|
||||
return { backend="http", url="http://" .. addr }
|
||||
end
|
||||
|
||||
error("EINVAL: unrecognised address format: " .. tostring(addr))
|
||||
end
|
||||
|
||||
local rednetOpen = false
|
||||
local function ensureRednet()
|
||||
if rednetOpen then return end
|
||||
local rn = kernel.apis and kernel.apis.rednet
|
||||
if not rn then error("ENODEV: no rednet API available") end
|
||||
local peripheral = kernel.apis.peripheral
|
||||
if peripheral then
|
||||
for _, name in ipairs(peripheral.getNames and peripheral.getNames() or {}) do
|
||||
if peripheral.getType(name) == "modem" then
|
||||
pcall(rn.open, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
rednetOpen = true
|
||||
end
|
||||
|
||||
local function getModem()
|
||||
local peripheral = kernel.apis and kernel.apis.peripheral
|
||||
if not peripheral then error("ENODEV") end
|
||||
for _, name in ipairs(peripheral.getNames and peripheral.getNames() or {}) do
|
||||
if peripheral.getType(name) == "modem" then
|
||||
local m = peripheral.wrap(name)
|
||||
if m then return m, name end
|
||||
end
|
||||
end
|
||||
error("ENODEV: no modem peripheral found")
|
||||
end
|
||||
|
||||
local function pumpEvents()
|
||||
local ev = kernel.computer:getMachineEvent()
|
||||
while ev do
|
||||
if ev == "rednet_message" then
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "rednet" and sock.bound then
|
||||
if sock.address.protocol == tostring(select(4, table.unpack({ev}))) or
|
||||
sock.address.protocol == "hyperion" then
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ev = kernel.computer:getMachineEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local function pollEvent()
|
||||
local results = table.pack(kernel.computer:getMachineEvent())
|
||||
if results.n == 0 or results[1] == nil then return nil end
|
||||
return results
|
||||
end
|
||||
|
||||
local function dispatchEvent(ev)
|
||||
if not ev then return end
|
||||
local evtype = ev[1]
|
||||
|
||||
if evtype == "rednet_message" then
|
||||
local senderId = ev[2]
|
||||
local message = ev[3]
|
||||
local protocol = ev[4] or "hyperion"
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "rednet" and (sock.listening or sock.connected) then
|
||||
if sock.address and sock.address.protocol == protocol then
|
||||
table.insert(sock.rxbuf, { from=senderId, data=message })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "modem_message" then
|
||||
local channel = ev[3]
|
||||
local msg = ev[5]
|
||||
local fromCh = ev[4]
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "modem" and sock.modemChannel == channel then
|
||||
table.insert(sock.rxbuf, { from=fromCh, data=msg })
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "http_success" then
|
||||
local url = ev[2]
|
||||
local handle = ev[3]
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "http" or sock.backend == "https" then
|
||||
if sock.pendingUrl == url then
|
||||
local body = handle.readAll and handle.readAll() or ""
|
||||
handle.close()
|
||||
table.insert(sock.rxbuf, { data=body, done=true })
|
||||
sock.pendingUrl = nil
|
||||
sock.connected = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "http_failure" then
|
||||
local url = ev[2]
|
||||
local err = ev[3]
|
||||
for _, sock in pairs(sockets) do
|
||||
if (sock.backend == "http" or sock.backend == "https") and
|
||||
sock.pendingUrl == url then
|
||||
sock.error = err
|
||||
sock.pendingUrl = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function pumpAll()
|
||||
local ev = pollEvent()
|
||||
while ev do
|
||||
dispatchEvent(ev)
|
||||
ev = pollEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local function newSocket(domain, socktype)
|
||||
local sock = {
|
||||
id = allocSockId(),
|
||||
domain = domain, -- "unix" | "inet"
|
||||
socktype = socktype, -- "stream" | "dgram"
|
||||
backend = nil,
|
||||
state = "idle", -- idle | bound | listening | connected | closed
|
||||
rxbuf = {},
|
||||
txbuf = {},
|
||||
backlog = {},
|
||||
address = nil,
|
||||
peer = nil,
|
||||
modemChannel = nil,
|
||||
modem = nil,
|
||||
pendingUrl = nil,
|
||||
bound = false,
|
||||
listening = false,
|
||||
connected = false,
|
||||
error = nil,
|
||||
}
|
||||
sockets[sock.id] = sock
|
||||
return sock
|
||||
end
|
||||
|
||||
local sockSend, sockClose
|
||||
|
||||
local function socketToFd(sock)
|
||||
return {
|
||||
isSocket = true,
|
||||
sockId = sock.id,
|
||||
mode = "rw",
|
||||
meta = { etype=0, owner=0, group=0, perms=0x1FF, cmeta="" },
|
||||
type = "socket",
|
||||
refcount = 1,
|
||||
handle = {
|
||||
read = function(count)
|
||||
pumpAll()
|
||||
if #sock.rxbuf == 0 then return "" end
|
||||
local item = table.remove(sock.rxbuf, 1)
|
||||
local data = type(item) == "table" and (item.data or "") or tostring(item)
|
||||
if count and #data > count then
|
||||
table.insert(sock.rxbuf, 1, { data=data:sub(count+1), from=item.from })
|
||||
data = data:sub(1, count)
|
||||
end
|
||||
return data
|
||||
end,
|
||||
write = function(data)
|
||||
if sock.state == "closed" then error("EBADF") end
|
||||
return sockSend(sock, data)
|
||||
end,
|
||||
close = function()
|
||||
sockClose(sock)
|
||||
end,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
sockSend = function(sock, data)
|
||||
if sock.backend == "unix" then
|
||||
local peer = sock.peer
|
||||
if not peer then error("ENOTCONN") end
|
||||
table.insert(peer.rxbuf, { data=data })
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "rednet" then
|
||||
ensureRednet()
|
||||
local rn = kernel.apis.rednet
|
||||
rn.send(sock.address.compId, data, sock.address.protocol)
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "modem" then
|
||||
local modem = sock.modem
|
||||
if not modem then error("ENOTCONN") end
|
||||
modem.transmit(sock.address.port, sock.modemChannel or 0, data)
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "http" or sock.backend == "https" then
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API") end
|
||||
local url = sock.address.url
|
||||
local ok, err = pcall(http.request, url, data, {
|
||||
["Content-Type"] = "application/octet-stream"
|
||||
})
|
||||
if not ok then error("ENETDOWN: " .. tostring(err)) end
|
||||
sock.pendingUrl = url
|
||||
return #data
|
||||
end
|
||||
error("EPROTONOSUPPORT")
|
||||
end
|
||||
|
||||
sockClose = function(sock)
|
||||
if sock.state == "closed" then return end
|
||||
sock.state = "closed"
|
||||
|
||||
if sock.backend == "unix" then
|
||||
if sock.peer then
|
||||
sock.peer.peer = nil
|
||||
sock.peer.state = "closed"
|
||||
end
|
||||
if sock.bound and sock.address and sock.address.path then
|
||||
unixSocks[sock.address.path] = nil
|
||||
end
|
||||
|
||||
elseif sock.backend == "modem" and sock.modem and sock.modemChannel then
|
||||
pcall(sock.modem.close, sock.modemChannel)
|
||||
|
||||
elseif sock.backend == "rednet" then
|
||||
end
|
||||
|
||||
sockets[sock.id] = nil
|
||||
end
|
||||
|
||||
kernel.syscalls["socket"] = function(domain, socktype)
|
||||
domain = domain or "inet"
|
||||
socktype = socktype or "stream"
|
||||
if domain ~= "unix" and domain ~= "inet" then error("EAFNOSUPPORT") end
|
||||
if socktype ~= "stream" and socktype ~= "dgram" then error("EPROTOTYPE") end
|
||||
|
||||
local sock = newSocket(domain, socktype)
|
||||
local fdobj = socketToFd(sock)
|
||||
local fd = kernel.vfs.newfd(fdobj)
|
||||
return fd
|
||||
end
|
||||
|
||||
kernel.syscalls["bind"] = function(fd, address)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if sock.bound then error("EINVAL") end
|
||||
|
||||
local parsed = parseAddress(address)
|
||||
|
||||
if parsed.backend == "unix" then
|
||||
local existing = unixSocks[parsed.path]
|
||||
if existing then
|
||||
if existing.state == "closed" then
|
||||
unixSocks[parsed.path] = nil
|
||||
else
|
||||
error("EADDRINUSE")
|
||||
end
|
||||
end
|
||||
sock.backend = "unix"
|
||||
sock.address = parsed
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
unixSocks[parsed.path] = sock
|
||||
|
||||
elseif parsed.backend == "rednet" then
|
||||
ensureRednet()
|
||||
sock.backend = "rednet"
|
||||
sock.address = parsed
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
|
||||
elseif parsed.backend == "modem" then
|
||||
local modem, side = getModem()
|
||||
sock.backend = "modem"
|
||||
sock.address = parsed
|
||||
sock.modem = modem
|
||||
sock.modemChannel = parsed.port
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
modem.open(parsed.port)
|
||||
|
||||
else
|
||||
error("EOPNOTSUPP: cannot bind to " .. parsed.backend .. " address")
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["listen"] = function(fd, backlog)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if not sock.bound then error("EDESTADDRREQ") end
|
||||
sock.listening = true
|
||||
sock.state = "listening"
|
||||
sock.maxBacklog = backlog or 5
|
||||
end
|
||||
|
||||
kernel.syscalls["accept"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if not sock.listening then error("EINVAL") end
|
||||
|
||||
local deadline = kernel.computer:time() + 30000
|
||||
while #sock.backlog == 0 do
|
||||
pumpAll()
|
||||
if kernel.computer:time() > deadline then error("ETIMEDOUT") end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
local clientSock = table.remove(sock.backlog, 1)
|
||||
local cfdobj = socketToFd(clientSock)
|
||||
local newfd = kernel.vfs.newfd(cfdobj)
|
||||
return newfd
|
||||
end
|
||||
|
||||
kernel.syscalls["connect"] = function(fd, address)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if sock.connected then error("EISCONN") end
|
||||
|
||||
local parsed = parseAddress(address)
|
||||
sock.address = parsed
|
||||
sock.backend = parsed.backend
|
||||
|
||||
if parsed.backend == "unix" then
|
||||
local server = unixSocks[parsed.path]
|
||||
if not server then error("ECONNREFUSED") end
|
||||
if not server.listening then error("ECONNREFUSED") end
|
||||
if #server.backlog >= (server.maxBacklog or 5) then error("ECONNREFUSED") end
|
||||
|
||||
local serverPeer = newSocket("unix", sock.socktype)
|
||||
serverPeer.backend = "unix"
|
||||
serverPeer.connected = true
|
||||
serverPeer.state = "connected"
|
||||
serverPeer.peer = sock
|
||||
|
||||
sock.peer = serverPeer
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
table.insert(server.backlog, serverPeer)
|
||||
|
||||
elseif parsed.backend == "rednet" then
|
||||
ensureRednet()
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
elseif parsed.backend == "modem" then
|
||||
local modem, side = getModem()
|
||||
local replyChannel = math.random(1024, 65534)
|
||||
sock.modem = modem
|
||||
sock.modemChannel = replyChannel
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
modem.open(replyChannel)
|
||||
|
||||
elseif parsed.backend == "http" or parsed.backend == "https" then
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
else
|
||||
error("EAFNOSUPPORT")
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["send"] = function(fd, data)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
return sockSend(sock, data)
|
||||
end
|
||||
|
||||
kernel.syscalls["recv"] = function(fd, maxlen, timeout_ms)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
|
||||
local deadline = kernel.computer:time() + (timeout_ms or 10000)
|
||||
while #sock.rxbuf == 0 do
|
||||
pumpAll()
|
||||
if #sock.rxbuf > 0 then break end
|
||||
if sock.state == "closed" or sock.error then
|
||||
if sock.error then error("ECONNRESET: " .. tostring(sock.error)) end
|
||||
return ""
|
||||
end
|
||||
if kernel.computer:time() > deadline then return "" end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
local item = table.remove(sock.rxbuf, 1)
|
||||
local data = type(item) == "table" and (item.data or "") or tostring(item)
|
||||
if maxlen and #data > maxlen then
|
||||
table.insert(sock.rxbuf, 1, { data=data:sub(maxlen+1), from=item and item.from })
|
||||
data = data:sub(1, maxlen)
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
kernel.syscalls["sockshutdown"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if sock then sockClose(sock) end
|
||||
end
|
||||
|
||||
kernel.syscalls["getpeername"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock or not sock.connected then error("ENOTCONN") end
|
||||
if sock.address then return sock.address end
|
||||
return nil
|
||||
end
|
||||
|
||||
kernel.syscalls["getsockname"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
return sock.address
|
||||
end
|
||||
|
||||
kernel.syscalls["httpget"] = function(url, headers)
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API") end
|
||||
|
||||
local ok, err = pcall(http.request, url, nil, headers)
|
||||
if not ok then error("ENETDOWN: " .. tostring(err)) end
|
||||
|
||||
local deadline = kernel.computer:time() + 15000
|
||||
while true do
|
||||
local ev = pollEvent()
|
||||
if ev then
|
||||
if ev[1] == "http_success" and ev[2] == url then
|
||||
local handle = ev[3]
|
||||
local body = handle.readAll and handle.readAll() or ""
|
||||
handle.close()
|
||||
return body
|
||||
elseif ev[1] == "http_failure" and ev[2] == url then
|
||||
error("ECONNREFUSED: " .. tostring(ev[3]))
|
||||
else
|
||||
dispatchEvent(ev)
|
||||
end
|
||||
end
|
||||
if kernel.computer:time() > deadline then error("ETIMEDOUT") end
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["resolve"] = function(hostname)
|
||||
if hostname:match("^%d+%.%d+%.%d+%.%d+$") then return hostname end
|
||||
|
||||
local a,b,c,d = hostname:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if a and tonumber(a) == 0 and tonumber(b) == 0 then
|
||||
return hostname
|
||||
end
|
||||
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API for DNS") end
|
||||
|
||||
local url = "https://cloudflare-dns.com/dns-query?name=" .. hostname .. "&type=A"
|
||||
local body = kernel.syscalls["httpget"](url, {
|
||||
["Accept"] = "application/dns-json"
|
||||
})
|
||||
|
||||
local ip = body:match('"type":1[^}]*"data":"([%d%.]+)"')
|
||||
if not ip then error("ENOENT: could not resolve " .. hostname) end
|
||||
return ip
|
||||
end
|
||||
|
||||
kernel.sockets = sockets
|
||||
kernel.unixSockets = unixSocks
|
||||
|
||||
kernel.log("Loaded socket module")
|
||||
@@ -1,9 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
kernel.processes.login = function()
|
||||
local ok, err = pcall(kernel.hpv.execspawn, "/bin/login", "login")
|
||||
if not ok then
|
||||
kernel.log("Failed to exec /bin/login: " .. tostring(err), "ERROR", 2)
|
||||
end
|
||||
end
|
||||
@@ -1,120 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local P = kernel.vfs.P
|
||||
local PERM = kernel.vfs.PERM
|
||||
|
||||
local RW_R_R = P.OWNER_R + P.OWNER_W + P.GROUP_R + P.WORLD_R
|
||||
local RWX_RX_RX = P.OWNER_R + P.OWNER_W + P.OWNER_X
|
||||
+ P.GROUP_R + P.GROUP_X
|
||||
+ P.WORLD_R + P.WORLD_X
|
||||
local RW_R__ = P.OWNER_R + P.OWNER_W + P.GROUP_R
|
||||
local RW____ = P.OWNER_R + P.OWNER_W
|
||||
local RWXRWXRWX = PERM.RWXRWXRWX
|
||||
local SUID_755 = PERM.SUID_755
|
||||
|
||||
local META_VERSION = 0x02
|
||||
local rootDisk = kernel.disks["$"]
|
||||
|
||||
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
||||
cmeta = cmeta or ""
|
||||
local plo = perms % 256
|
||||
local phi = math.floor(perms / 256) % 256
|
||||
local olo = (owner or 0) % 256
|
||||
local ohi = math.floor((owner or 0) / 256) % 256
|
||||
local glo = (group or 0) % 256
|
||||
local ghi = math.floor((group or 0) / 256) % 256
|
||||
return string.char(#name) .. name
|
||||
.. string.char(etype, olo, ohi, glo, ghi, plo, phi)
|
||||
.. string.char(#cmeta) .. cmeta
|
||||
end
|
||||
|
||||
local REG = 0x00
|
||||
|
||||
local function mergeMeta(dir, entries)
|
||||
local diskDir = dir
|
||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||
|
||||
local existing = {}
|
||||
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||
if rok and rf then
|
||||
local raw = rf.read(65535)
|
||||
if rf.close then rf.close() end
|
||||
existing = (kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw)) or {}
|
||||
end
|
||||
|
||||
for _, e in ipairs(entries) do
|
||||
local name = e[1]
|
||||
local etype = e[2] or REG
|
||||
local owner = e[3] or 0
|
||||
local group = e[4] or 0
|
||||
local perms = e[5] or RWX_RX_RX
|
||||
local cmeta = e[6] or ""
|
||||
existing[name] = {
|
||||
etype = etype,
|
||||
owner = owner,
|
||||
group = group,
|
||||
perms = perms,
|
||||
cmeta = cmeta,
|
||||
}
|
||||
end
|
||||
|
||||
local data = string.char(META_VERSION)
|
||||
for name, m in pairs(existing) do
|
||||
data = data .. makeEntry(
|
||||
name,
|
||||
m.etype or REG,
|
||||
m.owner or 0,
|
||||
m.group or 0,
|
||||
m.perms or RWX_RX_RX,
|
||||
m.cmeta or ""
|
||||
)
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
local f = rootDisk:open(metaPath, "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
end)
|
||||
if not ok then
|
||||
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 8)
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.firstBoot then
|
||||
kernel.log("Seeding filesystem permissions...")
|
||||
|
||||
mergeMeta("/", {
|
||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||
{"dev", REG, 0, 0, RWXRWXRWX},
|
||||
{"etc", REG, 0, 0, RWX_RX_RX},
|
||||
{"home", REG, 0, 0, RWX_RX_RX},
|
||||
{"lib", REG, 0, 0, RWX_RX_RX},
|
||||
{"root", REG, 0, 0, RW____ },
|
||||
{"sbin", REG, 0, 0, RWX_RX_RX},
|
||||
{"tmp", REG, 0, 0, RWXRWXRWX},
|
||||
{"usr", REG, 0, 0, RWX_RX_RX},
|
||||
{"var", REG, 0, 0, RWXRWXRWX},
|
||||
{"opt", REG, 0, 0, RWX_RX_RX},
|
||||
})
|
||||
|
||||
mergeMeta("/bin", {
|
||||
{"login", REG, 0, 0, SUID_755 },
|
||||
{"su", REG, 0, 0, SUID_755 },
|
||||
{"sudo", REG, 0, 0, SUID_755 },
|
||||
})
|
||||
|
||||
mergeMeta("/etc", {
|
||||
{"passwd", REG, 0, 0, RW_R_R },
|
||||
{"shadow", REG, 0, 0, RW____ },
|
||||
{"pam.d", REG, 0, 0, RW____ },
|
||||
})
|
||||
|
||||
mergeMeta("/etc/pam.d", {
|
||||
{"secret", REG, 0, 0, RW____},
|
||||
})
|
||||
|
||||
kernel.log("Filesystem permissions seeded.")
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
1.5.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Lua
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
Bit32 package for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
blake2s package for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
Spsf
|
||||
@@ -1,5 +1,5 @@
|
||||
--:Minify:--
|
||||
syscall.open("/dev/tty/1", "r") --stdin (fd 0)
|
||||
syscall.open("/dev/input/keyboard1", "r") --stdin (fd 0)
|
||||
syscall.open("/dev/tty/1", "w") --stdout (fd 1)
|
||||
syscall.open("/dev/null", "w") --stderr (fd 2)
|
||||
|
||||
@@ -37,9 +37,9 @@ local function firstBoot()
|
||||
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "HyperionOS First Boot Setup\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "No root password is set. Please create one now.\n\n")
|
||||
|
||||
while true do
|
||||
@@ -49,25 +49,25 @@ local function firstBoot()
|
||||
local pw2 = readLine("*")
|
||||
|
||||
if pw1 ~= pw2 then
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Passwords do not match. Try again.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
elseif #pw1 < 6 then
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Password too short (minimum 6 characters).\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
else
|
||||
local ok, err = syscall.setpassword(0, pw1)
|
||||
if ok then
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "Root password set.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.5)
|
||||
break
|
||||
else
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -112,8 +112,8 @@ end
|
||||
|
||||
local function doLogin()
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sbgc", 16)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
|
||||
local hostname = syscall.getHostname() or "hyperion"
|
||||
@@ -122,45 +122,44 @@ local function doLogin()
|
||||
|
||||
local attempts = 0
|
||||
while attempts < MAX_ATTEMPTS do
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "Username: ")
|
||||
local username = readLine(nil)
|
||||
|
||||
if username == "" then goto continue end
|
||||
if username ~= "" then
|
||||
|
||||
syscall.write(1, "Password: ")
|
||||
local password = readLine("*")
|
||||
local uid = syscall.getuidbyname(username)
|
||||
syscall.write(1, "Password: ")
|
||||
local password = readLine("*")
|
||||
local uid = syscall.getuidbyname(username)
|
||||
|
||||
local ok, err = syscall.login(uid, password)
|
||||
if ok then
|
||||
local uid = syscall.getuid()
|
||||
local pwent = syscall.getpasswd(uid)
|
||||
local ok, err = syscall.login(uid, password)
|
||||
if ok then
|
||||
local uid = syscall.getuid()
|
||||
local pwent = syscall.getpasswd(uid)
|
||||
|
||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
sleep(0.3)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.3)
|
||||
|
||||
spawnShell(username, uid, shell, homedir)
|
||||
return -- back to login prompt
|
||||
else
|
||||
attempts = attempts + 1
|
||||
sleep(1)
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
spawnShell(username, uid, shell, homedir)
|
||||
return -- back to login prompt
|
||||
else
|
||||
attempts = attempts + 1
|
||||
sleep(1)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Maximum login attempts exceeded.\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(5)
|
||||
end
|
||||
|
||||
@@ -5,15 +5,15 @@ if not users or #users == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
syscall.devctl(1,"sfgc",13)
|
||||
syscall.devctl(1,"sfgc",0xDBDBDB)
|
||||
print(string.format("%-6s %-6s %-16s %-20s %s", "UID", "GID", "Username", "Home", "Shell"))
|
||||
print(string.rep("-", 65))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
|
||||
for _, u in ipairs(users) do
|
||||
local lock_marker = u.locked and " [locked]" or ""
|
||||
if u.locked then syscall.devctl(1,"sfgc",2) end
|
||||
if u.locked then syscall.devctl(1,"sfgc",0xFF0000) end
|
||||
print(string.format("%-6d %-6d %-16s %-20s %s%s",
|
||||
u.uid, u.gid, u.username, u.homedir, u.shell, lock_marker))
|
||||
if u.locked then syscall.devctl(1,"sfgc",1) end
|
||||
if u.locked then syscall.devctl(1,"sfgc",0xFFFFFF) end
|
||||
end
|
||||
@@ -69,17 +69,17 @@ if #args == 0 and not opts.o then
|
||||
end
|
||||
|
||||
if next(loDevs) == nil then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
print("(no loop devices attached)")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
for id, info in pairs(loDevs) do
|
||||
local colour = info.mode == "image" and 5 or 4
|
||||
local colour = info.mode == "image" and 0x00FFFF or 0x0000FF
|
||||
syscall.devctl(1, "sfgc", colour)
|
||||
printInline(info.mode.." "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
print(" on "..info.path)
|
||||
end
|
||||
return
|
||||
@@ -119,9 +119,9 @@ if opts.o and opts.o:lower() == "loop" then
|
||||
print(name..": mount: "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": "..loopId.." mounted at "..dest)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -141,9 +141,9 @@ if #args == 2 then
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": "..loopId.." mounted at "..dest)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
File renamed without changes.
@@ -1,6 +1,9 @@
|
||||
--:Minify:--
|
||||
local targetUser = ({ ... })[1]
|
||||
local currentUid = syscall.getuid()
|
||||
if syscall.geteuid()~=0 then
|
||||
syscall.exec("/bin/su", {...})
|
||||
end
|
||||
local targetUid
|
||||
if targetUser then
|
||||
targetUid = syscall.getuidbyname(targetUser)
|
||||
File renamed without changes.
@@ -59,9 +59,9 @@ if opts.l then
|
||||
end
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": detached "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -95,17 +95,17 @@ if not ok then
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": unmounted "..mpt)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
|
||||
if loopIdToDetach then
|
||||
for _, id in ipairs(loopIdToDetach) do
|
||||
local dok = pcall(syscall.lodetach, id)
|
||||
if dok then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
print(name..": auto-detached "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
File renamed without changes.
File renamed without changes.
Loaded 100 of 269 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user