1.2 dev #19
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
|
||||
File renamed without changes.
@@ -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)
|
||||
+3
-3
@@ -106,7 +106,7 @@ local ok, err = xpcall(function()
|
||||
|
||||
local file = {}
|
||||
|
||||
function file:read(n)
|
||||
function file.read(n)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
@@ -123,7 +123,7 @@ local ok, err = xpcall(function()
|
||||
return out
|
||||
end
|
||||
|
||||
function file:write(data)
|
||||
function file.write(data)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
@@ -136,7 +136,7 @@ local ok, err = xpcall(function()
|
||||
return true
|
||||
end
|
||||
|
||||
function file:seek(whence, offset)
|
||||
function file.seek(whence, offset)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
@@ -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
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-1
@@ -1,3 +1,6 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
kernel.unixSockets={}
|
||||
|
||||
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.EFI: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
|
||||
+115
-70
@@ -1,9 +1,8 @@
|
||||
--:Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
local os = os
|
||||
local function write(text)
|
||||
local lterm = term
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
@@ -49,18 +48,19 @@ local function write(text)
|
||||
end
|
||||
|
||||
local function displaySuperBadError(err)
|
||||
term.setBackgroundColor(0x1)
|
||||
term.setTextColor(0x4)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
term.write("A critical error occurred while loading the system:")
|
||||
term.setCursorPos(1, 3)
|
||||
write(err)
|
||||
while true do end
|
||||
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 = {
|
||||
@@ -101,6 +101,7 @@ local ok, err = xpcall(function()
|
||||
_G[i] = nil
|
||||
end
|
||||
end
|
||||
--p
|
||||
|
||||
local acekeys={
|
||||
[apis.keys.enter]="\n",
|
||||
@@ -172,22 +173,22 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
|
||||
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
|
||||
[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
|
||||
@@ -249,11 +250,12 @@ local ok, err = xpcall(function()
|
||||
return value
|
||||
end
|
||||
|
||||
local peripheral={}
|
||||
--p
|
||||
local p={}
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.getNames()
|
||||
function p.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
@@ -270,7 +272,7 @@ local ok, err = xpcall(function()
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
function p.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
@@ -284,7 +286,7 @@ local ok, err = xpcall(function()
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
function p.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
@@ -305,7 +307,7 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
function p.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
@@ -326,7 +328,7 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
function p.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
@@ -339,7 +341,7 @@ local ok, err = xpcall(function()
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
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)
|
||||
@@ -347,7 +349,7 @@ local ok, err = xpcall(function()
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
function p.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
@@ -361,13 +363,13 @@ local ok, err = xpcall(function()
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
function p.wrap(name)
|
||||
local methods = p.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
local types = { p.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
@@ -377,17 +379,17 @@ local ok, err = xpcall(function()
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
return p.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
function p.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
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
|
||||
@@ -395,13 +397,25 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local allscreens = {peripheral.find("monitor")}
|
||||
--p
|
||||
local allscreens = {p.find("monitor")}
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setTextScale(.5)
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1,1)
|
||||
allscreens[i].write("Initializing...")
|
||||
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 = {
|
||||
@@ -424,22 +438,38 @@ local ok, err = xpcall(function()
|
||||
initfs=fs,
|
||||
disks=initFs,
|
||||
screenCtl={
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
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()
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
setCursorPos = function(_, x, y)
|
||||
apis.term.setCursorPos(x, y)
|
||||
resetCursor = function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(aprox(color))
|
||||
bg=color
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setBackgroundColor(aprox(color))
|
||||
end
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(aprox(color))
|
||||
fg=color
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setTextColor(aprox(color))
|
||||
end
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return bg
|
||||
@@ -447,7 +477,12 @@ local ok, err = xpcall(function()
|
||||
getTextColor = function()
|
||||
return fg
|
||||
end,
|
||||
enable=function() end,
|
||||
enable=function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
@@ -468,7 +503,8 @@ local ok, err = xpcall(function()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
--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
|
||||
@@ -497,6 +533,7 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
|
||||
EFI.screenCtl:print("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
--p
|
||||
|
||||
while true do
|
||||
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||
@@ -505,28 +542,30 @@ local ok, err = xpcall(function()
|
||||
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] == "disk" then
|
||||
queueEvent("componentAdded", "disk")
|
||||
elseif event[1] == "disk_eject" then
|
||||
queueEvent("componentRemoved", "disk")
|
||||
elseif event[1] == "modem_message" then
|
||||
queueEvent("modem_message", table.unpack(event, 2))
|
||||
elseif event[1] == "rednet_message" then
|
||||
queueEvent("rednet_message", table.unpack(event, 2))
|
||||
elseif event[1] == "http_success" then
|
||||
queueEvent("http_success", table.unpack(event, 2))
|
||||
elseif event[1] == "http_failure" then
|
||||
queueEvent("http_failure", table.unpack(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
|
||||
@@ -535,6 +574,12 @@ local ok, err = xpcall(function()
|
||||
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
|
||||
File renamed without changes.
File renamed without changes.
+44
-1
@@ -3,6 +3,7 @@
|
||||
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
|
||||
@@ -103,6 +104,40 @@ function peripheral.getName(peripheral)
|
||||
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
|
||||
@@ -116,7 +151,7 @@ function peripheral.call(name, method, ...)
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
function peripheral.wrap(name, wrap)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
@@ -130,11 +165,19 @@ function peripheral.wrap(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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
+37
-6
@@ -144,7 +144,6 @@ local function write(text, term)
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
kernel.devfs.data.tty={}
|
||||
kernel.cct.ctrl,kernel.cct.alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
@@ -220,8 +219,8 @@ local function newtty(obj, id, ev)
|
||||
gbgc=function()
|
||||
return bg
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||
isvirt=function()
|
||||
return false
|
||||
end,
|
||||
gplt=function()
|
||||
return plt
|
||||
@@ -243,10 +242,42 @@ end
|
||||
local fifo = kernel.newFifo()
|
||||
kernel.cct.fifo=fifo
|
||||
|
||||
newtty(kernel.apis.term, "1", fifo.pop)
|
||||
newtty(kernel.apis.term, "1", function() end)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
v.setTextScale(.5)
|
||||
v.write("Initializing...")
|
||||
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
|
||||
+23
-1
@@ -1,9 +1,11 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local keys=kernel.apis.keys
|
||||
kernel.cct.eventhooks={}
|
||||
|
||||
kernel.processes.cctdeamon = function()
|
||||
kernel.processes.cctdaemon = function()
|
||||
local timeout = false
|
||||
kernel.log("CCT daemon started")
|
||||
while true do
|
||||
local event = {kernel.EFI:getMachineEvent()}
|
||||
|
||||
@@ -66,12 +68,30 @@ kernel.processes.cctdeamon = function()
|
||||
|
||||
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
|
||||
@@ -84,3 +104,5 @@ kernel.processes.cctdeamon = function()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("CCT daemon queued for execution")
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
firmware for ComputerCraft Tweaked
|
||||
@@ -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
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,6 @@
|
||||
--:Minify:--
|
||||
local EFI=...
|
||||
--pf
|
||||
EFI.beep(440, 500)
|
||||
local screen=EFI.screenCtl
|
||||
local ifs=EFI.initfs
|
||||
@@ -8,8 +9,9 @@ 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",[1]="User"}
|
||||
kernel.users={[0]="root",[1000]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
kernel.groups = {}
|
||||
kernel.uid = 0
|
||||
@@ -18,13 +20,15 @@ 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)
|
||||
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
|
||||
@@ -41,6 +45,12 @@ function kernel.log(msg, level, c)
|
||||
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)
|
||||
@@ -51,7 +61,7 @@ function kernel.PANIC(msg)
|
||||
screen:setTextColor(0xFF0000)
|
||||
screen:setBackgroundColor(0x000000)
|
||||
screen:clear()
|
||||
screen:setCursorPos(1,1)
|
||||
screen:resetCursor()
|
||||
screen:print(kernel.LOG_Text)
|
||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||
screen:print("Press any key to continue...")
|
||||
@@ -72,17 +82,11 @@ if windowsExp then
|
||||
screen:setTextColor(0xFFFFFF)
|
||||
screen:setBackgroundColor(0x0000FF)
|
||||
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: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: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")
|
||||
screen:print("\n\n\n Stop code: average windows experience")
|
||||
while true do end
|
||||
end
|
||||
|
||||
@@ -190,6 +194,100 @@ function kernel.newUUID()
|
||||
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
|
||||
@@ -205,20 +303,24 @@ for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
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
|
||||
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",
|
||||
@@ -251,9 +353,24 @@ function kernel.reboot()
|
||||
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
|
||||
@@ -268,14 +385,35 @@ kernel.syscalls["sysdump"]=function()
|
||||
end
|
||||
return rv
|
||||
end
|
||||
kernel.syscalls["reboot"]=kernel.reboot
|
||||
kernel.syscalls["shutdown"]=kernel.shutdown
|
||||
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(v)
|
||||
local code=ifs.readAllText("/lib/modules/"..v)
|
||||
if not code then
|
||||
kernel.panic("Failed to read module "..v)
|
||||
end
|
||||
@@ -284,18 +422,30 @@ for _,p in ipairs(modules) do
|
||||
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()
|
||||
kernel.main()
|
||||
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
|
||||
@@ -8,5 +8,4 @@ return {
|
||||
maxOpenFiles = 128,
|
||||
maxFilesPerTask = 16,
|
||||
preempt = true,
|
||||
logTaskExit=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, {
|
||||
+112
-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
|
||||
@@ -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
|
||||
@@ -549,27 +556,88 @@ function vfs.newfd(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)
|
||||
local drive, path = resolvePath(target)
|
||||
if not drive:directoryExists(path) then drive:makeDirectory(path) end
|
||||
if drive:type(target) ~= "directory" then error("EINVAL") end
|
||||
|
||||
if not drive:directoryExists(path) then
|
||||
drive:makeDirectory(path)
|
||||
end
|
||||
if drive:type(path) ~= "directory" then
|
||||
error("EINVAL")
|
||||
end
|
||||
local disk, id
|
||||
-- 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 = kernel.disks[diskOrId]
|
||||
disk = vfs.disks[diskOrId]
|
||||
if not disk then error("ENODEV") end
|
||||
checkDisk(disk); id = diskOrId
|
||||
checkDisk(disk)
|
||||
id = diskOrId
|
||||
elseif type(diskOrId) == "table" then
|
||||
checkDisk(diskOrId); disk = diskOrId
|
||||
id = disk.address; vfs.disks[id] = disk
|
||||
else error("EINVAL") end
|
||||
|
||||
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")
|
||||
@@ -596,8 +668,8 @@ function vfs.open(path, mode)
|
||||
if not disk then error("NODISK") end
|
||||
if (mode=="w" or mode=="a") and disk:isReadOnly() then error("ERDONLY") end
|
||||
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
local meta = kernel.unixSockets[normalizePath(path)].meta
|
||||
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
|
||||
@@ -606,7 +678,7 @@ function vfs.open(path, mode)
|
||||
end
|
||||
if not access then error("EACCES") end
|
||||
end
|
||||
task[fd]=kernel.unixSockets[normalizePath(path)]
|
||||
task[fd]=kernel.unixSockets[namei(path)]
|
||||
return fd
|
||||
end
|
||||
|
||||
@@ -618,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
|
||||
@@ -711,12 +785,11 @@ end
|
||||
|
||||
function vfs.stat(path)
|
||||
local attrs
|
||||
local meta
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
if meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(path)
|
||||
meta = getFileMeta(path)
|
||||
local ok
|
||||
ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||
@@ -856,13 +929,13 @@ function vfs.remove(path)
|
||||
|
||||
local meta = getFileMeta(path, true)
|
||||
|
||||
if kernel.unixSockets and kernel.unixSockets[normalizePath(path)] then
|
||||
if kernel.unixSockets[namei(path)] then
|
||||
if kernel.uid ~= 0 then
|
||||
if kernel.unixSockets[normalizePath(path)].meta.owner~=kernel.uid then
|
||||
if kernel.unixSockets[namei(path)].meta.owner~=kernel.uid then
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
kernel.unixSockets[normalizePath(path)] = nil
|
||||
kernel.unixSockets[namei(path)] = nil
|
||||
end
|
||||
|
||||
if meta.etype == 0x01 then
|
||||
@@ -973,7 +1046,7 @@ local function updateMeta(path, fn, noFollow)
|
||||
end
|
||||
|
||||
function vfs.chmod(path, perms)
|
||||
if kernel.unixSockets[normalizePath(path)] then error("EINVAL") end
|
||||
if kernel.unixSockets[namei(path)] then error("EINVAL") end
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local meta = getFileMeta(path)
|
||||
@@ -985,12 +1058,12 @@ end
|
||||
function vfs.fchmod(fd, perms)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.etype==0x02 then error("EINVAL") 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[normalizePath(path)] then error("EINVAL") end
|
||||
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
|
||||
@@ -1001,14 +1074,14 @@ end
|
||||
function vfs.fchown(fd, uid, gid)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.etype==0x02 then error("EINVAL") end
|
||||
if file.meta.etype==0x02 then error("EINVAL") end
|
||||
vfs.chown(file.path, uid, gid)
|
||||
end
|
||||
|
||||
function vfs.exists(path)
|
||||
if kernel.unixSockets[normalizePath(path)] then return true end
|
||||
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
|
||||
if disk:type(diskPath) then
|
||||
@@ -1021,7 +1094,7 @@ end
|
||||
function vfs.type(path)
|
||||
local meta = getFileMeta(path, true)
|
||||
if meta.etype == 0x01 then return "symlink" end
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
if kernel.unixSockets[namei(path)] then
|
||||
return "socket"
|
||||
end
|
||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||
@@ -1076,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
|
||||
@@ -1108,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
|
||||
+94
-8
@@ -50,7 +50,7 @@ function proxy:type(path, mode)
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return "directory"
|
||||
end
|
||||
error(type(step[steps[#steps]]))
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
@@ -140,11 +140,91 @@ function data.zero(op, mode)
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI:getEEPROM() then
|
||||
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 {
|
||||
@@ -154,7 +234,6 @@ if kernel.EFI:getEEPROM() then
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
@@ -166,7 +245,6 @@ if kernel.EFI:getEEPROM() then
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||
@@ -178,11 +256,12 @@ if kernel.EFI:getEEPROM() then
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI:getNvram() then
|
||||
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 {
|
||||
@@ -192,7 +271,6 @@ if kernel.EFI:getNvram() then
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
@@ -204,7 +282,6 @@ if kernel.EFI:getNvram() then
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||
@@ -216,7 +293,16 @@ if kernel.EFI:getNvram() then
|
||||
end
|
||||
end
|
||||
|
||||
data["disk"]={}
|
||||
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
|
||||
+2
-1
@@ -114,7 +114,8 @@ local function newtaskproxy(task)
|
||||
},
|
||||
children={
|
||||
[".meta"]=strFile(buildMeta(children))
|
||||
}
|
||||
},
|
||||
pid=strFile(task.pid)
|
||||
}
|
||||
end
|
||||
|
||||
@@ -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.
+2
-1
@@ -25,10 +25,11 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
||||
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
|
||||
File renamed without changes.
@@ -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
|
||||
File renamed without changes.
+76
-12
@@ -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)
|
||||
@@ -150,7 +150,6 @@ function sys.exec(path, args, envars)
|
||||
tasks[tostring(task.pid)].status = "Z"
|
||||
end)
|
||||
task.syscallReturn = {}
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
function sys.sleep(s)
|
||||
@@ -203,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
|
||||
@@ -223,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
|
||||
if task.status == "S" then
|
||||
task.status = "ST"
|
||||
else
|
||||
task.status = "T"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -235,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
|
||||
if task.status == "ST" then
|
||||
task.status = "S"
|
||||
else
|
||||
task.status = "R"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -289,6 +304,7 @@ 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
|
||||
if task.pid == 1 then kernel.panic("Attempted to gc init!") end
|
||||
task.coro = nil
|
||||
task.ivs = nil
|
||||
task.vs = nil
|
||||
@@ -334,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
|
||||
@@ -342,6 +374,7 @@ function kernel.main()
|
||||
local taskTimes = {}
|
||||
|
||||
for pid, task in pairs(tasks) do
|
||||
if kernel.exitMain then break end
|
||||
kernel.currentTask = task
|
||||
kernel.uid = task.euid or task.uid
|
||||
kernel.process = task.name
|
||||
@@ -351,9 +384,28 @@ function kernel.main()
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
if task.status == "ST" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||
task.status = "T"
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
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.ksh then
|
||||
coroutine.resume(task.ksh)
|
||||
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
|
||||
|
||||
@@ -364,14 +416,19 @@ function kernel.main()
|
||||
|
||||
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
||||
local coro = coroutine.create(task.sigh)
|
||||
local status,err=coroutine.resumeWithTimeout(coro, 100, table.remove(task.sigq, 1))
|
||||
if status=="error" then
|
||||
task.sigd.error=err
|
||||
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" then
|
||||
elseif status=="success" or status==true then
|
||||
if err=="syscall" then
|
||||
task.sigd.error="Cannot execute syscalls from signals"
|
||||
task.sigd.active=false
|
||||
@@ -385,7 +442,9 @@ function kernel.main()
|
||||
if task.status == "R" then
|
||||
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
|
||||
if not task.debugger then
|
||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||
@@ -471,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.
File renamed without changes.
+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
|
||||
+1
@@ -25,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
|
||||
File renamed without changes.
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,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,58 +0,0 @@
|
||||
--:Minify:--
|
||||
-- Supports:
|
||||
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
||||
-- AF_INET - network sockets with three backends:
|
||||
-- Implemented by drivers but expect http:// and https://
|
||||
--
|
||||
-- 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 socket={}
|
||||
socket.handlers={}
|
||||
kernel.socket=socket
|
||||
|
||||
function socket.registerProtocal(protocal, handler)
|
||||
socket.handlers[protocal] = handler
|
||||
end
|
||||
|
||||
function socket.socket()
|
||||
local P=kernel.vfs.P
|
||||
local data=kernel.newFifo()
|
||||
local isClosed=false
|
||||
kernel.vfs.newfd({
|
||||
handle={
|
||||
read=function() if isClosed then error("ECCON") end return data.read() end,
|
||||
write=function() if isClosed then error("ECCON") end return data.write() end,
|
||||
close=function() isClosed = true end
|
||||
},
|
||||
type="socket",
|
||||
refcount=1,
|
||||
|
||||
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
|
||||
})
|
||||
end
|
||||
|
||||
function socket.connect(fd, address)
|
||||
|
||||
end
|
||||
|
||||
function socket.listen(fd, backlog)
|
||||
|
||||
end
|
||||
|
||||
kernel.log("Loaded socket module")
|
||||
@@ -1,10 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
if not kernel.vfs.exists("/root") then kernel.vfs.mkdir("/root") end
|
||||
|
||||
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", 0xFF0000)
|
||||
end
|
||||
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)
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,169 @@
|
||||
--:Minify:--
|
||||
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)
|
||||
|
||||
|
||||
local MAX_ATTEMPTS = 3
|
||||
|
||||
local function readLine(mask)
|
||||
local input = ""
|
||||
while true do
|
||||
local ch = syscall.read(0)
|
||||
if not ch or ch == "" then
|
||||
elseif ch == "\n" then
|
||||
syscall.write(1, "\n")
|
||||
return input
|
||||
elseif ch == "\b" then
|
||||
if #input > 0 then
|
||||
input = input:sub(1, -2)
|
||||
syscall.write(1, "\b \b")
|
||||
end
|
||||
else
|
||||
input = input .. ch
|
||||
syscall.write(1, mask or ch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function firstBoot()
|
||||
local shadow = ""
|
||||
local _fd, _fderr = pcall(function()
|
||||
local fd = syscall.open("/etc/shadow", "r")
|
||||
shadow = syscall.read(fd, 65535) or ""
|
||||
syscall.close(fd)
|
||||
end)
|
||||
if shadow:match("%S") then return end
|
||||
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "HyperionOS First Boot Setup\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "No root password is set. Please create one now.\n\n")
|
||||
|
||||
while true do
|
||||
syscall.write(1, "New root password: ")
|
||||
local pw1 = readLine("*")
|
||||
syscall.write(1, "Confirm password: ")
|
||||
local pw2 = readLine("*")
|
||||
|
||||
if pw1 ~= pw2 then
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Passwords do not match. Try again.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
elseif #pw1 < 6 then
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Password too short (minimum 6 characters).\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
else
|
||||
local ok, err = syscall.setpassword(0, pw1)
|
||||
if ok then
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "Root password set.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.5)
|
||||
break
|
||||
else
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function spawnShell(username, uid, shell, homedir)
|
||||
local existsOk, existsErr = pcall(syscall.exists, shell)
|
||||
if not existsOk or not existsErr then
|
||||
syscall.write(1, "login: shell not found: " .. shell .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
local accessOk, accessErr = pcall(syscall.access, shell, "rx")
|
||||
|
||||
syscall.setEnviron("HOME", homedir)
|
||||
syscall.setEnviron("USER", username)
|
||||
syscall.setEnviron("SHELL", shell)
|
||||
syscall.setEnviron("PATH", "/bin/")
|
||||
|
||||
local setuidOk, setuidErr = pcall(syscall.setuid, uid)
|
||||
if not setuidOk then
|
||||
syscall.write(1, "login: setuid failed: " .. tostring(setuidErr) .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
local chdirOk, chdirErr = pcall(syscall.chdir, homedir)
|
||||
if not chdirOk then
|
||||
pcall(syscall.chdir, "/")
|
||||
end
|
||||
|
||||
local ok, err = pcall(syscall.execspawn, shell, username .. ":shell")
|
||||
if not ok then
|
||||
syscall.write(1, "login: failed to launch shell: " .. tostring(err) .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
syscall.exit(0)
|
||||
end
|
||||
|
||||
local function doLogin()
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
|
||||
local hostname = syscall.getHostname() or "hyperion"
|
||||
syscall.write(1, "HyperionOS\n")
|
||||
syscall.write(1, hostname .. " login\n\n")
|
||||
|
||||
local attempts = 0
|
||||
while attempts < MAX_ATTEMPTS do
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "Username: ")
|
||||
local username = readLine(nil)
|
||||
|
||||
if username ~= "" then
|
||||
|
||||
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 shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
|
||||
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", 0xFF0000)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Maximum login attempts exceeded.\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(5)
|
||||
end
|
||||
|
||||
firstBoot()
|
||||
while true do
|
||||
doLogin()
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
core utilities for user management
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Haoqian He
|
||||
@@ -315,7 +315,9 @@ end
|
||||
|
||||
-- CRC-16/CRC-32 computation
|
||||
local band, bnot, xor, lshift, rshift
|
||||
|
||||
local bit32
|
||||
local ok, temp = pcall(require, "bit32")
|
||||
if ok then bit32=temp end
|
||||
if bit ~= nil then
|
||||
band = bit.band
|
||||
bnot = bit.bnot
|
||||
Loaded 100 of 346 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user