Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b79492dbb8 | ||
|
|
bc87c53427 | ||
|
|
030e5bfd96 | ||
|
|
099638c735 | ||
|
|
5172da1b5b |
Vendored
+1
-5
@@ -6,10 +6,6 @@
|
|||||||
"printf",
|
"printf",
|
||||||
"printInline",
|
"printInline",
|
||||||
"toHex",
|
"toHex",
|
||||||
"loadcstr",
|
"loadcstr"
|
||||||
"userinput"
|
|
||||||
],
|
|
||||||
"Lua.diagnostics.disable": [
|
|
||||||
"need-check-nil"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,202 +1,18 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
Apache License
|
Copyright (c) 2025 Astronand
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
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:
|
||||||
|
|
||||||
1. Definitions.
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||||
|
portions of the Software.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
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
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
the copyright owner that is granting the License.
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
"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,10 +15,8 @@ See `building.md`.
|
|||||||
|
|
||||||
- Functionality is split into kernel modules (`.kmod`)
|
- Functionality is split into kernel modules (`.kmod`)
|
||||||
- Task-based lightweight thread/task preemptive scheduler with process isolation and IPC support
|
- Task-based lightweight thread/task preemptive scheduler with process isolation and IPC support
|
||||||
- Virtual filesystem
|
- Virtual filesystem unified interface for disk, RAM, and virtual filesystems
|
||||||
- TTY & Shell
|
- TTY & Shell
|
||||||
- Sockets
|
|
||||||
-
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -50,12 +48,6 @@ Add your name to `contributors.md` when your PR is merged.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Information
|
|
||||||
|
|
||||||
Trello: https://trello.com/b/8dryrlMi
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License. See the LICENSE file for details.
|
This project is licensed under the MIT License. See the LICENSE file for details.
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Core library for Hyperion
|
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local fs={}
|
local fs={}
|
||||||
|
|
||||||
|
-- "open" : open
|
||||||
|
-- "read" : read
|
||||||
|
-- "write" : write
|
||||||
|
-- "close" : close
|
||||||
|
|
||||||
function fs.open(path, mode)
|
function fs.open(path, mode)
|
||||||
local fd=syscall.open(path,mode)
|
local fd=syscall.open(path,mode)
|
||||||
local ret={
|
local ret={
|
||||||
@@ -135,12 +140,4 @@ function fs.isDir(path)
|
|||||||
return syscall.type(path) == "directory"
|
return syscall.type(path) == "directory"
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.symlink(target, path)
|
|
||||||
return syscall.syslink(target, path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.readlink(path)
|
|
||||||
return syscall.readlink(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
return fs
|
return fs
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
GHXX (Advanced Computers)
|
|
||||||
+3
-3
@@ -106,7 +106,7 @@ local ok, err = xpcall(function()
|
|||||||
|
|
||||||
local file = {}
|
local file = {}
|
||||||
|
|
||||||
function file.read(n)
|
function file:read(n)
|
||||||
assert(not closed, "file is closed")
|
assert(not closed, "file is closed")
|
||||||
|
|
||||||
local s = content()
|
local s = content()
|
||||||
@@ -123,7 +123,7 @@ local ok, err = xpcall(function()
|
|||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
function file.write(data)
|
function file:write(data)
|
||||||
assert(not closed, "file is closed")
|
assert(not closed, "file is closed")
|
||||||
|
|
||||||
local s = content()
|
local s = content()
|
||||||
@@ -136,7 +136,7 @@ local ok, err = xpcall(function()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function file.seek(whence, offset)
|
function file:seek(whence, offset)
|
||||||
assert(not closed, "file is closed")
|
assert(not closed, "file is closed")
|
||||||
|
|
||||||
local s = content()
|
local s = content()
|
||||||
@@ -1 +0,0 @@
|
|||||||
firmware for Advanced Computers
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
|
|
||||||
local kbs = {kernel.cct.peripheral.find("tm_keyboard")}
|
|
||||||
|
|
||||||
|
|
||||||
kernel.cct.eventhooks["tm_keyboard_char"]=function(...)
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
+2
-2
@@ -321,7 +321,7 @@ local ok, err = xpcall(function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function EFI.resumeWithTimeout(co, timeout, ...)
|
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||||
local startTime = EFI.getEpochMs()
|
local startTime = EFI.getEpochMs()
|
||||||
debug.sethook(co, function()
|
debug.sethook(co, function()
|
||||||
if EFI.getEpochMs() > startTime + timeout then
|
if EFI.getEpochMs() > startTime + timeout then
|
||||||
@@ -342,7 +342,7 @@ local ok, err = xpcall(function()
|
|||||||
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local status, err = EFI.resumeWithTimeout(kernelCoro, 50)
|
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||||
apis.os.queueEvent("NoSleep")
|
apis.os.queueEvent("NoSleep")
|
||||||
local exit = false
|
local exit = false
|
||||||
while not exit do
|
while not exit do
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
|
|
||||||
if kernel.gfx then
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
firmware for CraftOS PC
|
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
--: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
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||||
|
---@diagnostic disable-next-line: undefined-global
|
||||||
|
local term = term
|
||||||
|
local os = os
|
||||||
|
local function write(text)
|
||||||
|
local x, y = term.getCursorPos()
|
||||||
|
local w, h = term.getSize()
|
||||||
|
|
||||||
|
for i = 1, #text do
|
||||||
|
local c = text:sub(i, i)
|
||||||
|
|
||||||
|
if c == "\n" then
|
||||||
|
y = y + 1
|
||||||
|
x = 1
|
||||||
|
elseif c == "\t" then
|
||||||
|
local tabSize = 4
|
||||||
|
local spaces = tabSize - ((x - 1) % tabSize)
|
||||||
|
term.write(string.rep(" ", spaces))
|
||||||
|
x = x + spaces
|
||||||
|
elseif c == "\b" then
|
||||||
|
if x > 1 then
|
||||||
|
x = x - 1
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(" ")
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if x <= w and y <= h then
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(c)
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x > w then
|
||||||
|
x = 1
|
||||||
|
y = y + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if y - 1 >= h then
|
||||||
|
term.scroll(1)
|
||||||
|
y = h
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setCursorBlink(false)
|
||||||
|
local ok, err = xpcall(function()
|
||||||
|
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
||||||
|
|
||||||
|
local lua = {
|
||||||
|
coroutine = true,
|
||||||
|
debug = true,
|
||||||
|
_VERSION = true,
|
||||||
|
assert = true,
|
||||||
|
collectgarbage = true,
|
||||||
|
error = true,
|
||||||
|
gcinfo = true,
|
||||||
|
getmetatable = true,
|
||||||
|
ipairs = true,
|
||||||
|
__inext = true,
|
||||||
|
load = true,
|
||||||
|
math = true,
|
||||||
|
next = true,
|
||||||
|
pairs = true,
|
||||||
|
pcall = true,
|
||||||
|
rawequal = true,
|
||||||
|
rawget = true,
|
||||||
|
rawlen = true,
|
||||||
|
rawset = true,
|
||||||
|
select = true,
|
||||||
|
setmetatable = true,
|
||||||
|
string = true,
|
||||||
|
table = true,
|
||||||
|
tonumber = true,
|
||||||
|
tostring = true,
|
||||||
|
type = true,
|
||||||
|
xpcall = true,
|
||||||
|
_G = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local debug = debug
|
||||||
|
for i, v in pairs(_G) do
|
||||||
|
if not lua[i] or lua[i] == nil then
|
||||||
|
apis[i] = v
|
||||||
|
_G[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local acekeys={
|
||||||
|
[apis.keys.enter]="\n",
|
||||||
|
[apis.keys.tab]="\t",
|
||||||
|
[apis.keys.backspace]="\b",
|
||||||
|
[apis.keys.up]="\17",
|
||||||
|
[apis.keys.down]="\18",
|
||||||
|
[apis.keys.left]="\19",
|
||||||
|
[apis.keys.right]="\20",
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(time)
|
||||||
|
local stoptime = apis.os.clock() + (time)
|
||||||
|
while stoptime > apis.os.clock() do end
|
||||||
|
end
|
||||||
|
|
||||||
|
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||||
|
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||||
|
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||||
|
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||||
|
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||||
|
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||||
|
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||||
|
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||||
|
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||||
|
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||||
|
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||||
|
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||||
|
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||||
|
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||||
|
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||||
|
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||||
|
|
||||||
|
local function getFile(path)
|
||||||
|
local file = apis.fs.open(path, "r")
|
||||||
|
if not file then
|
||||||
|
displaySuperBadError("Could not open file: " .. path)
|
||||||
|
end
|
||||||
|
local content = file.readAll()
|
||||||
|
file.close()
|
||||||
|
return content
|
||||||
|
end
|
||||||
|
|
||||||
|
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
|
||||||
|
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
|
||||||
|
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
|
||||||
|
|
||||||
|
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
||||||
|
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||||
|
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||||
|
|
||||||
|
if not apis.fs.exists("/nvram.dat") then
|
||||||
|
local file = apis.fs.open("/nvram.dat", "w")
|
||||||
|
file.write("Hello, World!")
|
||||||
|
file.close()
|
||||||
|
end
|
||||||
|
|
||||||
|
local eeprom
|
||||||
|
if apis.fs.exists("/startup.lua") then
|
||||||
|
eeprom="/startup.lua"
|
||||||
|
elseif apis.fs.exists("/eeprom") then
|
||||||
|
eeprom="/eeprom"
|
||||||
|
end
|
||||||
|
|
||||||
|
local eventQueue = {}
|
||||||
|
|
||||||
|
local function queueEvent(event, ...)
|
||||||
|
table.insert(eventQueue, {event, ...})
|
||||||
|
end
|
||||||
|
|
||||||
|
local colors = {
|
||||||
|
[0x000000]=0x0001,
|
||||||
|
[0xFFFFFF]=0x0002,
|
||||||
|
[0xFF0000]=0x0004,
|
||||||
|
[0x00FF00]=0x0008,
|
||||||
|
[0x0000FF]=0x0010,
|
||||||
|
[0x00FFFF]=0x0020,
|
||||||
|
[0xFF00FF]=0x0040,
|
||||||
|
[0xFFFF00]=0x0080,
|
||||||
|
[0xFF6D00]=0x0100,
|
||||||
|
[0x6DFF55]=0x0200,
|
||||||
|
[0x24FFFF]=0x0400,
|
||||||
|
[0x924900]=0x0800,
|
||||||
|
[0x6D6D55]=0x1000,
|
||||||
|
[0xDBDBAA]=0x2000,
|
||||||
|
[0x6D00FF]=0x4000,
|
||||||
|
[0xB6FF00]=0x8000
|
||||||
|
}
|
||||||
|
|
||||||
|
local fg,bg=0x6D6D55,0x000000
|
||||||
|
local l1f,l1d,l2,ops={},{},{},0
|
||||||
|
|
||||||
|
local function findClosest(tbl, target)
|
||||||
|
local closest = nil
|
||||||
|
local smallestDiff = math.huge
|
||||||
|
|
||||||
|
for k, _ in pairs(tbl) do
|
||||||
|
local diff = math.abs(k - target)
|
||||||
|
if diff < smallestDiff then
|
||||||
|
smallestDiff = diff
|
||||||
|
closest = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return closest
|
||||||
|
end
|
||||||
|
|
||||||
|
local function aprox(c24)
|
||||||
|
ops = ops + 1
|
||||||
|
|
||||||
|
if ops % 1024 == 0 then
|
||||||
|
l1d = {}
|
||||||
|
l1f = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
if ops % 8192 == 0 then
|
||||||
|
l2 = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
if l2[c24] ~= nil then
|
||||||
|
return l2[c24]
|
||||||
|
end
|
||||||
|
|
||||||
|
if l1d[c24] ~= nil then
|
||||||
|
l1f[c24] = l1f[c24] + 1
|
||||||
|
|
||||||
|
if l1f[c24] >= 16 then
|
||||||
|
l2[c24] = l1d[c24]
|
||||||
|
l1d[c24] = nil
|
||||||
|
l1f[c24] = nil
|
||||||
|
return l2[c24]
|
||||||
|
end
|
||||||
|
|
||||||
|
return l1d[c24]
|
||||||
|
end
|
||||||
|
|
||||||
|
local closestKey = findClosest(colors, c24)
|
||||||
|
if not closestKey then return nil end
|
||||||
|
|
||||||
|
local value = colors[closestKey]
|
||||||
|
|
||||||
|
l1d[c24] = value
|
||||||
|
l1f[c24] = 1
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
local EFI = {
|
||||||
|
getEpochMs = function() return apis.os.epoch("utc") end,
|
||||||
|
getUptime = function() return apis.os.clock() * 1000 end,
|
||||||
|
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
||||||
|
getMachineEvent = function()
|
||||||
|
if #eventQueue > 0 then
|
||||||
|
return table.unpack(table.remove(eventQueue, 1))
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
getEEPROM = function() return getFile(eeprom) end,
|
||||||
|
setEEPROM = function(_, text)
|
||||||
|
local h = apis.fs.open(eeprom, "w")
|
||||||
|
h.write(text)
|
||||||
|
h.close()
|
||||||
|
end,
|
||||||
|
initfs=fs,
|
||||||
|
disks=initFs,
|
||||||
|
screenCtl={
|
||||||
|
print = function(_, text) write(text .. "\n") end,
|
||||||
|
printInline = function(_, text) write(text) end,
|
||||||
|
clear = function()
|
||||||
|
apis.term.clear()
|
||||||
|
apis.term.setCursorPos(1, 1)
|
||||||
|
end,
|
||||||
|
setCursorPos = function(_, x, y)
|
||||||
|
apis.term.setCursorPos(x, y)
|
||||||
|
end,
|
||||||
|
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||||
|
getSize = function() return apis.term.getSize() end,
|
||||||
|
setBackgroundColor = function(_, color)
|
||||||
|
apis.term.setBackgroundColor(aprox(color))
|
||||||
|
end,
|
||||||
|
setTextColor = function(_, color)
|
||||||
|
apis.term.setTextColor(aprox(color))
|
||||||
|
end,
|
||||||
|
getBackgroundColor = function()
|
||||||
|
return bg
|
||||||
|
end,
|
||||||
|
getTextColor = function()
|
||||||
|
return fg
|
||||||
|
end,
|
||||||
|
enable=function() end,
|
||||||
|
disable=function() end
|
||||||
|
},
|
||||||
|
architecture="cct",
|
||||||
|
getNvram = function() return getFile("/nvram.dat") end,
|
||||||
|
setNvram = function(_, text)
|
||||||
|
local h = apis.fs.open("/nvram.dat", "w")
|
||||||
|
h.write(text)
|
||||||
|
h.close()
|
||||||
|
end,
|
||||||
|
firmware=apis,
|
||||||
|
reboot=false
|
||||||
|
}
|
||||||
|
|
||||||
|
apis.term.setBackgroundColor(0x8000)
|
||||||
|
apis.term.setTextColor(0x1000)
|
||||||
|
apis.term.clear()
|
||||||
|
apis.term.setCursorPos(1, 1)
|
||||||
|
|
||||||
|
local kernelCoro = coroutine.create(function()
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
|
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
||||||
|
if not ok and not EFI.reboot then displaySuperBadError(err) end
|
||||||
|
if err then
|
||||||
|
apis.os.reboot()
|
||||||
|
else
|
||||||
|
apis.os.shutdown()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||||
|
local startTime = EFI.getEpochMs()
|
||||||
|
debug.sethook(co, function()
|
||||||
|
if EFI.getEpochMs() > startTime + timeout then
|
||||||
|
return coroutine.yield("timeout")
|
||||||
|
end
|
||||||
|
end, "", 1000)
|
||||||
|
local ret = {coroutine.resume(co, ...)}
|
||||||
|
if ret[1] and ret[2] == "timeout" then
|
||||||
|
return "timeout"
|
||||||
|
elseif ret[1] == false then
|
||||||
|
return "error", ret[2]
|
||||||
|
else
|
||||||
|
debug.sethook(co)
|
||||||
|
return "success", table.unpack(ret, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||||
|
apis.os.queueEvent("NoSleep")
|
||||||
|
local exit = false
|
||||||
|
while not exit do
|
||||||
|
local event = {coroutine.yield()}
|
||||||
|
if event[1] == "key" then
|
||||||
|
queueEvent("keyPressed", 1, event[2])
|
||||||
|
if acekeys[event[2]] then
|
||||||
|
queueEvent("keyTyped", 1, acekeys[event[2]])
|
||||||
|
end
|
||||||
|
elseif event[1] == "char" then
|
||||||
|
queueEvent("keyTyped", 1, event[2])
|
||||||
|
elseif event[1] == "key_up" then
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||||
|
if EFI.reboot then
|
||||||
|
apis.os.reboot()
|
||||||
|
end
|
||||||
|
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||||
|
coroutine.yield("key")
|
||||||
|
end
|
||||||
|
initFs:refresh()
|
||||||
|
end
|
||||||
|
end, debug.traceback)
|
||||||
|
|
||||||
|
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||||
|
while true do coroutine.yield("key") end
|
||||||
+3
-3
@@ -58,11 +58,11 @@ function _G.term.native()
|
|||||||
term.setCursorPos(1, 1)
|
term.setCursorPos(1, 1)
|
||||||
term.setCursorBlink(true)
|
term.setCursorBlink(true)
|
||||||
term.clear()
|
term.clear()
|
||||||
local file = fs.open(BOOT_DRIVE_PATH.."/cct/boot.lua", "r")
|
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
|
||||||
if file == nil then
|
if file == nil then
|
||||||
term.setCursorBlink(false)
|
term.setCursorBlink(false)
|
||||||
term.setTextColor(16384)
|
term.setTextColor(16384)
|
||||||
term.write("Could not find /cct/boot.lua. UnBIOS cannot continue.")
|
term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")
|
||||||
term.setCursorPos(1, 2)
|
term.setCursorPos(1, 2)
|
||||||
term.write("Press any key to continue")
|
term.write("Press any key to continue")
|
||||||
coroutine.yield("key")
|
coroutine.yield("key")
|
||||||
@@ -73,7 +73,7 @@ function _G.term.native()
|
|||||||
if fn == nil then
|
if fn == nil then
|
||||||
term.setCursorBlink(false)
|
term.setCursorBlink(false)
|
||||||
term.setTextColor(16384)
|
term.setTextColor(16384)
|
||||||
term.write("Could not load /cc/boot.lua. UnBIOS cannot continue.")
|
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
|
||||||
term.setCursorPos(1, 2)
|
term.setCursorPos(1, 2)
|
||||||
term.write(err)
|
term.write(err)
|
||||||
term.setCursorPos(1, 3)
|
term.setCursorPos(1, 3)
|
||||||
+1
-16
@@ -250,21 +250,6 @@ internal["rom"] = createDisk("rom", "/rom", true, {
|
|||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
internal["root"] = createDisk("root", "/root", false, {
|
|
||||||
setLabel = function(label)
|
|
||||||
local h = fs.open("/.rootlabel", "w")
|
|
||||||
h.write(label)
|
|
||||||
h.close()
|
|
||||||
end,
|
|
||||||
getLabel = function()
|
|
||||||
local h = fs.open("/.rootlabel", "r")
|
|
||||||
if not h then return "$" end
|
|
||||||
local label = h.readAll()
|
|
||||||
h.close()
|
|
||||||
return label
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
local function refresh()
|
local function refresh()
|
||||||
disks={}
|
disks={}
|
||||||
for _, disk in ipairs({peripheral.find("drive")}) do
|
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||||
@@ -273,7 +258,7 @@ local function refresh()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function iter()
|
local function iter()
|
||||||
refresh()
|
refresh()
|
||||||
local combined = {}
|
local combined = {}
|
||||||
@@ -1,589 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
|
||||||
---@diagnostic disable-next-line: undefined-global
|
|
||||||
local lterm = term
|
|
||||||
local function write(text, term)
|
|
||||||
local x, y = term.getCursorPos()
|
|
||||||
local w, h = term.getSize()
|
|
||||||
|
|
||||||
for i = 1, #text do
|
|
||||||
local c = text:sub(i, i)
|
|
||||||
|
|
||||||
if c == "\n" then
|
|
||||||
y = y + 1
|
|
||||||
x = 1
|
|
||||||
elseif c == "\t" then
|
|
||||||
local tabSize = 4
|
|
||||||
local spaces = tabSize - ((x - 1) % tabSize)
|
|
||||||
term.write(string.rep(" ", spaces))
|
|
||||||
x = x + spaces
|
|
||||||
elseif c == "\b" then
|
|
||||||
if x > 1 then
|
|
||||||
x = x - 1
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
term.write(" ")
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if x <= w and y <= h then
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
term.write(c)
|
|
||||||
x = x + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if x > w then
|
|
||||||
x = 1
|
|
||||||
y = y + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if y - 1 >= h then
|
|
||||||
term.scroll(1)
|
|
||||||
y = h
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function displaySuperBadError(err, noyield)
|
|
||||||
lterm.setBackgroundColor(0x1)
|
|
||||||
lterm.setTextColor(0x4)
|
|
||||||
lterm.clear()
|
|
||||||
lterm.setCursorPos(1, 1)
|
|
||||||
lterm.write("A critical error occurred while loading the system:")
|
|
||||||
lterm.setCursorPos(1, 3)
|
|
||||||
write(err, lterm)
|
|
||||||
coroutine.yield("key")
|
|
||||||
end
|
|
||||||
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
local ok, err = xpcall(function()
|
|
||||||
--p
|
|
||||||
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
|
||||||
|
|
||||||
local lua = {
|
|
||||||
coroutine = true,
|
|
||||||
debug = true,
|
|
||||||
_VERSION = true,
|
|
||||||
assert = true,
|
|
||||||
collectgarbage = true,
|
|
||||||
error = true,
|
|
||||||
gcinfo = true,
|
|
||||||
getmetatable = true,
|
|
||||||
ipairs = true,
|
|
||||||
__inext = true,
|
|
||||||
load = true,
|
|
||||||
math = true,
|
|
||||||
next = true,
|
|
||||||
pairs = true,
|
|
||||||
pcall = true,
|
|
||||||
rawequal = true,
|
|
||||||
rawget = true,
|
|
||||||
rawlen = true,
|
|
||||||
rawset = true,
|
|
||||||
select = true,
|
|
||||||
setmetatable = true,
|
|
||||||
string = true,
|
|
||||||
table = true,
|
|
||||||
tonumber = true,
|
|
||||||
tostring = true,
|
|
||||||
type = true,
|
|
||||||
xpcall = true,
|
|
||||||
_G = true
|
|
||||||
}
|
|
||||||
|
|
||||||
local debug = debug
|
|
||||||
for i, v in pairs(_G) do
|
|
||||||
if not lua[i] or lua[i] == nil then
|
|
||||||
apis[i] = v
|
|
||||||
_G[i] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--p
|
|
||||||
|
|
||||||
local acekeys={
|
|
||||||
[apis.keys.enter]="\n",
|
|
||||||
[apis.keys.tab]="\t",
|
|
||||||
[apis.keys.backspace]="\b",
|
|
||||||
[apis.keys.up]="\17",
|
|
||||||
[apis.keys.down]="\18",
|
|
||||||
[apis.keys.left]="\19",
|
|
||||||
[apis.keys.right]="\20",
|
|
||||||
}
|
|
||||||
|
|
||||||
function sleep(time)
|
|
||||||
local stoptime = apis.os.clock() + (time)
|
|
||||||
while stoptime > apis.os.clock() do end
|
|
||||||
end
|
|
||||||
|
|
||||||
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
|
||||||
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
|
||||||
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
|
||||||
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
|
||||||
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
|
||||||
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
|
||||||
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
|
||||||
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
|
||||||
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
|
||||||
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
|
||||||
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
|
||||||
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
|
||||||
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
|
||||||
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
|
||||||
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
|
||||||
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
|
||||||
|
|
||||||
local function getFile(path)
|
|
||||||
local file = apis.fs.open(path, "r")
|
|
||||||
if not file then
|
|
||||||
displaySuperBadError("Could not open file: " .. path)
|
|
||||||
end
|
|
||||||
local content = file.readAll()
|
|
||||||
file.close()
|
|
||||||
return content
|
|
||||||
end
|
|
||||||
|
|
||||||
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/kernel.lua"),"@Kernel")
|
|
||||||
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/cct/initdisks"),"@Init_disks")(apis)
|
|
||||||
local fs = load(getFile(BOOT_DRIVE_PATH .. "/initfs"), "@InitFs")()
|
|
||||||
|
|
||||||
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
|
||||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
|
||||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
|
||||||
|
|
||||||
if not apis.fs.exists("/nvram.dat") then
|
|
||||||
local file = apis.fs.open("/nvram.dat", "w")
|
|
||||||
file.write("Hello, World!")
|
|
||||||
file.close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local eeprom
|
|
||||||
if apis.fs.exists("/startup.lua") then
|
|
||||||
eeprom="/startup.lua"
|
|
||||||
elseif apis.fs.exists("/eeprom") then
|
|
||||||
eeprom="/eeprom"
|
|
||||||
end
|
|
||||||
|
|
||||||
local eventQueue = {}
|
|
||||||
|
|
||||||
local function queueEvent(event, ...)
|
|
||||||
table.insert(eventQueue, {event, ...})
|
|
||||||
end
|
|
||||||
|
|
||||||
local colors = {
|
|
||||||
[0xFFFFFF]=0x0001,
|
|
||||||
[0xFF0000]=0x0002,
|
|
||||||
[0x00FF00]=0x0004,
|
|
||||||
[0x0000FF]=0x0008,
|
|
||||||
[0x00FFFF]=0x0010,
|
|
||||||
[0xFF00FF]=0x0020,
|
|
||||||
[0xFFFF00]=0x0040,
|
|
||||||
[0xFF6D00]=0x0080,
|
|
||||||
[0x6DFF55]=0x0100,
|
|
||||||
[0x24FFFF]=0x0200,
|
|
||||||
[0x924900]=0x0400,
|
|
||||||
[0x6D6D55]=0x0800,
|
|
||||||
[0xDBDBAA]=0x1000,
|
|
||||||
[0x6D00FF]=0x2000,
|
|
||||||
[0xB6FF00]=0x4000,
|
|
||||||
[0x000000]=0x8000
|
|
||||||
}
|
|
||||||
|
|
||||||
local fg,bg=0x6D6D55,0x000000
|
|
||||||
local l1f,l1d,l2,ops={},{},{},0
|
|
||||||
|
|
||||||
local function findClosest(tbl, target)
|
|
||||||
local closest = nil
|
|
||||||
local smallestDiff = math.huge
|
|
||||||
|
|
||||||
for k, _ in pairs(tbl) do
|
|
||||||
if k==target then return k end
|
|
||||||
local diff = math.abs(k - target)
|
|
||||||
if diff < smallestDiff then
|
|
||||||
smallestDiff = diff
|
|
||||||
closest = k
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return closest
|
|
||||||
end
|
|
||||||
|
|
||||||
local function aprox(c24)
|
|
||||||
ops = ops + 1
|
|
||||||
|
|
||||||
if ops % 1024 == 0 then
|
|
||||||
l1d = {}
|
|
||||||
l1f = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
if ops % 8192 == 0 then
|
|
||||||
l2 = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
if l2[c24] ~= nil then
|
|
||||||
return l2[c24]
|
|
||||||
end
|
|
||||||
|
|
||||||
if l1d[c24] ~= nil then
|
|
||||||
l1f[c24] = l1f[c24] + 1
|
|
||||||
|
|
||||||
if l1f[c24] >= 16 then
|
|
||||||
l2[c24] = l1d[c24]
|
|
||||||
l1d[c24] = nil
|
|
||||||
l1f[c24] = nil
|
|
||||||
return l2[c24]
|
|
||||||
end
|
|
||||||
|
|
||||||
return l1d[c24]
|
|
||||||
end
|
|
||||||
|
|
||||||
local closestKey = findClosest(colors, c24)
|
|
||||||
if not closestKey then return nil end
|
|
||||||
|
|
||||||
local value = colors[closestKey]
|
|
||||||
|
|
||||||
l1d[c24] = value
|
|
||||||
l1f[c24] = 1
|
|
||||||
|
|
||||||
return value
|
|
||||||
end
|
|
||||||
|
|
||||||
--p
|
|
||||||
local p={}
|
|
||||||
local native = apis.peripheral
|
|
||||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
|
||||||
|
|
||||||
function p.getNames()
|
|
||||||
local results = {}
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.isPresent(side) then
|
|
||||||
table.insert(results, side)
|
|
||||||
if native.hasType(side, "peripheral_hub") then
|
|
||||||
local remote = native.call(side, "getNamesRemote")
|
|
||||||
for _, name in ipairs(remote) do
|
|
||||||
table.insert(results, name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.isPresent(name)
|
|
||||||
if native.isPresent(name) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.getType(peripheral)
|
|
||||||
if type(peripheral) == "string" then
|
|
||||||
if native.isPresent(peripheral) then
|
|
||||||
return native.getType(peripheral)
|
|
||||||
end
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
|
||||||
return native.call(side, "getTypeRemote", peripheral)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
local mt = getmetatable(peripheral)
|
|
||||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
|
||||||
error("bad argument #1 (table is not a peripheral)", 2)
|
|
||||||
end
|
|
||||||
return table.unpack(mt.types)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.hasType(peripheral, peripheral_type)
|
|
||||||
if type(peripheral) == "string" then
|
|
||||||
if native.isPresent(peripheral) then
|
|
||||||
return native.hasType(peripheral, peripheral_type)
|
|
||||||
end
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
|
||||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
local mt = getmetatable(peripheral)
|
|
||||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
|
||||||
error("bad argument #1 (table is not a peripheral)", 2)
|
|
||||||
end
|
|
||||||
return mt.types[peripheral_type] ~= nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.getMethods(name)
|
|
||||||
if native.isPresent(name) then
|
|
||||||
return native.getMethods(name)
|
|
||||||
end
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
|
||||||
return native.call(side, "getMethodsRemote", name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.getName(peripheral)
|
|
||||||
local mt = getmetatable(peripheral)
|
|
||||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
|
||||||
error("bad argument #1 (table is not a peripheral)", 2)
|
|
||||||
end
|
|
||||||
return mt.name
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.call(name, method, ...)
|
|
||||||
if native.isPresent(name) then
|
|
||||||
return native.call(name, method, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
|
||||||
return native.call(side, "callRemote", name, method, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.wrap(name)
|
|
||||||
local methods = p.getMethods(name)
|
|
||||||
if not methods then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local types = { p.getType(name) }
|
|
||||||
for i = 1, #types do types[types[i]] = true end
|
|
||||||
local result = setmetatable({}, {
|
|
||||||
__name = "peripheral",
|
|
||||||
name = name,
|
|
||||||
type = types[1],
|
|
||||||
types = types,
|
|
||||||
})
|
|
||||||
for _, method in ipairs(methods) do
|
|
||||||
result[method] = function(...)
|
|
||||||
return p.call(name, method, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
function p.find(ty, filter)
|
|
||||||
local results = {}
|
|
||||||
for _, name in ipairs(p.getNames()) do
|
|
||||||
if p.hasType(name, ty) then
|
|
||||||
local wrapped = p.wrap(name)
|
|
||||||
if filter == nil or filter(name, wrapped) then
|
|
||||||
table.insert(results, wrapped)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return table.unpack(results)
|
|
||||||
end
|
|
||||||
--p
|
|
||||||
local allscreens = {p.find("monitor")}
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].setTextScale(.5)
|
|
||||||
allscreens[i].clear()
|
|
||||||
allscreens[i].setCursorPos(1,1)
|
|
||||||
end
|
|
||||||
|
|
||||||
allscreens[#allscreens+1] = apis.term
|
|
||||||
|
|
||||||
local callAsyncQueue = {}
|
|
||||||
local callAsyncReturn = {}
|
|
||||||
apis.callAsyncReturn = callAsyncReturn
|
|
||||||
local callidx=0
|
|
||||||
|
|
||||||
function apis.callAsync(func, ...)
|
|
||||||
callidx=callidx+1
|
|
||||||
callAsyncQueue[#callAsyncQueue+1] = {callidx, func, ...}
|
|
||||||
return callidx
|
|
||||||
end
|
|
||||||
|
|
||||||
local EFI = {
|
|
||||||
yield=function() end,
|
|
||||||
getEpochMs = function() return apis.os.epoch("utc") end,
|
|
||||||
getUptime = function() return apis.os.clock() * 1000 end,
|
|
||||||
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
|
||||||
getMachineEvent = function()
|
|
||||||
if #eventQueue > 0 then
|
|
||||||
return table.unpack(table.remove(eventQueue, 1))
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
getEEPROM = function() return getFile(eeprom) end,
|
|
||||||
setEEPROM = function(_, text)
|
|
||||||
local h = apis.fs.open(eeprom, "w")
|
|
||||||
h.write(text)
|
|
||||||
h.close()
|
|
||||||
end,
|
|
||||||
initfs=fs,
|
|
||||||
disks=initFs,
|
|
||||||
screenCtl={
|
|
||||||
print = function(_, text)
|
|
||||||
for i=1, #allscreens do
|
|
||||||
write(text.."\n", allscreens[i])
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
printInline = function(_, text)
|
|
||||||
for i=1, #allscreens do
|
|
||||||
write(text, allscreens[i])
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
clear = function()
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].clear()
|
|
||||||
allscreens[i].setCursorPos(1, 1)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
resetCursor = function()
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].setCursorPos(1, 1)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
setBackgroundColor = function(_, color)
|
|
||||||
bg=color
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].setBackgroundColor(aprox(color))
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
setTextColor = function(_, color)
|
|
||||||
fg=color
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].setTextColor(aprox(color))
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
getBackgroundColor = function()
|
|
||||||
return bg
|
|
||||||
end,
|
|
||||||
getTextColor = function()
|
|
||||||
return fg
|
|
||||||
end,
|
|
||||||
enable=function()
|
|
||||||
for i=1, #allscreens do
|
|
||||||
allscreens[i].clear()
|
|
||||||
allscreens[i].setCursorPos(1, 1)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
disable=function() end
|
|
||||||
},
|
|
||||||
architecture="cct",
|
|
||||||
getNvram = function() return getFile("/nvram.dat") end,
|
|
||||||
setNvram = function(_, text)
|
|
||||||
local h = apis.fs.open("/nvram.dat", "w")
|
|
||||||
h.write(text)
|
|
||||||
h.close()
|
|
||||||
end,
|
|
||||||
firmware=apis,
|
|
||||||
reboot=false,
|
|
||||||
beep=function() end
|
|
||||||
}
|
|
||||||
|
|
||||||
apis.term.setBackgroundColor(0x8000)
|
|
||||||
apis.term.setTextColor(0x1000)
|
|
||||||
apis.term.clear()
|
|
||||||
apis.term.setCursorPos(1, 1)
|
|
||||||
|
|
||||||
local kernelCoro = coroutine.create(function()
|
|
||||||
--pf
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch-
|
|
||||||
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
|
||||||
if not ok then
|
|
||||||
error(err)
|
|
||||||
else
|
|
||||||
apis.os.shutdown()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
function EFI.resumeWithTimeout(co, timeout, ...)
|
|
||||||
local startTime = EFI.getEpochMs()
|
|
||||||
debug.sethook(co, function()
|
|
||||||
if EFI.getEpochMs() > startTime + timeout then
|
|
||||||
return coroutine.yield("timeout")
|
|
||||||
end
|
|
||||||
end, "", 1000)
|
|
||||||
local ret = {coroutine.resume(co, ...)}
|
|
||||||
if ret[1] and ret[2] == "timeout" then
|
|
||||||
return "timeout"
|
|
||||||
elseif ret[1] == false then
|
|
||||||
return "error", ret[2]
|
|
||||||
else
|
|
||||||
debug.sethook(co)
|
|
||||||
return "success", table.unpack(ret, 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
EFI.screenCtl:print("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
|
||||||
--p
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local status, err = EFI.resumeWithTimeout(kernelCoro, 50)
|
|
||||||
apis.os.queueEvent("NoSleep")
|
|
||||||
local exit = false
|
|
||||||
while not exit do
|
|
||||||
local event = {coroutine.yield()}
|
|
||||||
if event[1] == "key" then
|
|
||||||
queueEvent(table.unpack(event))
|
|
||||||
queueEvent("keyPressed", 1, event[2])
|
|
||||||
if acekeys[event[2]] then
|
|
||||||
queueEvent("keyTyped", 1, acekeys[event[2]])
|
|
||||||
end
|
|
||||||
elseif event[1] == "char" then
|
|
||||||
queueEvent(table.unpack(event))
|
|
||||||
queueEvent("keyTyped", 1, event[2])
|
|
||||||
elseif event[1] == "key_up" then
|
|
||||||
queueEvent(table.unpack(event))
|
|
||||||
queueEvent("keyReleased", 1, event[2])
|
|
||||||
elseif event[1] == "NoSleep" then
|
|
||||||
exit = true
|
|
||||||
else
|
|
||||||
queueEvent(table.unpack(event))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
while #callAsyncQueue>0 do
|
|
||||||
local bundle = table.remove(callAsyncQueue, 1)
|
|
||||||
local ret = {xpcall(bundle[2], debug.traceback, table.unpack(bundle, 3))}
|
|
||||||
if not ret[1] then
|
|
||||||
callAsyncReturn[bundle[1]]={false, ret[2]}
|
|
||||||
else
|
|
||||||
callAsyncReturn[bundle[1]]={true, table.unpack(ret,2)}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
|
||||||
if EFI.reboot then
|
|
||||||
apis.os.reboot()
|
|
||||||
end
|
|
||||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
|
||||||
coroutine.yield("key")
|
|
||||||
elseif status == "success" then
|
|
||||||
if EFI.reboot then
|
|
||||||
apis.os.reboot()
|
|
||||||
end
|
|
||||||
displaySuperBadError("Kernel error: Attempted to yield main thread\n"..debug.traceback(kernelCoro, "Attempted to yield main thread"))
|
|
||||||
coroutine.yield("key")
|
|
||||||
end
|
|
||||||
initFs:refresh()
|
|
||||||
end
|
|
||||||
end, debug.traceback)
|
|
||||||
|
|
||||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
|
||||||
while true do coroutine.yield("key") end
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
--: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
|
|
||||||
)
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
local keys=kernel.apis.keys
|
|
||||||
kernel.cct.eventhooks={}
|
|
||||||
|
|
||||||
kernel.processes.cctdaemon = function()
|
|
||||||
local timeout = false
|
|
||||||
kernel.log("CCT daemon started")
|
|
||||||
while true do
|
|
||||||
local event = {kernel.EFI:getMachineEvent()}
|
|
||||||
|
|
||||||
if event[1] then
|
|
||||||
local eventType = event[1]
|
|
||||||
local charOrKey = event[3]
|
|
||||||
|
|
||||||
local ctrlKeyMap = {
|
|
||||||
[keys.a]=1, [keys.b]=2, [keys.c]=3,
|
|
||||||
[keys.d]=4, [keys.e]=5, [keys.f]=6,
|
|
||||||
[keys.g]=7, [keys.h]=8, [keys.i]=9,
|
|
||||||
[keys.j]=10, [keys.k]=11, [keys.l]=12,
|
|
||||||
[keys.m]=13, [keys.n]=14, [keys.o]=15,
|
|
||||||
[keys.p]=16, [keys.q]=17, [keys.r]=18,
|
|
||||||
[keys.s]=19, [keys.t]=20, [keys.u]=21,
|
|
||||||
[keys.v]=22, [keys.w]=23, [keys.x]=24,
|
|
||||||
[keys.y]=25, [keys.z]=26,
|
|
||||||
}
|
|
||||||
|
|
||||||
if eventType == "keyPressed" then
|
|
||||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
|
||||||
kernel.cct.ctrl = true
|
|
||||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
|
||||||
kernel.cct.alt = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if kernel.cct.ctrl then
|
|
||||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
|
||||||
if ctrlByte then
|
|
||||||
if ctrlByte == 3 then
|
|
||||||
for _, task in ipairs(syscall.getTasks()) do
|
|
||||||
syscall.sigsend(task, 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
kernel.cct.fifo.push(string.char(ctrlByte))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local specialKeyMap = {
|
|
||||||
[keys.up] = "[A",
|
|
||||||
[keys.down] = "[B",
|
|
||||||
[keys.right] = "[C",
|
|
||||||
[keys.left] = "[D",
|
|
||||||
[keys.home] = "[H",
|
|
||||||
[keys["end"]] = "[F",
|
|
||||||
[keys.pageUp] = "[5~",
|
|
||||||
[keys.pageDown] = "[6~",
|
|
||||||
[keys.delete] = "[3~",
|
|
||||||
}
|
|
||||||
local special = specialKeyMap[charOrKey]
|
|
||||||
if special then kernel.cct.fifo.push(special) end
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif eventType == "keyReleased" then
|
|
||||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
|
||||||
kernel.cct.ctrl = false
|
|
||||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
|
||||||
kernel.cct.alt = false
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif eventType == "keyTyped" then
|
|
||||||
if charOrKey then kernel.cct.fifo.push(charOrKey) end
|
|
||||||
elseif eventType == "mouse_scroll" then
|
|
||||||
if event[2] == 1 then
|
|
||||||
kernel.cct.fifo.push("[nS")
|
|
||||||
else
|
|
||||||
kernel.cct.fifo.push("[nT")
|
|
||||||
end
|
|
||||||
elseif eventType == "http_success" then
|
|
||||||
if kernel.cct.httpqueue[event[2]] then
|
|
||||||
kernel.cct.httpqueue[event[2]]=nil
|
|
||||||
kernel.cct.httpresponse[event[2]]=event[3]
|
|
||||||
end
|
|
||||||
elseif eventType == "http_failure" then
|
|
||||||
if kernel.cct.httpqueue[event[2]] then
|
|
||||||
kernel.cct.httpqueue[event[2]]=nil
|
|
||||||
kernel.cct.httperror[event[2]]=event[3]
|
|
||||||
kernel.cct.httpresponse[event[2]]=event[4]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if kernel.cct.eventhooks[eventType] then
|
|
||||||
local ok,err = xpcall(kernel.cct.eventhooks[eventType], debug.traceback, table.unpack(event))
|
|
||||||
if not ok then
|
|
||||||
kernel.log("Error on eventhook "..eventType.."\n"..err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
timeout = false
|
|
||||||
else
|
|
||||||
timeout = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if timeout then
|
|
||||||
sleep(0.05)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.log("CCT daemon queued for execution")
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
local alpha = 0.85
|
|
||||||
local C_target = 0.01
|
|
||||||
local Tmin = 0.0005
|
|
||||||
local Tmax = 0.5
|
|
||||||
local lambda_budget = 0.08
|
|
||||||
local lambda_clamp = 0.03
|
|
||||||
local lambda_var = 0.02
|
|
||||||
local k_min = 0.5
|
|
||||||
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(kernel.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
|
|
||||||
local totalTaskTime = 0
|
|
||||||
local taskTimes = {}
|
|
||||||
|
|
||||||
for pid, task in pairs(kernel.tasks) do
|
|
||||||
if kernel.exitMain then break end
|
|
||||||
|
|
||||||
for _,list in ipairs(kernel.perTaskHooks) do
|
|
||||||
for id,hook in ipairs(list) do
|
|
||||||
local ok,err = xpcall(hook, debug.traceback, task, pid)
|
|
||||||
if not ok then
|
|
||||||
kernel.log("[MAIN HOOK ERR]: "..err, "ERROR", 0xFF0000)
|
|
||||||
list[id]=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if task.status == "R" then
|
|
||||||
N = N + 1
|
|
||||||
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
|
||||||
if task.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 = { kernel.EFI.resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
|
||||||
else
|
|
||||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
|
||||||
end
|
|
||||||
|
|
||||||
local elapsed = kernel.EFI:getEpochMs() - startTime
|
|
||||||
task.lastTime = elapsed
|
|
||||||
task.totalTime = (task.totalTime or 0) + elapsed
|
|
||||||
task.numRuns = (task.numRuns or 0) + 1
|
|
||||||
|
|
||||||
taskTimes[#taskTimes+1] = elapsed
|
|
||||||
totalTaskTime = totalTaskTime + elapsed
|
|
||||||
|
|
||||||
if elapsed <= Tmin then Tmin_hit = Tmin_hit + 1 end
|
|
||||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
|
||||||
|
|
||||||
if ret[1] == "error" or ret[1] == false then
|
|
||||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 0xFF0000)
|
|
||||||
task.status = "Z"
|
|
||||||
task.exit = "processHandlerException: " .. tostring(ret[2])
|
|
||||||
|
|
||||||
elseif ret[1] == "timeout" then
|
|
||||||
task.ivs = task.ivs + 1
|
|
||||||
task.syscallReturn = {}
|
|
||||||
|
|
||||||
elseif ret[1] == "success" or ret[1] == true then
|
|
||||||
task.vs = task.vs + 1
|
|
||||||
|
|
||||||
if ret[2] == "syscall" then
|
|
||||||
local scname = ret[3]
|
|
||||||
if kernel.syscalls[scname] then
|
|
||||||
if kernel.config.debugSyscalls then
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 0x00FFFF)
|
|
||||||
for i = 4, #ret do
|
|
||||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 0x00FFFF)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(ret, 4)) }
|
|
||||||
|
|
||||||
if kernel.config.debugSyscalls then
|
|
||||||
if not sysret[1] then
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 0xFF0000)
|
|
||||||
else
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 0x00FFFF)
|
|
||||||
for i = 2, #sysret do
|
|
||||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
|
||||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not sysret[1] then
|
|
||||||
task.syscallReturn = { false, sysret[2] }
|
|
||||||
else
|
|
||||||
task.syscallReturn = { true, table.unpack(sysret, 2) }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
task.syscallReturn = { false, "Unknown syscall: " .. tostring(scname) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
|
|
||||||
local T_prev_var = 0
|
|
||||||
for _, t in ipairs(taskTimes) do
|
|
||||||
T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
|
|
||||||
end
|
|
||||||
if N > 0 then T_prev_var = T_prev_var / N end
|
|
||||||
|
|
||||||
if N > 0 then
|
|
||||||
local f_clamp = k_min * (Tmin_hit / N) - k_max * (Tmax_hit / N)
|
|
||||||
local B_budget = (C_target * (N ^ (alpha - 1))) / math.max(T_prev_avg, 1e-8)
|
|
||||||
B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp - lambda_var * T_prev_var
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.hpv.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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
firmware for ComputerCraft Tweaked
|
|
||||||
+5
-48
@@ -3,7 +3,6 @@
|
|||||||
local kernel=...
|
local kernel=...
|
||||||
kernel.cct={}
|
kernel.cct={}
|
||||||
kernel.cct.peripheral={}
|
kernel.cct.peripheral={}
|
||||||
kernel.cct.callAsync=kernel.apis.callAsync
|
|
||||||
local peripheral=kernel.cct.peripheral
|
local peripheral=kernel.cct.peripheral
|
||||||
local apis = kernel.apis
|
local apis = kernel.apis
|
||||||
local native = apis.peripheral
|
local native = apis.peripheral
|
||||||
@@ -104,40 +103,6 @@ function peripheral.getName(peripheral)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function peripheral.call(name, method, ...)
|
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
|
if native.isPresent(name) then
|
||||||
return native.call(name, method, ...)
|
return native.call(name, method, ...)
|
||||||
end
|
end
|
||||||
@@ -151,7 +116,7 @@ function peripheral.callnative(name, method, ...)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function peripheral.wrap(name, wrap)
|
function peripheral.wrap(name)
|
||||||
local methods = peripheral.getMethods(name)
|
local methods = peripheral.getMethods(name)
|
||||||
if not methods then
|
if not methods then
|
||||||
return nil
|
return nil
|
||||||
@@ -165,17 +130,9 @@ function peripheral.wrap(name, wrap)
|
|||||||
type = types[1],
|
type = types[1],
|
||||||
types = types,
|
types = types,
|
||||||
})
|
})
|
||||||
if wrap then
|
for _, method in ipairs(methods) do
|
||||||
for _, method in ipairs(methods) do
|
result[method] = function(...)
|
||||||
result[method] = function(...)
|
return peripheral.call(name, method, ...)
|
||||||
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
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
@@ -192,4 +149,4 @@ function peripheral.find(ty, filter)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
return table.unpack(results)
|
return table.unpack(results)
|
||||||
end
|
end
|
||||||
+86
-39
@@ -1,6 +1,7 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
local peripheral=kernel.cct.peripheral
|
local peripheral=kernel.cct.peripheral
|
||||||
|
local keys=kernel.apis.keys
|
||||||
|
|
||||||
local colors = {
|
local colors = {
|
||||||
[0xFFFFFF]=0x0001,
|
[0xFFFFFF]=0x0001,
|
||||||
@@ -48,7 +49,6 @@ local function findClosest(tbl, target)
|
|||||||
local smallestDiff = math.huge
|
local smallestDiff = math.huge
|
||||||
|
|
||||||
for k, _ in pairs(tbl) do
|
for k, _ in pairs(tbl) do
|
||||||
if k==target then return k end
|
|
||||||
local diff = math.abs(k - target)
|
local diff = math.abs(k - target)
|
||||||
if diff < smallestDiff then
|
if diff < smallestDiff then
|
||||||
smallestDiff = diff
|
smallestDiff = diff
|
||||||
@@ -144,7 +144,8 @@ local function write(text, term)
|
|||||||
term.setCursorPos(x, y)
|
term.setCursorPos(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.cct.ctrl,kernel.cct.alt = false, false
|
kernel.devfs.data.tty={}
|
||||||
|
local ctrl,alt = false, false
|
||||||
|
|
||||||
local function serializeBool(bool)
|
local function serializeBool(bool)
|
||||||
if bool then
|
if bool then
|
||||||
@@ -191,14 +192,16 @@ local function newtty(obj, id, ev)
|
|||||||
write(content, obj)
|
write(content, obj)
|
||||||
end,
|
end,
|
||||||
size=function()
|
size=function()
|
||||||
return obj.getSize()
|
local s={obj.getSize()}
|
||||||
|
return table.concat(s,";")
|
||||||
end,
|
end,
|
||||||
clear=function()
|
clear=function()
|
||||||
obj.clear()
|
obj.clear()
|
||||||
obj.setCursorPos(1,1)
|
obj.setCursorPos(1,1)
|
||||||
end,
|
end,
|
||||||
gpos=function()
|
gpos=function()
|
||||||
return obj.getCursorPos()
|
local s={obj.getCursorPos()}
|
||||||
|
return table.concat(s,";")
|
||||||
end,
|
end,
|
||||||
spos=function(x,y)
|
spos=function(x,y)
|
||||||
return obj.setCursorPos(x,y)
|
return obj.setCursorPos(x,y)
|
||||||
@@ -217,8 +220,8 @@ local function newtty(obj, id, ev)
|
|||||||
gbgc=function()
|
gbgc=function()
|
||||||
return bg
|
return bg
|
||||||
end,
|
end,
|
||||||
isvirt=function()
|
gctrl=function()
|
||||||
return false
|
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||||
end,
|
end,
|
||||||
gplt=function()
|
gplt=function()
|
||||||
return plt
|
return plt
|
||||||
@@ -238,44 +241,88 @@ local function newtty(obj, id, ev)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local fifo = kernel.newFifo()
|
local fifo = kernel.newFifo()
|
||||||
kernel.cct.fifo=fifo
|
|
||||||
|
|
||||||
newtty(kernel.apis.term, "1", function() end)
|
kernel.processes.cctmond = function()
|
||||||
|
local timeout = false
|
||||||
|
while true do
|
||||||
|
local event = {kernel.EFI:getMachineEvent()}
|
||||||
|
|
||||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
if event[1] then
|
||||||
newtty(v,tostring(i+1),function () end)
|
local eventType = event[1]
|
||||||
end
|
local charOrKey = event[3]
|
||||||
|
|
||||||
kernel.devfs.data["input"]["keyboard1"] = function(op, mode)
|
local ctrlKeyMap = {
|
||||||
if op=="type" then
|
[keys.a]=1, [keys.b]=2, [keys.c]=3,
|
||||||
return "Keyboard"
|
[keys.d]=4, [keys.e]=5, [keys.f]=6,
|
||||||
elseif op=="open" then
|
[keys.g]=7, [keys.h]=8, [keys.i]=9,
|
||||||
local h = {
|
[keys.j]=10, [keys.k]=11, [keys.l]=12,
|
||||||
read=function(amount)
|
[keys.m]=13, [keys.n]=14, [keys.o]=15,
|
||||||
local rv=""
|
[keys.p]=16, [keys.q]=17, [keys.r]=18,
|
||||||
for i=1, amount or 1 do
|
[keys.s]=19, [keys.t]=20, [keys.u]=21,
|
||||||
local event = {fifo.pop()}
|
[keys.v]=22, [keys.w]=23, [keys.x]=24,
|
||||||
if event[1] then
|
[keys.y]=25, [keys.z]=26,
|
||||||
rv=rv..event[1]
|
}
|
||||||
end
|
|
||||||
|
if eventType == "keyPressed" then
|
||||||
|
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||||
|
ctrl = true
|
||||||
|
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||||
|
alt = true
|
||||||
end
|
end
|
||||||
if rv=="" then rv=nil end
|
|
||||||
return rv
|
if ctrl then
|
||||||
end,
|
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||||
write=function(content)
|
if ctrlByte then
|
||||||
end,
|
if ctrlByte == 3 then
|
||||||
gctrl=function()
|
for _, task in ipairs(syscall.getTasks()) do
|
||||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
syscall.sigsend(task, 1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fifo.push(string.char(ctrlByte))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local specialKeyMap = {
|
||||||
|
[keys.up] = "[A",
|
||||||
|
[keys.down] = "[B",
|
||||||
|
[keys.right] = "[C",
|
||||||
|
[keys.left] = "[D",
|
||||||
|
[keys.home] = "[H",
|
||||||
|
[keys["end"]] = "[F",
|
||||||
|
[keys.pageUp] = "[5~",
|
||||||
|
[keys.pageDown] = "[6~",
|
||||||
|
[keys.delete] = "[3~",
|
||||||
|
}
|
||||||
|
local special = specialKeyMap[charOrKey]
|
||||||
|
if special then fifo.push(special) end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif eventType == "keyReleased" then
|
||||||
|
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||||
|
ctrl = false
|
||||||
|
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||||
|
alt = false
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif eventType == "keyTyped" then
|
||||||
|
if charOrKey then fifo.push(charOrKey) end
|
||||||
end
|
end
|
||||||
}
|
|
||||||
if mode=="rw" then
|
timeout = false
|
||||||
return h
|
else
|
||||||
elseif mode=="r" then
|
timeout = true
|
||||||
h["write"]=nil
|
end
|
||||||
return h
|
|
||||||
elseif mode=="w" then
|
if timeout then
|
||||||
h["read"]=nil
|
sleep(0.05)
|
||||||
return h
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
newtty(kernel.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
|
end
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.3.0
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
local lua = {
|
||||||
|
coroutine = true,
|
||||||
|
debug = true,
|
||||||
|
_HOST = true,
|
||||||
|
_VERSION = true,
|
||||||
|
assert = true,
|
||||||
|
collectgarbage = true,
|
||||||
|
error = true,
|
||||||
|
gcinfo = true,
|
||||||
|
getfenv = true,
|
||||||
|
getmetatable = true,
|
||||||
|
ipairs = true,
|
||||||
|
__inext = true,
|
||||||
|
load = true,
|
||||||
|
math = true,
|
||||||
|
next = true,
|
||||||
|
pairs = true,
|
||||||
|
pcall = true,
|
||||||
|
rawequal = true,
|
||||||
|
rawget = true,
|
||||||
|
rawlen = true,
|
||||||
|
rawset = true,
|
||||||
|
select = true,
|
||||||
|
setfenv = true,
|
||||||
|
setmetatable = true,
|
||||||
|
string = true,
|
||||||
|
table = true,
|
||||||
|
tonumber = true,
|
||||||
|
tostring = true,
|
||||||
|
type = true,
|
||||||
|
xpcall = true,
|
||||||
|
_G=true
|
||||||
|
}
|
||||||
|
|
||||||
|
local apis={}
|
||||||
|
for i,v in pairs(_G) do
|
||||||
|
if not lua[i] or lua[i]==nil then
|
||||||
|
apis[i]=v
|
||||||
|
_G[i]=nil
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
checkArg=nil
|
||||||
|
local oldcomputer=computer
|
||||||
|
_G.computer=nil
|
||||||
|
local os=os
|
||||||
|
_G.os=nil
|
||||||
|
|
||||||
|
function component.wrap(address)
|
||||||
|
local methods=oldcomponent.methods(address)
|
||||||
|
local object={}
|
||||||
|
for _,method in ipairs(methods) do
|
||||||
|
object[method]=function(_,...)
|
||||||
|
return oldcomponent.invoke(address,method,...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
|
local
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
local fs={}
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
local cp,c=component,computer;local b_addr=c.getBootAddress();local b_fs=cp.proxy(b_addr)
|
|
||||||
local gpu=cp.list("gpu")() and cp.proxy(cp.list("gpu")())
|
|
||||||
local e_rom=cp.list("eeprom")() and cp.proxy(cp.list("eeprom")())
|
|
||||||
local screens={}
|
|
||||||
for addr in cp.list("screen") do
|
|
||||||
local w,h=gpu and gpu.maxResolution() or 20,10
|
|
||||||
gpu.setResolution(w,h)
|
|
||||||
gpu.fill(1,1,w,h," ")
|
|
||||||
cp.proxy(addr).turnOn()
|
|
||||||
screens[#screens+1] = {cx=1,cy=1,w=w,h=h,addr=addr}
|
|
||||||
end
|
|
||||||
local function scroll(scr) gpu.copy(1,2,scr.w,scr.h-1,0,-1);gpu.fill(1,scr.h,scr.w,1," ") end
|
|
||||||
local function write(t)
|
|
||||||
if not gpu then return end
|
|
||||||
for s=1, #screens do
|
|
||||||
local scr=screens[s]
|
|
||||||
gpu.bind(scr.addr)
|
|
||||||
for i=1,#t do
|
|
||||||
local char=t:sub(i,i)
|
|
||||||
if char=="\n" then scr.cx=1;scr.cy=scr.cy+1
|
|
||||||
elseif char=="\t" then scr.cx=scr.cx+(4-((scr.cx-1)%4))
|
|
||||||
elseif char=="\b" then if scr.cx>1 then scr.cx=scr.cx-1;gpu.set(scr.cx,scr.cy," ") end
|
|
||||||
else gpu.set(scr.cx,scr.cy,char);scr.cx=scr.cx+1 end
|
|
||||||
if scr.cx>scr.w then scr.cx=1;scr.cy=scr.cy+1 end
|
|
||||||
if scr.cy>scr.h then error("executed")scroll(scr);scr.cy=scr.cy-1 end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function throw(err)
|
|
||||||
if gpu then
|
|
||||||
gpu.setBackground(0x0000AA);
|
|
||||||
gpu.setForeground(0xFFFFFF);
|
|
||||||
for i=1, #screens do
|
|
||||||
gpu.fill(1,1,screens[i].w,screens[i].h," ");
|
|
||||||
screens[i].cx,screens[i].cy=1,1;
|
|
||||||
end
|
|
||||||
write("CRITICAL KERNEL ERROR:\n"..tostring(err))
|
|
||||||
end
|
|
||||||
while true do c.pullSignal() end
|
|
||||||
end
|
|
||||||
local ok,err=xpcall(function()
|
|
||||||
local apis={os={},fs={},peripheral={},term={}}
|
|
||||||
local _l={coroutine=1,debug=1,_VERSION=1,assert=1,collectgarbage=1,error=1,getmetatable=1,ipairs=1,load=1,math=1,next=1,pairs=1,pcall=1,rawequal=1,rawget=1,rawlen=1,rawset=1,select=1,setmetatable=1,string=1,table=1,tonumber=1,tostring=1,type=1,xpcall=1,_G=1}
|
|
||||||
for k,v in pairs(_G) do if not _l[k] then apis[k]=v;_G[k]=nil end end
|
|
||||||
apis.os.clock=c.uptime;apis.os.epoch=function()return math.floor(c.uptime()*1000) end
|
|
||||||
apis.os.queueEvent=c.pushSignal
|
|
||||||
function sleep(t) local s=c.uptime()+t;while c.uptime()<s do c.pullSignal(s-c.uptime()) end end
|
|
||||||
local function getFile(path)
|
|
||||||
local h,err=b_fs.open(path,"r")
|
|
||||||
if not h then throw("Cannot open: "..path) end
|
|
||||||
local buf,chk="",""
|
|
||||||
repeat chk=b_fs.read(h,math.huge);buf=buf..(chk or "") until not chk
|
|
||||||
b_fs.close(h)
|
|
||||||
return buf
|
|
||||||
end
|
|
||||||
local Kernel=load(getFile("/boot/kernel.lua"),"@Kernel")
|
|
||||||
local initFs=load(getFile("/boot/oc/initdisks"),"@Init_disks")
|
|
||||||
local fs=load(getFile("/boot/initfs"),"@InitFs")
|
|
||||||
if not Kernel then throw("Kernel load failed.") end
|
|
||||||
if initFs then initFs=initFs(apis, b_fs, b_addr) end
|
|
||||||
if fs then fs=fs() end
|
|
||||||
local n_addr=cp.list("filesystem")()
|
|
||||||
local eQ={}
|
|
||||||
local function qEv(e,...) table.insert(eQ,{e,...}) end
|
|
||||||
apis.peripheral.getNames=function() local res={};for k in cp.list() do table.insert(res,k) end return res end
|
|
||||||
apis.peripheral.isPresent=function(a) return cp.type(a)~=nil end
|
|
||||||
apis.peripheral.getType=cp.type
|
|
||||||
apis.peripheral.getMethods=cp.methods
|
|
||||||
apis.peripheral.call=cp.invoke
|
|
||||||
local efi={
|
|
||||||
getEpochMs=function() return math.floor(c.uptime()*1000) end,
|
|
||||||
getUptime=function() return c.uptime()*1000 end,
|
|
||||||
date=function() return tostring(apis.os.date()) end,
|
|
||||||
getMachineEvent=function() return #eQ>0 and table.unpack(table.remove(eQ,1)) or nil end,
|
|
||||||
getEEPROM=function() return e_rom and e_rom.get() or "" end,
|
|
||||||
setEEPROM=function(_,t) if e_rom then e_rom.set(t) end end,
|
|
||||||
getNvram=function() return e_rom and e_rom.getData() or "" end,
|
|
||||||
setNvram=function(_,t) if e_rom then e_rom.setData(t) end end,
|
|
||||||
beep=function(freq, timeMs) c.beep(freq, timeMs / 1000) end,
|
|
||||||
initfs=fs,
|
|
||||||
disks=initFs,
|
|
||||||
architecture="oc",
|
|
||||||
firmware=apis,
|
|
||||||
reboot=false,
|
|
||||||
yield=function() coroutine.yield() end,
|
|
||||||
screenCtl={
|
|
||||||
print=function(_,t) write(tostring(t).."\n") end,
|
|
||||||
printInline=function(_,t) write(tostring(t)) end,
|
|
||||||
clear=function() if gpu then gpu.fill(1,1,w,h," ");cx,cy=1,1 end end,
|
|
||||||
resetCursor=function() cx,cy=1,1 end,
|
|
||||||
setBackgroundColor=function(_,cl) if gpu then gpu.setBackground(cl) end end,
|
|
||||||
setTextColor=function(_,cl) if gpu then gpu.setForeground(cl) end end,
|
|
||||||
enable=function() end,
|
|
||||||
disable=function() end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local kCo=coroutine.create(function()
|
|
||||||
local s,e=xpcall(Kernel,debug.traceback,efi)
|
|
||||||
if not s and not efi.reboot then throw(e) end
|
|
||||||
if efi.reboot then c.shutdown(true) else c.shutdown() end
|
|
||||||
end)
|
|
||||||
efi.screenCtl:print("Loaded in "..tostring(c.uptime()).."s")
|
|
||||||
while true do
|
|
||||||
local st,e=coroutine.resume(kCo)
|
|
||||||
c.pushSignal("NoSleep")
|
|
||||||
local ex=false
|
|
||||||
while not ex do
|
|
||||||
local ev={c.pullSignal(0)}
|
|
||||||
if ev[1]=="key_down" then qEv("keyPressed",1,ev[3]);qEv("keyTyped",1,string.char(ev[3]))
|
|
||||||
elseif ev[1]=="key_up" then qEv("keyReleased",1,ev[3])
|
|
||||||
elseif ev[1]=="component_added" then qEv("componentAdded",ev[3])
|
|
||||||
elseif ev[1]=="component_removed" then qEv("componentRemoved",ev[3])
|
|
||||||
elseif ev[1]=="modem_message" then qEv("modem_message",table.unpack(ev,2))
|
|
||||||
elseif ev[1]=="NoSleep" then ex=true end
|
|
||||||
end
|
|
||||||
if st=="error" or coroutine.status(kCo)=="dead" then
|
|
||||||
if efi.reboot then c.shutdown(true) end
|
|
||||||
throw("Kernel fault: "..tostring(e))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,debug.traceback)
|
|
||||||
if not ok then throw("Boot fault: "..err) end
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
local init
|
|
||||||
do
|
|
||||||
local component_invoke = component.invoke
|
|
||||||
local function boot_invoke(address, method, ...)
|
|
||||||
local result = table.pack(pcall(component_invoke, address, method, ...))
|
|
||||||
if not result[1] then
|
|
||||||
return nil, result[2]
|
|
||||||
else
|
|
||||||
return table.unpack(result, 2, result.n)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- backwards compatibility, may remove later
|
|
||||||
local eeprom = component.list("eeprom")()
|
|
||||||
computer.getBootAddress = function()
|
|
||||||
return boot_invoke(eeprom, "getData")
|
|
||||||
end
|
|
||||||
computer.setBootAddress = function(address)
|
|
||||||
return boot_invoke(eeprom, "setData", address)
|
|
||||||
end
|
|
||||||
|
|
||||||
do
|
|
||||||
local screen = component.list("screen")()
|
|
||||||
local gpu = component.list("gpu")()
|
|
||||||
if gpu and screen then
|
|
||||||
boot_invoke(gpu, "bind", screen)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function tryLoadFrom(address)
|
|
||||||
local handle, reason = boot_invoke(address, "open", "/boot/oc/boot.lua")
|
|
||||||
if not handle then
|
|
||||||
return nil, reason
|
|
||||||
end
|
|
||||||
local buffer = ""
|
|
||||||
repeat
|
|
||||||
local data, reason = boot_invoke(address, "read", handle, math.maxinteger or math.huge)
|
|
||||||
if not data and reason then
|
|
||||||
return nil, reason
|
|
||||||
end
|
|
||||||
buffer = buffer .. (data or "")
|
|
||||||
until not data
|
|
||||||
boot_invoke(address, "close", handle)
|
|
||||||
return load(buffer, "=init")
|
|
||||||
end
|
|
||||||
local reason
|
|
||||||
if computer.getBootAddress() then
|
|
||||||
init, reason = tryLoadFrom(computer.getBootAddress())
|
|
||||||
end
|
|
||||||
if not init then
|
|
||||||
computer.setBootAddress()
|
|
||||||
for address in component.list("filesystem") do
|
|
||||||
init, reason = tryLoadFrom(address)
|
|
||||||
if init then
|
|
||||||
computer.setBootAddress(address)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not init then
|
|
||||||
error("no bootable medium found" .. (reason and (": " .. tostring(reason)) or ""), 0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ok, err = xpcall(init,debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
error(err)
|
|
||||||
else
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
local apis = args[1]
|
|
||||||
local bootdrive = args[2]
|
|
||||||
local bootaddr = args[3]
|
|
||||||
local disks = {}
|
|
||||||
local internal = {}
|
|
||||||
|
|
||||||
local function createDisk(id, hw)
|
|
||||||
local disk = {
|
|
||||||
address = id,
|
|
||||||
isReadOnly = function() return hw.isReadOnly() end
|
|
||||||
}
|
|
||||||
|
|
||||||
function disk:spaceUsed() return hw.spaceUsed() end
|
|
||||||
function disk:spaceTotal() return hw.spaceTotal() end
|
|
||||||
|
|
||||||
function disk:list(path)
|
|
||||||
if not hw.exists(path) or not hw.isDirectory(path) then
|
|
||||||
return nil, "not directory"
|
|
||||||
end
|
|
||||||
return hw.list(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:fileExists(path)
|
|
||||||
return hw.exists(path) and not hw.isDirectory(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:directoryExists(path)
|
|
||||||
return hw.exists(path) and hw.isDirectory(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:type(path)
|
|
||||||
if not hw.exists(path) then
|
|
||||||
return nil
|
|
||||||
elseif hw.isDirectory(path) then
|
|
||||||
return "directory"
|
|
||||||
else
|
|
||||||
return "file"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:makeDirectory(path)
|
|
||||||
hw.makeDirectory(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:remove(path)
|
|
||||||
if hw.exists(path) then hw.remove(path) end
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:setLabel(label) hw.setLabel(label) end
|
|
||||||
function disk:getLabel() return hw.getLabel() end
|
|
||||||
|
|
||||||
function disk:attributes(path)
|
|
||||||
return {
|
|
||||||
size = hw.size(path),
|
|
||||||
isDir = hw.isDirectory(path),
|
|
||||||
isReadOnly = hw.isReadOnly(),
|
|
||||||
modified = hw.lastModified(path),
|
|
||||||
created = hw.lastModified(path)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function disk:open(path, mode)
|
|
||||||
local fd = hw.open(path, mode)
|
|
||||||
|
|
||||||
if not fd then
|
|
||||||
local dir = path:match("^(.*)/[^/]+$")
|
|
||||||
|
|
||||||
if dir and not hw.exists(dir) then
|
|
||||||
local ok, err = hw.makeDirectory(dir)
|
|
||||||
if not ok then
|
|
||||||
return nil, err or "could not create parent directory"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
fd = hw.open(path, mode)
|
|
||||||
if not fd then
|
|
||||||
return nil, "file not found or access denied"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
read = function(num) return hw.read(fd, num) end,
|
|
||||||
|
|
||||||
readAll = function()
|
|
||||||
local data = {}
|
|
||||||
while true do
|
|
||||||
local chunk = hw.read(fd, math.huge)
|
|
||||||
if not chunk then break end
|
|
||||||
data[#data + 1] = chunk
|
|
||||||
end
|
|
||||||
return table.concat(data)
|
|
||||||
end,
|
|
||||||
|
|
||||||
write = function(data) return hw.write(fd, data) end,
|
|
||||||
seek = function(whence, offset)
|
|
||||||
return hw.seek(fd, whence, offset)
|
|
||||||
end,
|
|
||||||
|
|
||||||
flush = function()
|
|
||||||
hw.close(fd)
|
|
||||||
fd = hw.open(path, mode)
|
|
||||||
end,
|
|
||||||
|
|
||||||
close = function()
|
|
||||||
hw.close(fd)
|
|
||||||
fd = nil
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return disk
|
|
||||||
end
|
|
||||||
|
|
||||||
internal["$"] = createDisk("$", bootdrive)
|
|
||||||
|
|
||||||
local function refresh()
|
|
||||||
disks = {}
|
|
||||||
for addr in apis.component.list("filesystem") do
|
|
||||||
if addr ~= bootaddr then
|
|
||||||
disks[addr] = createDisk(addr, apis.component.proxy(addr))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function iter()
|
|
||||||
refresh()
|
|
||||||
local combined = {}
|
|
||||||
|
|
||||||
for id, obj in pairs(internal) do combined[id] = obj end
|
|
||||||
for id, obj in pairs(disks) do combined[id] = obj end
|
|
||||||
|
|
||||||
return pairs(combined)
|
|
||||||
end
|
|
||||||
|
|
||||||
return {refresh = refresh, list = iter}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
kernel.oc={}
|
|
||||||
kernel.oc.component=kernel.apis.component
|
|
||||||
kernel.oc.computer=kernel.apis.computer
|
|
||||||
|
|
||||||
kernel.log("Installed components:")
|
|
||||||
for addr, typ in kernel.oc.component.list() do
|
|
||||||
local dev=kernel.oc.component.proxy(addr)
|
|
||||||
local tier=""
|
|
||||||
if dev.getTier then
|
|
||||||
tier=dev.getTier()
|
|
||||||
end
|
|
||||||
kernel.log(" "..addr.." : "..typ..tier)
|
|
||||||
end
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
local component=kernel.oc.component
|
|
||||||
|
|
||||||
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 component.proxy(p)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for addr, typ in kernel.oc.component.list() do
|
|
||||||
local obj=wrap(addr)
|
|
||||||
kernel.devfs.data["raw"][addr]=obj
|
|
||||||
local typefolder=kernel.devfs.data["raw"]["by-type"][typ]
|
|
||||||
if not typefolder then typefolder={} end
|
|
||||||
typefolder[tostring(#table.keys(typefolder)+1)] = obj
|
|
||||||
kernel.devfs.data["raw"]["by-type"][typ]=typefolder
|
|
||||||
end
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
-- OpenComputers TTY driver
|
|
||||||
|
|
||||||
local kernel = ...
|
|
||||||
local component = kernel.oc.component
|
|
||||||
local computer = kernel.oc.computer
|
|
||||||
|
|
||||||
local plt = {
|
|
||||||
0x000000, 0x000040, 0x000080, 0x0000C0, 0x0000FF,
|
|
||||||
0x002400, 0x002440, 0x002480, 0x0024C0, 0x0024FF,
|
|
||||||
0x004900, 0x004940, 0x004980, 0x0049C0, 0x0049FF,
|
|
||||||
0x006D00, 0x006D40, 0x006D80, 0x006DC0, 0x006DFF,
|
|
||||||
0x009200, 0x009240, 0x009280, 0x0092C0, 0x0092FF,
|
|
||||||
0x00B600, 0x00B640, 0x00B680, 0x00B6C0, 0x00B6FF,
|
|
||||||
0x00DB00, 0x00DB40, 0x00DB80, 0x00DBC0, 0x00DBFF,
|
|
||||||
0x00FF00, 0x00FF40, 0x00FF80, 0x00FFC0, 0x00FFFF,
|
|
||||||
|
|
||||||
0x330000, 0x330040, 0x330080, 0x3300C0, 0x3300FF,
|
|
||||||
0x332400, 0x332440, 0x332480, 0x3324C0, 0x3324FF,
|
|
||||||
0x334900, 0x334940, 0x334980, 0x3349C0, 0x3349FF,
|
|
||||||
0x336D00, 0x336D40, 0x336D80, 0x336DC0, 0x336DFF,
|
|
||||||
0x339200, 0x339240, 0x339280, 0x3392C0, 0x3392FF,
|
|
||||||
0x33B600, 0x33B640, 0x33B680, 0x33B6C0, 0x33B6FF,
|
|
||||||
0x33DB00, 0x33DB40, 0x33DB80, 0x33DBC0, 0x33DBFF,
|
|
||||||
0x33FF00, 0x33FF40, 0x33FF80, 0x33FFC0, 0x33FFFF,
|
|
||||||
|
|
||||||
0x660000, 0x660040, 0x660080, 0x6600C0, 0x6600FF,
|
|
||||||
0x662400, 0x662440, 0x662480, 0x6624C0, 0x6624FF,
|
|
||||||
0x664900, 0x664940, 0x664980, 0x6649C0, 0x6649FF,
|
|
||||||
0x666D00, 0x666D40, 0x666D80, 0x666DC0, 0x666DFF,
|
|
||||||
0x669200, 0x669240, 0x669280, 0x6692C0, 0x6692FF,
|
|
||||||
0x66B600, 0x66B640, 0x66B680, 0x66B6C0, 0x66B6FF,
|
|
||||||
0x66DB00, 0x66DB40, 0x66DB80, 0x66DBC0, 0x66DBFF,
|
|
||||||
0x66FF00, 0x66FF40, 0x66FF80, 0x66FFC0, 0x66FFFF,
|
|
||||||
|
|
||||||
0x990000, 0x990040, 0x990080, 0x9900C0, 0x9900FF,
|
|
||||||
0x992400, 0x992440, 0x992480, 0x9924C0, 0x9924FF,
|
|
||||||
0x994900, 0x994940, 0x994980, 0x9949C0, 0x9949FF,
|
|
||||||
0x996D00, 0x996D40, 0x996D80, 0x996DC0, 0x996DFF,
|
|
||||||
0x999200, 0x999240, 0x999280, 0x9992C0, 0x9992FF,
|
|
||||||
0x99B600, 0x99B640, 0x99B680, 0x99B6C0, 0x99B6FF,
|
|
||||||
0x99DB00, 0x99DB40, 0x99DB80, 0x99DBC0, 0x99DBFF,
|
|
||||||
0x99FF00, 0x99FF40, 0x99FF80, 0x99FFC0, 0x99FFFF,
|
|
||||||
|
|
||||||
0xCC0000, 0xCC0040, 0xCC0080, 0xCC00C0, 0xCC00FF,
|
|
||||||
0xCC2400, 0xCC2440, 0xCC2480, 0xCC24C0, 0xCC24FF,
|
|
||||||
0xCC4900, 0xCC4940, 0xCC4980, 0xCC49C0, 0xCC49FF,
|
|
||||||
0xCC6D00, 0xCC6D40, 0xCC6D80, 0xCC6DC0, 0xCC6DFF,
|
|
||||||
0xCC9200, 0xCC9240, 0xCC9280, 0xCC92C0, 0xCC92FF,
|
|
||||||
0xCCB600, 0xCCB640, 0xCCB680, 0xCCB6C0, 0xCCB6FF,
|
|
||||||
0xCCDB00, 0xCCDB40, 0xCCDB80, 0xCCDBC0, 0xCCDBFF,
|
|
||||||
0xCCFF00, 0xCCFF40, 0xCCFF80, 0xCCFFC0, 0xCCFFFF,
|
|
||||||
|
|
||||||
0xFF0000, 0xFF0040, 0xFF0080, 0xFF00C0, 0xFF00FF,
|
|
||||||
0xFF2400, 0xFF2440, 0xFF2480, 0xFF24C0, 0xFF24FF,
|
|
||||||
0xFF4900, 0xFF4940, 0xFF4980, 0xFF49C0, 0xFF49FF,
|
|
||||||
0xFF6D00, 0xFF6D40, 0xFF6D80, 0xFF6DC0, 0xFF6DFF,
|
|
||||||
0xFF9200, 0xFF9240, 0xFF9280, 0xFF92C0, 0xFF92FF,
|
|
||||||
0xFFB600, 0xFFB640, 0xFFB680, 0xFFB6C0, 0xFFB6FF,
|
|
||||||
0xFFDB00, 0xFFDB40, 0xFFDB80, 0xFFDBC0, 0xFFDBFF,
|
|
||||||
0xFFFF00, 0xFFFF40, 0xFFFF80, 0xFFFFC0, 0xFFFFFF,
|
|
||||||
|
|
||||||
0x000000, 0x0F0F0F, 0x1E1E1E, 0x2D2D2D,
|
|
||||||
0x3C3C3C, 0x4B4B4B, 0x5A5A5A, 0x696969,
|
|
||||||
0x787878, 0x878787, 0x969696, 0xA5A5A5,
|
|
||||||
0xB4B4B4, 0xC3C3C3, 0xD2D2D2, 0xE1E1E1
|
|
||||||
}
|
|
||||||
|
|
||||||
local gpus,screens = {},{}
|
|
||||||
|
|
||||||
for addr, typ in component.list() do
|
|
||||||
if typ == "gpu" then
|
|
||||||
gpus[#gpus]=component.proxy(addr)
|
|
||||||
elseif typ == "screen" then
|
|
||||||
screens[addr]={cx=1,cy=1,w=w,h=h}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local binds,newid={},0
|
|
||||||
|
|
||||||
local function write(text, addr)
|
|
||||||
local g=gpus[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function newtty(addr)
|
|
||||||
newid=newid+1
|
|
||||||
kernel.devfs.data["tty"][newid]=function(op, mode)
|
|
||||||
if op=="type" then
|
|
||||||
return "Terminal"
|
|
||||||
elseif op=="open" then
|
|
||||||
local h = {
|
|
||||||
read=function(amount) end,
|
|
||||||
write=function(content)
|
|
||||||
write(content, addr)
|
|
||||||
end,
|
|
||||||
size=function()
|
|
||||||
local s={obj.getSize()}
|
|
||||||
return tostring(screens[addr].w)..":"
|
|
||||||
end,
|
|
||||||
clear=function()
|
|
||||||
obj.clear()
|
|
||||||
obj.setCursorPos(1,1)
|
|
||||||
end,
|
|
||||||
gpos=function()
|
|
||||||
local s={obj.getCursorPos()}
|
|
||||||
return table.concat(s,";")
|
|
||||||
end,
|
|
||||||
spos=function(x,y)
|
|
||||||
return obj.setCursorPos(x,y)
|
|
||||||
end,
|
|
||||||
sfgc=function(c)
|
|
||||||
fg=c
|
|
||||||
return obj.setTextColor(aprox(c))
|
|
||||||
end,
|
|
||||||
sbgc=function(c)
|
|
||||||
bg=c
|
|
||||||
return obj.setBackgroundColor(aprox(c))
|
|
||||||
end,
|
|
||||||
gfgc=function()
|
|
||||||
return fg
|
|
||||||
end,
|
|
||||||
gbgc=function()
|
|
||||||
return bg
|
|
||||||
end,
|
|
||||||
isvirt=function()
|
|
||||||
return false
|
|
||||||
end,
|
|
||||||
gplt=function()
|
|
||||||
return plt
|
|
||||||
end
|
|
||||||
}
|
|
||||||
if mode=="rw" then
|
|
||||||
return h
|
|
||||||
elseif mode=="r" then
|
|
||||||
h["write"]=nil
|
|
||||||
return h
|
|
||||||
elseif mode=="w" then
|
|
||||||
h["read"]=nil
|
|
||||||
return h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if #gpus>=1 and #screens>=1 then
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
local alpha = 0.85
|
|
||||||
local C_target = 0.01
|
|
||||||
local Tmin = 0.0005
|
|
||||||
local Tmax = 0.5
|
|
||||||
local lambda_budget = 0.08
|
|
||||||
local lambda_clamp = 0.03
|
|
||||||
local lambda_var = 0.02
|
|
||||||
local k_min = 0.5
|
|
||||||
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(kernel.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
|
|
||||||
local totalTaskTime = 0
|
|
||||||
local taskTimes = {}
|
|
||||||
|
|
||||||
for pid, task in pairs(kernel.tasks) do
|
|
||||||
if kernel.exitMain then break end
|
|
||||||
|
|
||||||
for _,list in ipairs(kernel.perTaskHooks) do
|
|
||||||
for id,hook in ipairs(list) do
|
|
||||||
local ok,err = xpcall(hook, debug.traceback, task, pid)
|
|
||||||
if not ok then
|
|
||||||
kernel.log("[MAIN HOOK ERR]: "..err, "ERROR", 0xFF0000)
|
|
||||||
list[id]=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if task.status == "R" then
|
|
||||||
N = N + 1
|
|
||||||
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
|
||||||
if task.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
|
|
||||||
|
|
||||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
|
||||||
|
|
||||||
|
|
||||||
local elapsed = kernel.EFI:getEpochMs() - startTime
|
|
||||||
task.lastTime = elapsed
|
|
||||||
task.totalTime = (task.totalTime or 0) + elapsed
|
|
||||||
task.numRuns = (task.numRuns or 0) + 1
|
|
||||||
|
|
||||||
taskTimes[#taskTimes+1] = elapsed
|
|
||||||
totalTaskTime = totalTaskTime + elapsed
|
|
||||||
|
|
||||||
if elapsed <= Tmin then Tmin_hit = Tmin_hit + 1 end
|
|
||||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
|
||||||
|
|
||||||
if ret[1] == "error" or ret[1] == false then
|
|
||||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 0xFF0000)
|
|
||||||
task.status = "Z"
|
|
||||||
task.exit = "processHandlerException: " .. tostring(ret[2])
|
|
||||||
|
|
||||||
elseif ret[1] == "timeout" then
|
|
||||||
task.ivs = task.ivs + 1
|
|
||||||
task.syscallReturn = {}
|
|
||||||
|
|
||||||
elseif ret[1] == "success" or ret[1] == true then
|
|
||||||
task.vs = task.vs + 1
|
|
||||||
|
|
||||||
if ret[2] == "syscall" then
|
|
||||||
local scname = ret[3]
|
|
||||||
if kernel.syscalls[scname] then
|
|
||||||
if kernel.config.debugSyscalls then
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 0x00FFFF)
|
|
||||||
for i = 4, #ret do
|
|
||||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 0x00FFFF)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(ret, 4)) }
|
|
||||||
|
|
||||||
if kernel.config.debugSyscalls then
|
|
||||||
if not sysret[1] then
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 0xFF0000)
|
|
||||||
else
|
|
||||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 0x00FFFF)
|
|
||||||
for i = 2, #sysret do
|
|
||||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
|
||||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not sysret[1] then
|
|
||||||
task.syscallReturn = { false, sysret[2] }
|
|
||||||
else
|
|
||||||
task.syscallReturn = { true, table.unpack(sysret, 2) }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
task.syscallReturn = { false, "Unknown syscall: " .. tostring(scname) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
kernel.EFI:yield()
|
|
||||||
end
|
|
||||||
|
|
||||||
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
|
|
||||||
local T_prev_var = 0
|
|
||||||
for _, t in ipairs(taskTimes) do
|
|
||||||
T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
|
|
||||||
end
|
|
||||||
if N > 0 then T_prev_var = T_prev_var / N end
|
|
||||||
|
|
||||||
if N > 0 then
|
|
||||||
local f_clamp = k_min * (Tmin_hit / N) - k_max * (Tmax_hit / N)
|
|
||||||
local B_budget = (C_target * (N ^ (alpha - 1))) / math.max(T_prev_avg, 1e-8)
|
|
||||||
B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp - lambda_var * T_prev_var
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.hpv.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
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
Spsf
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
U $;/
|
||||||
|
U devfs0000;/dev/
|
||||||
|
U tmpfs0000;/tmp/
|
||||||
|
U procfs0000;/proc/
|
||||||
@@ -77,7 +77,7 @@ end
|
|||||||
function fs.load(path) return load(fs.readAllText(path), path) end
|
function fs.load(path) return load(fs.readAllText(path), path) end
|
||||||
|
|
||||||
function fs.mount(disk, mountPoint)
|
function fs.mount(disk, mountPoint)
|
||||||
if not disks[disk] then error("NODISK : "..disk) end
|
if not disks[disk] then return end
|
||||||
mounts[mountPoint] = disk
|
mounts[mountPoint] = disk
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local EFI=...
|
||||||
|
local screen=EFI.screenCtl
|
||||||
|
local ifs=EFI.initfs
|
||||||
|
local disks=EFI.disks
|
||||||
|
local arch=EFI.architecture
|
||||||
|
local kernel = {}
|
||||||
|
kernel.LOG_Text=""
|
||||||
|
kernel.version="HyperionOS V1.2.4"
|
||||||
|
kernel.process = "Kernel"
|
||||||
|
kernel.users={[0]="root",[1]="User"}
|
||||||
|
kernel.hostname = "hyperion"
|
||||||
|
kernel.groups = {}
|
||||||
|
kernel.uid = 0
|
||||||
|
kernel.gid = 0
|
||||||
|
kernel.status = "start"
|
||||||
|
kernel.key = {}
|
||||||
|
kernel.cache = {}
|
||||||
|
kernel.cache.preload = {}
|
||||||
|
kernel._G=_G
|
||||||
|
kernel.sleep=sleep
|
||||||
|
|
||||||
|
_G.sleep=nil
|
||||||
|
local windowsExp = false
|
||||||
|
|
||||||
|
function kernel.log(msg, level, c)
|
||||||
|
c=c or 0x6D6D6D
|
||||||
|
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||||
|
if kernel.status == "start" then
|
||||||
|
screen:setTextColor(c)
|
||||||
|
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||||
|
elseif kernel.status == "term" then
|
||||||
|
kernel.standbyTask=kernel.currentTask
|
||||||
|
kernel.currentTask=kernel.kernelTask
|
||||||
|
local file=kernel.vfs.open("/dev/console", "w")
|
||||||
|
kernel.vfs.devctl(file,"sfgc",c)
|
||||||
|
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||||
|
kernel.vfs.close(file)
|
||||||
|
kernel.currentTask=kernel.standbyTask
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function kernel.PANIC(msg)
|
||||||
|
if kernel.status~="Panic" then
|
||||||
|
kernel.log("PANIC: "..msg, "PANIC", 0xFF0000)
|
||||||
|
pcall(kernel["saveLog"])
|
||||||
|
kernel.status="Panic"
|
||||||
|
kernel.reason=msg
|
||||||
|
screen:enable()
|
||||||
|
screen:setTextColor(0xFF0000)
|
||||||
|
screen:setBackgroundColor(0x000000)
|
||||||
|
screen:clear()
|
||||||
|
screen:setCursorPos(1,1)
|
||||||
|
screen:print(kernel.LOG_Text)
|
||||||
|
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||||
|
screen:print("Press any key to continue...")
|
||||||
|
kernel.exitMain = true
|
||||||
|
end
|
||||||
|
while true do
|
||||||
|
local event={EFI:getMachineEvent()}
|
||||||
|
if event[1]=="keyPressed" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EFI.reboot=true
|
||||||
|
error("KERNEL PANIC")
|
||||||
|
end
|
||||||
|
kernel.panic=kernel.PANIC
|
||||||
|
|
||||||
|
if windowsExp then
|
||||||
|
screen:setTextColor(0xFFFFFF)
|
||||||
|
screen:setBackgroundColor(0x0000FF)
|
||||||
|
screen:clear()
|
||||||
|
local w,h = screen:getSize()
|
||||||
|
screen:setCursorPos(3,5)
|
||||||
|
screen:print(":(")
|
||||||
|
screen:setCursorPos(3,7)
|
||||||
|
screen:print("Your PC ran into a problem and needs to restart. We're just collecting some error")
|
||||||
|
screen:setCursorPos(3,8)
|
||||||
|
screen:print("info, and then we'll restart for you.\n")
|
||||||
|
screen:setCursorPos(3,h-5)
|
||||||
|
screen:print("Stop code: average windows experience")
|
||||||
|
screen:setCursorPos(1,h)
|
||||||
|
screen:print("Press any key to continue... jk reboot it yourself lazy")
|
||||||
|
while true do end
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.log("Kernel loaded.")
|
||||||
|
kernel.log("Mounting init disks...")
|
||||||
|
disks.refresh()
|
||||||
|
ifs.update(disks)
|
||||||
|
kernel.disks={}
|
||||||
|
for _,v in disks.list() do
|
||||||
|
kernel.disks[v.address] = v
|
||||||
|
end
|
||||||
|
ifs.mount("$", "/")
|
||||||
|
|
||||||
|
local fstab=ifs.readAllText("/boot/fstab")
|
||||||
|
local split = function(str, delim, maxResultCountOrNil)
|
||||||
|
assert(#delim == 1, "only delim len 1 supported for now")
|
||||||
|
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
||||||
|
local rv = {}
|
||||||
|
local buf = ""
|
||||||
|
for i = 1, #str do
|
||||||
|
local c = string.sub(str,i,i)
|
||||||
|
if #rv ~= maxResultCountOrNil and c == delim then
|
||||||
|
table.insert(rv, buf)
|
||||||
|
buf = ""
|
||||||
|
else
|
||||||
|
buf = buf..c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(rv, buf)
|
||||||
|
return rv
|
||||||
|
end
|
||||||
|
|
||||||
|
if not ifs.isFile("/boot/boot.cfg") then
|
||||||
|
kernel.log("First boot detected writing boot.cfg", "INFO", 0x00FF00)
|
||||||
|
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||||
|
kernel.firstBoot=true
|
||||||
|
end
|
||||||
|
|
||||||
|
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||||
|
if not initCfgFunc then
|
||||||
|
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
|
||||||
|
end
|
||||||
|
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
|
local initCfgStatus, config = pcall(initCfgFunc)
|
||||||
|
if not initCfgStatus then
|
||||||
|
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
|
||||||
|
end
|
||||||
|
kernel.config = config
|
||||||
|
|
||||||
|
local skip=false
|
||||||
|
for i,v in ipairs(split(fstab,"\n")) do
|
||||||
|
if v:sub(1,1)=="U" then
|
||||||
|
local id=""
|
||||||
|
for i=3,#v do
|
||||||
|
if v:sub(i,i)==";" then
|
||||||
|
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 0xFF8800) skip = true break end
|
||||||
|
id=v:sub(3,i-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not skip then
|
||||||
|
local path=v:sub(#id+4)
|
||||||
|
ifs.mount(id,path)
|
||||||
|
else
|
||||||
|
skip=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
kernel.log("Disks initialized")
|
||||||
|
|
||||||
|
function kernel.saveLog()
|
||||||
|
if kernel.status=="running" then
|
||||||
|
local file = kernel.vfs.open("/var/log/syslog.log", "w")
|
||||||
|
kernel.vfs.write(file, kernel.LOG_Text)
|
||||||
|
kernel.vfs.close(file)
|
||||||
|
else
|
||||||
|
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function kernel.newFifo()
|
||||||
|
local fifo = {}
|
||||||
|
fifo.push=function(data)
|
||||||
|
table.insert(fifo, data)
|
||||||
|
end
|
||||||
|
fifo.pop=function()
|
||||||
|
return table.remove(fifo,1)
|
||||||
|
end
|
||||||
|
return fifo
|
||||||
|
end
|
||||||
|
|
||||||
|
function kernel.newUUID()
|
||||||
|
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||||
|
local uuid = ""
|
||||||
|
for i = 1, #template do
|
||||||
|
local c = template:sub(i,i)
|
||||||
|
if c == "x" then
|
||||||
|
uuid = uuid .. string.format("%x", math.random(0, 15))
|
||||||
|
elseif c == "y" then
|
||||||
|
uuid = uuid .. string.format("%x", math.random(8, 11))
|
||||||
|
else
|
||||||
|
uuid = uuid .. c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return uuid
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.syscalls={}
|
||||||
|
local modules={[0]={}}
|
||||||
|
for i=0, 100 do
|
||||||
|
modules[i]={}
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.log("Gathering modules")
|
||||||
|
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||||
|
local modlist = ifs.list("/lib/modules/"..i)
|
||||||
|
if not modlist then
|
||||||
|
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 0xFF8800)
|
||||||
|
else
|
||||||
|
for _,v in ipairs(modlist) do
|
||||||
|
local prior=tonumber(v:sub(1,2))
|
||||||
|
if prior then
|
||||||
|
modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.ifs=ifs
|
||||||
|
kernel.apis=EFI.firmware
|
||||||
|
kernel.EFI=EFI
|
||||||
|
kernel.arch=arch
|
||||||
|
kernel.initdisks=disks
|
||||||
|
kernel.screen=screen
|
||||||
|
kernel.processes={}
|
||||||
|
kernel.fstab=fstab
|
||||||
|
|
||||||
|
kernel.kernelTask = {
|
||||||
|
name="kernel",
|
||||||
|
status="R",
|
||||||
|
pid=0,
|
||||||
|
tgid=0,
|
||||||
|
uid=0,
|
||||||
|
fd={},
|
||||||
|
exit="",
|
||||||
|
sleep=0,
|
||||||
|
ivs=0,
|
||||||
|
vs=0,
|
||||||
|
children={},
|
||||||
|
syscallReturn={},
|
||||||
|
cwd="/",
|
||||||
|
timeSlice=0,
|
||||||
|
lastTime=0,
|
||||||
|
totalTime=0,
|
||||||
|
numRuns=0
|
||||||
|
}
|
||||||
|
kernel.currentTask = kernel.kernelTask
|
||||||
|
|
||||||
|
function kernel.shutdown()
|
||||||
|
kernel.exitMain=true
|
||||||
|
kernel.status="shutdown"
|
||||||
|
end
|
||||||
|
|
||||||
|
function kernel.reboot()
|
||||||
|
kernel.exitMain=true
|
||||||
|
kernel.status="reboot"
|
||||||
|
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["getUptime"]=function() return kernel.EFI:getUptime() end
|
||||||
|
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||||
|
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||||
|
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||||
|
kernel.syscalls["version"]=function() return kernel.version end
|
||||||
|
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
|
||||||
|
kernel.syscalls["arch"]=function() return arch end
|
||||||
|
kernel.syscalls["sysdump"]=function()
|
||||||
|
local rv={}
|
||||||
|
for i,v in pairs(kernel.syscalls) do
|
||||||
|
rv[#rv+1] = i
|
||||||
|
end
|
||||||
|
return rv
|
||||||
|
end
|
||||||
|
kernel.syscalls["reboot"]=kernel.reboot
|
||||||
|
kernel.syscalls["shutdown"]=kernel.shutdown
|
||||||
|
|
||||||
|
kernel.log("Running modules")
|
||||||
|
for _,p in ipairs(modules) do
|
||||||
|
for _,v in ipairs(p) do
|
||||||
|
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 0x00FFFF) end
|
||||||
|
local code=ifs.readAllText(v)
|
||||||
|
if not code then
|
||||||
|
kernel.panic("Failed to read module "..v)
|
||||||
|
end
|
||||||
|
local func,err=load(code,"@"..v)
|
||||||
|
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end
|
||||||
|
local status, err = xpcall(func,debug.traceback, kernel)
|
||||||
|
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||||
|
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.log("Kernel initialized successfully.")
|
||||||
|
kernel.saveLog()
|
||||||
|
kernel.status="running"
|
||||||
|
screen:disable()
|
||||||
|
kernel.main()
|
||||||
|
if kernel.status=="panic" then
|
||||||
|
kernel.panic(kernel.reason)
|
||||||
|
end
|
||||||
|
if kernel.status=="reboot" then
|
||||||
|
EFI.reboot=true
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -7,5 +7,6 @@ return {
|
|||||||
initPath = "/sbin/init",
|
initPath = "/sbin/init",
|
||||||
maxOpenFiles = 128,
|
maxOpenFiles = 128,
|
||||||
maxFilesPerTask = 16,
|
maxFilesPerTask = 16,
|
||||||
preempt = true,
|
preempt=true,
|
||||||
|
logTaskExit=true
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
F $;/boot/
|
|
||||||
V devfs0000;/dev/
|
|
||||||
V tmpfs0000;/tmp/
|
|
||||||
V procfs0000;/proc/
|
|
||||||
@@ -1,481 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local EFI=...
|
|
||||||
--pf
|
|
||||||
EFI.beep(440, 500)
|
|
||||||
local screen=EFI.screenCtl
|
|
||||||
local ifs=EFI.initfs
|
|
||||||
local disks=EFI.disks
|
|
||||||
local arch=EFI.architecture
|
|
||||||
local kernel = {}
|
|
||||||
kernel.LOG_Text=""
|
|
||||||
kernel.version="HyperionOS V1.2.4"
|
|
||||||
kernel.tag="1.2.4"
|
|
||||||
kernel.process = "Kernel"
|
|
||||||
kernel.users={[0]="root",[1000]="User"}
|
|
||||||
kernel.hostname = "hyperion"
|
|
||||||
kernel.groups = {}
|
|
||||||
kernel.uid = 0
|
|
||||||
kernel.gid = 0
|
|
||||||
kernel.status = "start"
|
|
||||||
kernel.key = {}
|
|
||||||
kernel.cache = {}
|
|
||||||
kernel.cache.preload = {}
|
|
||||||
kernel.unixSockets={}
|
|
||||||
kernel._G=_G
|
|
||||||
kernel.sleep=sleep
|
|
||||||
|
|
||||||
_G.sleep=nil
|
|
||||||
local windowsExp = false
|
|
||||||
|
|
||||||
function kernel.log(msg, level, c, nopanic)
|
|
||||||
local f=function()
|
|
||||||
c=c or 0x6D6D6D
|
|
||||||
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
|
||||||
if kernel.status == "start" then
|
|
||||||
screen:setTextColor(c)
|
|
||||||
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
|
||||||
elseif kernel.status == "term" then
|
|
||||||
kernel.standbyTask=kernel.currentTask
|
|
||||||
kernel.currentTask=kernel.kernelTask
|
|
||||||
local file=kernel.vfs.open("/dev/console", "w")
|
|
||||||
kernel.vfs.devctl(file,"sfgc",c)
|
|
||||||
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
|
||||||
kernel.vfs.close(file)
|
|
||||||
kernel.currentTask=kernel.standbyTask
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok,err = xpcall(f,debug.traceback)
|
|
||||||
if not ok and not nopanic then
|
|
||||||
kernel.panic(err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.PANIC(msg)
|
|
||||||
if kernel.status~="Panic" then
|
|
||||||
kernel.log("PANIC: "..msg, "PANIC", 0xFF0000)
|
|
||||||
pcall(kernel["saveLog"])
|
|
||||||
kernel.status="Panic"
|
|
||||||
kernel.reason=msg
|
|
||||||
screen:enable()
|
|
||||||
screen:setTextColor(0xFF0000)
|
|
||||||
screen:setBackgroundColor(0x000000)
|
|
||||||
screen:clear()
|
|
||||||
screen:resetCursor()
|
|
||||||
screen:print(kernel.LOG_Text)
|
|
||||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
|
||||||
screen:print("Press any key to continue...")
|
|
||||||
kernel.exitMain = true
|
|
||||||
end
|
|
||||||
while true do
|
|
||||||
EFI:yield()
|
|
||||||
local event={EFI:getMachineEvent()}
|
|
||||||
if event[1]=="keyPressed" then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
EFI.reboot=true
|
|
||||||
error("KERNEL PANIC")
|
|
||||||
end
|
|
||||||
kernel.panic=kernel.PANIC
|
|
||||||
|
|
||||||
if windowsExp then
|
|
||||||
screen:setTextColor(0xFFFFFF)
|
|
||||||
screen:setBackgroundColor(0x0000FF)
|
|
||||||
screen:clear()
|
|
||||||
screen:resetCursor()
|
|
||||||
screen:print("\n\n\n\n\n :(")
|
|
||||||
screen:print("\n Your PC ran into a problem and needs to restart. We're just collecting some error")
|
|
||||||
screen:print(" info, and then we'll restart for you.\n")
|
|
||||||
screen:print("\n\n\n Stop code: average windows experience")
|
|
||||||
while true do end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.log("Kernel loaded.")
|
|
||||||
kernel.log("Mounting init disks...")
|
|
||||||
disks.refresh()
|
|
||||||
ifs.update(disks)
|
|
||||||
kernel.disks={}
|
|
||||||
for _,v in disks.list() do
|
|
||||||
kernel.disks[v.address] = v
|
|
||||||
end
|
|
||||||
ifs.mount("$", "/boot/")
|
|
||||||
|
|
||||||
local fstab=ifs.readAllText("/boot/fstab")
|
|
||||||
local split = function(str, delim, maxResultCountOrNil)
|
|
||||||
assert(#delim == 1, "only delim len 1 supported for now")
|
|
||||||
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
|
||||||
local rv = {}
|
|
||||||
local buf = ""
|
|
||||||
for i = 1, #str do
|
|
||||||
local c = string.sub(str,i,i)
|
|
||||||
if #rv ~= maxResultCountOrNil and c == delim then
|
|
||||||
table.insert(rv, buf)
|
|
||||||
buf = ""
|
|
||||||
else
|
|
||||||
buf = buf..c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(rv, buf)
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
if not ifs.isFile("/boot/boot.cfg") then
|
|
||||||
kernel.log("First boot detected writing boot.cfg", "INFO", 0x00FF00)
|
|
||||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
|
||||||
kernel.firstBoot=true
|
|
||||||
end
|
|
||||||
|
|
||||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
|
||||||
if not initCfgFunc then
|
|
||||||
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
|
|
||||||
end
|
|
||||||
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
|
||||||
local initCfgStatus, config = pcall(initCfgFunc)
|
|
||||||
if not initCfgStatus then
|
|
||||||
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
|
|
||||||
end
|
|
||||||
kernel.config = config
|
|
||||||
|
|
||||||
local skip=false
|
|
||||||
local root=false
|
|
||||||
for i,v in ipairs(split(fstab,"\n")) do
|
|
||||||
if v:sub(1,1)=="U" or v:sub(1,1)=="F" then
|
|
||||||
local id=""
|
|
||||||
for i=3,#v do
|
|
||||||
if v:sub(i,i)==";" then
|
|
||||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 0xFF8800) skip = true break end
|
|
||||||
id=v:sub(3,i-1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not skip then
|
|
||||||
local path=v:sub(#id+4)
|
|
||||||
if path=="/" then root=true end
|
|
||||||
ifs.mount(id,path)
|
|
||||||
else
|
|
||||||
skip=false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not root then kernel.panic("No disk mounted to /") end
|
|
||||||
kernel.log("Disks initialized")
|
|
||||||
|
|
||||||
function kernel.saveLog()
|
|
||||||
if kernel.status=="running" then
|
|
||||||
local file = kernel.vfs.open("/var/log/syslog.log", "w")
|
|
||||||
kernel.vfs.write(file, kernel.LOG_Text)
|
|
||||||
kernel.vfs.close(file)
|
|
||||||
else
|
|
||||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.newFifo()
|
|
||||||
local fifo = {}
|
|
||||||
fifo.push=function(data)
|
|
||||||
table.insert(fifo, data)
|
|
||||||
end
|
|
||||||
fifo.pop=function()
|
|
||||||
return table.remove(fifo,1)
|
|
||||||
end
|
|
||||||
return fifo
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.newUUID()
|
|
||||||
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
|
||||||
local uuid = ""
|
|
||||||
for i = 1, #template do
|
|
||||||
local c = template:sub(i,i)
|
|
||||||
if c == "x" then
|
|
||||||
uuid = uuid .. string.format("%x", math.random(0, 15))
|
|
||||||
elseif c == "y" then
|
|
||||||
uuid = uuid .. string.format("%x", math.random(8, 11))
|
|
||||||
else
|
|
||||||
uuid = uuid .. c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return uuid
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.sfile(str, writeable)
|
|
||||||
local buf = {str or ""}
|
|
||||||
local pos = 1
|
|
||||||
local closed = false
|
|
||||||
|
|
||||||
local function content()
|
|
||||||
return table.concat(buf)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function set_content(s)
|
|
||||||
buf = {s}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function flush()
|
|
||||||
str=content()
|
|
||||||
end
|
|
||||||
|
|
||||||
local file = {}
|
|
||||||
|
|
||||||
function file.read(n)
|
|
||||||
assert(not closed, "file is closed")
|
|
||||||
|
|
||||||
local s = content()
|
|
||||||
local len = #s
|
|
||||||
|
|
||||||
if not n then
|
|
||||||
local out = s:sub(pos)
|
|
||||||
pos = len + 1
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local out = s:sub(pos, pos + n - 1)
|
|
||||||
pos = pos + #out
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
if writeable then
|
|
||||||
function file.write(data)
|
|
||||||
assert(not closed, "file is closed")
|
|
||||||
|
|
||||||
local s = content()
|
|
||||||
local before = s:sub(1, pos - 1)
|
|
||||||
local after = s:sub(pos + #data)
|
|
||||||
|
|
||||||
set_content(before .. data .. after)
|
|
||||||
pos = pos + #data
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function file.seek(whence, offset)
|
|
||||||
assert(not closed, "file is closed")
|
|
||||||
|
|
||||||
local s = content()
|
|
||||||
local len = #s
|
|
||||||
|
|
||||||
whence = whence or "cur"
|
|
||||||
offset = offset or 0
|
|
||||||
|
|
||||||
if whence == "set" then
|
|
||||||
pos = offset + 1
|
|
||||||
elseif whence == "cur" then
|
|
||||||
pos = pos + offset
|
|
||||||
elseif whence == "end" then
|
|
||||||
pos = len + offset + 1
|
|
||||||
else
|
|
||||||
error("invalid whence")
|
|
||||||
end
|
|
||||||
|
|
||||||
if pos < 1 then pos = 1 end
|
|
||||||
if pos > len + 1 then pos = len + 1 end
|
|
||||||
|
|
||||||
return pos - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function file.close()
|
|
||||||
assert(not closed, "file is closed")
|
|
||||||
flush()
|
|
||||||
closed = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function file.flush()
|
|
||||||
assert(not closed, "file is closed")
|
|
||||||
flush()
|
|
||||||
end
|
|
||||||
|
|
||||||
function file.content()
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
return file
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.syscalls={}
|
|
||||||
local modules={[0]={}}
|
|
||||||
for i=0, 100 do
|
|
||||||
modules[i]={}
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.log("Gathering modules")
|
|
||||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
|
||||||
local modlist = ifs.list("/lib/modules/"..i)
|
|
||||||
if not modlist then
|
|
||||||
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 0xFF8800)
|
|
||||||
else
|
|
||||||
for _,v in ipairs(modlist) do
|
|
||||||
local prior=tonumber(v:sub(1,2))
|
|
||||||
if prior then
|
|
||||||
modules[prior+1][#modules[prior+1]+1]=i.."/"..v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.ifs=ifs
|
|
||||||
--pf
|
|
||||||
kernel.apis=EFI.firmware
|
|
||||||
--pf
|
|
||||||
kernel.EFI=EFI
|
|
||||||
kernel.arch=arch
|
|
||||||
kernel.initdisks=disks
|
|
||||||
kernel.screen=screen
|
|
||||||
kernel.processes={}
|
|
||||||
kernel.fstab=fstab
|
|
||||||
kernel.denied={}
|
|
||||||
kernel.loadingModule="kernel"
|
|
||||||
kernel.perTaskHooks={}
|
|
||||||
kernel.mainHooks={}
|
|
||||||
kernel.runhooks={}
|
|
||||||
|
|
||||||
-- args {taskobj}
|
|
||||||
function kernel.execPerTask(func, prior)
|
|
||||||
if not kernel.perTaskHooks[prior] then kernel.perTaskHooks[prior]={} end
|
|
||||||
kernel.perTaskHooks[prior][#kernel.perTaskHooks[prior]+1] = func
|
|
||||||
return #kernel.perTaskHooks[prior]
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.execOnMain(func)
|
|
||||||
kernel.mainHooks[#kernel.mainHooks+1] = func
|
|
||||||
return #kernel.mainHooks
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.runWhenLoaded(func)
|
|
||||||
kernel.runhooks[#kernel.runhooks+1] = func
|
|
||||||
return #kernel.runhooks
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.kernelTask = {
|
|
||||||
name="kernel",
|
|
||||||
status="R",
|
|
||||||
pid=0,
|
|
||||||
tgid=0,
|
|
||||||
uid=0,
|
|
||||||
fd={},
|
|
||||||
exit="",
|
|
||||||
sleep=0,
|
|
||||||
ivs=0,
|
|
||||||
vs=0,
|
|
||||||
children={},
|
|
||||||
syscallReturn={},
|
|
||||||
cwd="/",
|
|
||||||
timeSlice=0,
|
|
||||||
lastTime=0,
|
|
||||||
totalTime=0,
|
|
||||||
numRuns=0
|
|
||||||
}
|
|
||||||
kernel.currentTask = kernel.kernelTask
|
|
||||||
|
|
||||||
function kernel.shutdown()
|
|
||||||
kernel.exitMain=true
|
|
||||||
kernel.status="shutdown"
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.reboot()
|
|
||||||
kernel.exitMain=true
|
|
||||||
kernel.status="reboot"
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.halt()
|
|
||||||
kernel.exitMain=true
|
|
||||||
kernel.status="halt"
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.asyncReturn(...)
|
|
||||||
kernel.currentTask.syscallReturn = {...}
|
|
||||||
end
|
|
||||||
|
|
||||||
function kernel.deny(moduleid)
|
|
||||||
kernel.denied[moduleid]=true
|
|
||||||
if kernel.config.showModLoad then kernel.log("Module "..kernel.loadingModule.." denied "..moduleid, "DBUG", 0xFF0000) end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.syscalls["time"]=function() return kernel.EFI:getEpochMs() end
|
|
||||||
kernel.syscalls["date"]=function() return kernel.EFI:date() end
|
|
||||||
kernel.syscalls["log"]=kernel.log
|
|
||||||
kernel.syscalls["tag"]=function() return kernel.tag end
|
|
||||||
kernel.syscalls["getUptime"]=function() return kernel.EFI:getUptime() end
|
|
||||||
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
|
||||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
|
||||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
|
||||||
kernel.syscalls["version"]=function() return kernel.version end
|
|
||||||
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
|
|
||||||
kernel.syscalls["arch"]=function() return arch end
|
|
||||||
kernel.syscalls["sysdump"]=function()
|
|
||||||
local rv={}
|
|
||||||
for i,v in pairs(kernel.syscalls) do
|
|
||||||
rv[#rv+1] = i
|
|
||||||
end
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
kernel.syscalls["reboot"]=function()
|
|
||||||
if kernel.uid==0 or kernel.groups.wheel then
|
|
||||||
kernel.reboot()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
kernel.syscalls["shutdown"]=function()
|
|
||||||
if kernel.uid==0 or kernel.groups.wheel then
|
|
||||||
kernel.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
kernel.syscalls["halt"]=function()
|
|
||||||
if kernel.uid==0 or kernel.groups.wheel then
|
|
||||||
kernel.halt()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
kernel.syscalls["saveLog"]=function()
|
|
||||||
if kernel.uid==0 or kernel.groups.wheel then
|
|
||||||
kernel.saveLog()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.saveLog()
|
|
||||||
kernel.log("Running modules")
|
|
||||||
for _,p in ipairs(modules) do
|
|
||||||
for _,v in ipairs(p) do
|
|
||||||
kernel.loadingModule=v
|
|
||||||
if not kernel.denied[v] then
|
|
||||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 0x00FFFF) end
|
|
||||||
local code=ifs.readAllText("/lib/modules/"..v)
|
|
||||||
if not code then
|
|
||||||
kernel.panic("Failed to read module "..v)
|
|
||||||
end
|
|
||||||
local func,err=load(code,"@"..v)
|
|
||||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end
|
|
||||||
local status, err = xpcall(func,debug.traceback, kernel)
|
|
||||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
|
||||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
|
||||||
if kernel.config.moreLogsaves then kernel.saveLog() end
|
|
||||||
else
|
|
||||||
if kernel.config.showModLoad then kernel.log("Denied module "..v, "DBUG", 0xFF0000) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i=1, #kernel.runhooks do
|
|
||||||
local ok,err = xpcall(kernel.runhooks[i], debug.traceback)
|
|
||||||
if not ok then kernel.panic(err) end
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.log("Kernel initialized successfully.")
|
|
||||||
kernel.saveLog()
|
|
||||||
kernel.status="running"
|
|
||||||
kernel.loadingModule=nil
|
|
||||||
screen:disable()
|
|
||||||
if not kernel.main then kernel.panic("No scheduler implemented from firmware") end
|
|
||||||
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
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel = ...
|
|
||||||
|
|
||||||
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")
|
|
||||||
kernel.runWhenLoaded(function()
|
|
||||||
kernel.vfs.remove("/tmp")
|
|
||||||
kernel.vfs.mkdir("/tmp")
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel = ...
|
|
||||||
local signal = {}
|
|
||||||
kernel.signal=signal
|
|
||||||
|
|
||||||
function signal.sigsend(pid, sig)
|
|
||||||
if sig<0 or sig>256 then error("EINVAL") end
|
|
||||||
local task = kernel.tasks[tostring(pid)]
|
|
||||||
if not task then error("ENOENT") end
|
|
||||||
if not task.sigq then return end
|
|
||||||
task.sigq[#task.sigq+1] = sig
|
|
||||||
end
|
|
||||||
|
|
||||||
function signal.sigcatch(handler)
|
|
||||||
local task=kernel.currentTask
|
|
||||||
task.sigh=handler
|
|
||||||
if not task.sigq then task.sigq={} end
|
|
||||||
local handle={
|
|
||||||
error="",
|
|
||||||
active=true
|
|
||||||
}
|
|
||||||
if task.sigd then task.sigd.active=false; end
|
|
||||||
task.sigd=handle
|
|
||||||
return handle
|
|
||||||
end
|
|
||||||
|
|
||||||
function signal.sigignore()
|
|
||||||
local task=kernel.currentTask
|
|
||||||
task.sigh=nil
|
|
||||||
task.sigq=nil
|
|
||||||
if task.sigd then task.sigd.active=false end
|
|
||||||
task.sigd=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.execPerTask(function(task)
|
|
||||||
if task.status=="R" then
|
|
||||||
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
|
||||||
local coro = coroutine.create(task.sigh)
|
|
||||||
local status,err=coroutine.resume(coro, table.remove(task.sigq, 1))
|
|
||||||
EFI:yeild()
|
|
||||||
if status=="error" or status==false then
|
|
||||||
task.sigd.error=err or "Unknown"
|
|
||||||
task.sigd.active=false
|
|
||||||
task.sigh=nil
|
|
||||||
task.sigq=nil
|
|
||||||
task.sigd=nil
|
|
||||||
elseif status=="success" or status==true then
|
|
||||||
if err=="syscall" then
|
|
||||||
task.sigd.error="Cannot execute syscalls from signals"
|
|
||||||
task.sigd.active=false
|
|
||||||
task.sigh=nil
|
|
||||||
task.sigq=nil
|
|
||||||
task.sigd=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,2)
|
|
||||||
|
|
||||||
local s=kernel.syscalls
|
|
||||||
s["sigsend"] = signal.sigsend
|
|
||||||
s["sigcatch"] = signal.sigcatch
|
|
||||||
s["sigignore"] = signal.sigignore
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
--: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")
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel=...
|
|
||||||
kernel.unixSockets={}
|
|
||||||
local socket=kernel.socket
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Hyperion kernel package
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0:0:root:/root:/bin/hysh
|
||||||
-18
@@ -23,7 +23,6 @@ function string.split(str, delim, maxResultCountOrNil)
|
|||||||
assert(#delim == 1, "only delim len 1 supported for now")
|
assert(#delim == 1, "only delim len 1 supported for now")
|
||||||
if not str then return false end
|
if not str then return false end
|
||||||
maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
|
maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
|
||||||
if str == "" then return {} end
|
|
||||||
local rv = {}
|
local rv = {}
|
||||||
local buf = ""
|
local buf = ""
|
||||||
for i = 1, #str do
|
for i = 1, #str do
|
||||||
@@ -230,23 +229,6 @@ function toHex(num)
|
|||||||
return string.format("%X", num)
|
return string.format("%X", num)
|
||||||
end
|
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 function makeSyscallProxy()
|
||||||
local backing = {}
|
local backing = {}
|
||||||
return setmetatable(backing, {
|
return setmetatable(backing, {
|
||||||
+38
-187
@@ -2,7 +2,7 @@
|
|||||||
local kernel = ...
|
local kernel = ...
|
||||||
local vfs = {}
|
local vfs = {}
|
||||||
kernel.vfs = vfs
|
kernel.vfs = vfs
|
||||||
vfs.mounts = {}
|
vfs.mounts = {["$"] = "/"}
|
||||||
vfs.disks = kernel.disks
|
vfs.disks = kernel.disks
|
||||||
|
|
||||||
-- Metafile format (version 2)
|
-- Metafile format (version 2)
|
||||||
@@ -124,13 +124,11 @@ end
|
|||||||
|
|
||||||
local function validateComponent(comp)
|
local function validateComponent(comp)
|
||||||
local lower = comp:lower()
|
local lower = comp:lower()
|
||||||
if not comp:match(SAFE_COMPONENT_PATTERN) then
|
if not lower:match(SAFE_COMPONENT_PATTERN) then
|
||||||
error("EINVAL: illegal characters in path component: " .. comp, 3)
|
error("EINVAL: illegal characters in path component: " .. comp, 3)
|
||||||
end
|
end
|
||||||
if lower == ".meta" then
|
if lower == ".meta" then
|
||||||
error("EINVAL: reserved path component: .meta", 3)
|
error("EINVAL: reserved path component: .meta", 3)
|
||||||
elseif lower:sub(#lower) == "." then
|
|
||||||
error("Cannot have empty name extention: " .. comp, 3)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -276,7 +274,7 @@ local function namei(path, noFollow, symDepth)
|
|||||||
|
|
||||||
else
|
else
|
||||||
validateComponent(comp)
|
validateComponent(comp)
|
||||||
local lname = comp
|
local lname = comp:lower()
|
||||||
|
|
||||||
local curPath = "/" .. table.concat(stack, "/")
|
local curPath = "/" .. table.concat(stack, "/")
|
||||||
|
|
||||||
@@ -374,7 +372,7 @@ local function normalizePath(path)
|
|||||||
table.remove(stack)
|
table.remove(stack)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(stack, comp)
|
table.insert(stack, comp:lower())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -399,10 +397,6 @@ end
|
|||||||
local function getFileMeta(path, noFollow)
|
local function getFileMeta(path, noFollow)
|
||||||
local real = namei(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
|
|
||||||
if kernel.unixSockets[real] then
|
|
||||||
return kernel.unixSockets[real].meta
|
|
||||||
end
|
|
||||||
|
|
||||||
if real == "/" then
|
if real == "/" then
|
||||||
return { etype = 0x00, owner = 0, group = 0, perms = 62, cmeta = "" }
|
return { etype = 0x00, owner = 0, group = 0, perms = 62, cmeta = "" }
|
||||||
end
|
end
|
||||||
@@ -505,7 +499,7 @@ local function checkperms(meta, mode)
|
|||||||
local bitmap = {
|
local bitmap = {
|
||||||
r = {owner = 5, group = 3, everyone = 1},
|
r = {owner = 5, group = 3, everyone = 1},
|
||||||
w = {owner = 4, group = 2, everyone = 0},
|
w = {owner = 4, group = 2, everyone = 0},
|
||||||
a = {owner = 4, group = 2, everyone = 0}
|
a = {owner = 4, group = 2, everyone = 0},
|
||||||
}
|
}
|
||||||
local m = bitmap[mode]
|
local m = bitmap[mode]
|
||||||
if not m then error("EINVAL") end
|
if not m then error("EINVAL") end
|
||||||
@@ -542,7 +536,6 @@ local function allocFD(task)
|
|||||||
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
||||||
return fd
|
return fd
|
||||||
end
|
end
|
||||||
|
|
||||||
local function checkSystemLimit()
|
local function checkSystemLimit()
|
||||||
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
||||||
end
|
end
|
||||||
@@ -551,95 +544,33 @@ local function newFileObj(handle, mode, path, meta, ftype)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.newfd(fdobj)
|
function vfs.newfd(fdobj)
|
||||||
|
checkSystemLimit(); total = total + 1
|
||||||
local fd = allocFD(kernel.currentTask)
|
local fd = allocFD(kernel.currentTask)
|
||||||
kernel.currentTask.fd[fd] = fdobj
|
kernel.currentTask.fd[fd] = fdobj
|
||||||
return fd
|
return fd
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.mount(target, diskOrId, bind, floating)
|
function vfs.mount(target, diskOrId)
|
||||||
if not floating and target ~= "/" then
|
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
if _euid ~= 0 then error("EPERM") end
|
||||||
if _euid ~= 0 then error("EPERM") end
|
if not target then error("EINVAL") end
|
||||||
if not target then error("EINVAL") end
|
target = normalizeMountPoint(target)
|
||||||
target = normalizeMountPoint(target)
|
local drive, path = resolvePath(target)
|
||||||
local drive, path = resolvePath(target)
|
if not drive:directoryExists(path) then drive:makeDirectory(path) end
|
||||||
if not drive:directoryExists(path) then
|
if drive:type(target) ~= "directory" then error("EINVAL") end
|
||||||
drive:makeDirectory(path)
|
|
||||||
end
|
|
||||||
if drive:type(path) ~= "directory" then
|
|
||||||
error("EINVAL")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local disk, id
|
local disk, id
|
||||||
-- bind mount
|
if type(diskOrId) == "string" then
|
||||||
if bind then
|
disk = kernel.disks[diskOrId]
|
||||||
local src = normalizeMountPoint(diskOrId)
|
if not disk then error("ENODEV") end
|
||||||
local srcDrive = resolvePath(src)
|
checkDisk(disk); id = diskOrId
|
||||||
if not srcDrive then error("ENOENT") end
|
elseif type(diskOrId) == "table" then
|
||||||
id = "bind:" .. src
|
checkDisk(diskOrId); disk = diskOrId
|
||||||
disk = {
|
id = disk.address; vfs.disks[id] = disk
|
||||||
address = id,
|
else error("EINVAL") end
|
||||||
isBind = true,
|
|
||||||
source = srcDrive,
|
|
||||||
exists = function(_, p)
|
|
||||||
return srcDrive:exists(p)
|
|
||||||
end,
|
|
||||||
type = function(_, p)
|
|
||||||
return srcDrive:type(p)
|
|
||||||
end,
|
|
||||||
list = function(_, p)
|
|
||||||
return srcDrive:list(p)
|
|
||||||
end,
|
|
||||||
open = function(_, ...)
|
|
||||||
return srcDrive:open(...)
|
|
||||||
end,
|
|
||||||
remove = function(_, p)
|
|
||||||
return srcDrive:remove(p)
|
|
||||||
end,
|
|
||||||
makeDirectory = function(_, p)
|
|
||||||
return srcDrive:makeDirectory(p)
|
|
||||||
end,
|
|
||||||
rename = function(_, a, b)
|
|
||||||
return srcDrive:rename(a, b)
|
|
||||||
end,
|
|
||||||
size = function(_, p)
|
|
||||||
return srcDrive:size(p)
|
|
||||||
end,
|
|
||||||
lastModified = function(_, p)
|
|
||||||
return srcDrive:lastModified(p)
|
|
||||||
end,
|
|
||||||
isReadOnly = function()
|
|
||||||
return srcDrive:isReadOnly()
|
|
||||||
end,
|
|
||||||
spaceTotal = function()
|
|
||||||
return srcDrive:spaceTotal()
|
|
||||||
end,
|
|
||||||
spaceUsed = function()
|
|
||||||
return srcDrive:spaceUsed()
|
|
||||||
end
|
|
||||||
}
|
|
||||||
vfs.disks[id] = disk
|
|
||||||
else
|
|
||||||
if type(diskOrId) == "string" then
|
|
||||||
disk = vfs.disks[diskOrId]
|
|
||||||
if not disk then error("ENODEV") end
|
|
||||||
checkDisk(disk)
|
|
||||||
id = diskOrId
|
|
||||||
elseif type(diskOrId) == "table" then
|
|
||||||
checkDisk(diskOrId)
|
|
||||||
disk = diskOrId
|
|
||||||
id = disk.address
|
|
||||||
vfs.disks[id] = disk
|
|
||||||
else
|
|
||||||
error("EINVAL")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if vfs.mounts[id] then error("EBUSY") end
|
if vfs.mounts[id] then error("EBUSY") end
|
||||||
for _, mp in pairs(vfs.mounts) do
|
for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
|
||||||
if mp == target then
|
|
||||||
error("EBUSY")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vfs.mounts[id] = target
|
vfs.mounts[id] = target
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -652,11 +583,7 @@ function vfs.umount(target)
|
|||||||
for id, mp in pairs(vfs.mounts) do
|
for id, mp in pairs(vfs.mounts) do
|
||||||
if mp == target then
|
if mp == target then
|
||||||
if id == "$" then error("EBUSY") end
|
if id == "$" then error("EBUSY") end
|
||||||
vfs.mounts[id] = nil
|
vfs.mounts[id] = nil; return true
|
||||||
if vfs.disks[id] and vfs.disks[id].isBind then
|
|
||||||
vfs.disks[id] = nil
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
error("EINVAL")
|
error("EINVAL")
|
||||||
@@ -668,21 +595,6 @@ function vfs.open(path, mode)
|
|||||||
local fd = allocFD(task)
|
local fd = allocFD(task)
|
||||||
local disk, diskPath = resolvePath(path)
|
local disk, diskPath = resolvePath(path)
|
||||||
if not disk then error("NODISK") end
|
if not disk then error("NODISK") end
|
||||||
if (mode=="w" or mode=="a") and disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
|
|
||||||
if kernel.unixSockets[namei(path)] then
|
|
||||||
local meta = kernel.unixSockets[namei(path)].meta
|
|
||||||
if kernel.uid~=0 or kernel.uid~=meta.owner then
|
|
||||||
local groups = (task and task.groups) or kernel.groups or {}
|
|
||||||
local access=false
|
|
||||||
for _, gid in ipairs(groups) do
|
|
||||||
if gid == meta.group then access=true end
|
|
||||||
end
|
|
||||||
if not access then error("EACCES") end
|
|
||||||
end
|
|
||||||
task[fd]=kernel.unixSockets[namei(path)]
|
|
||||||
return fd
|
|
||||||
end
|
|
||||||
|
|
||||||
local meta = getFileMeta(path)
|
local meta = getFileMeta(path)
|
||||||
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
||||||
@@ -692,9 +604,7 @@ function vfs.open(path, mode)
|
|||||||
local handle
|
local handle
|
||||||
if disk:type(diskPath) ~= "directory" then
|
if disk:type(diskPath) ~= "directory" then
|
||||||
handle = disk:open(diskPath, mode)
|
handle = disk:open(diskPath, mode)
|
||||||
if type(handle, true) ~= "table" then
|
if type(handle) ~= "table" then error("ENFILE") end
|
||||||
error("ENFILE")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if isNew then
|
if isNew then
|
||||||
@@ -765,7 +675,7 @@ function vfs.close(fd)
|
|||||||
local task = kernel.currentTask
|
local task = kernel.currentTask
|
||||||
local file = task.fd[fd]
|
local file = task.fd[fd]
|
||||||
if not file then error("EBADF") end
|
if not file then error("EBADF") end
|
||||||
if not task.fd[fd].isvirt then
|
if not task.fd[fd].isvirt then
|
||||||
total = total - 1
|
total = total - 1
|
||||||
end
|
end
|
||||||
task.fd[fd] = nil
|
task.fd[fd] = nil
|
||||||
@@ -786,17 +696,10 @@ function vfs.sendfile(outfd, infd, count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.stat(path)
|
function vfs.stat(path)
|
||||||
local attrs
|
|
||||||
local disk, diskPath = resolvePath(path)
|
local disk, diskPath = resolvePath(path)
|
||||||
local meta = getFileMeta(path)
|
local meta = getFileMeta(path)
|
||||||
if meta.etype == 0x02 then
|
local ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||||
attrs = { size=0, modified=0, created=0 }
|
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||||
else
|
|
||||||
local ok
|
|
||||||
ok, attrs = pcall(disk.attributes, disk, diskPath)
|
|
||||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
size = attrs.size,
|
size = attrs.size,
|
||||||
modified = attrs.modified,
|
modified = attrs.modified,
|
||||||
@@ -811,15 +714,15 @@ end
|
|||||||
|
|
||||||
function vfs.lstat(path)
|
function vfs.lstat(path)
|
||||||
local meta = getFileMeta(path, true)
|
local meta = getFileMeta(path, true)
|
||||||
|
|
||||||
local attrs
|
local attrs
|
||||||
if meta.etype == 0x01 or meta.etype == 0x02 then
|
if meta.etype == 0x01 then
|
||||||
attrs = { size=0, modified=0, created=0 }
|
attrs = { size=0, modified=0, created=0 }
|
||||||
else
|
else
|
||||||
local disk, diskPath = resolvePath(path, true)
|
local disk, diskPath = resolvePath(path, true)
|
||||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
local ok, a = pcall(disk.attributes, disk, diskPath)
|
||||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
attrs = ok and a or { size=0, modified=0, created=0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
size = attrs.size,
|
size = attrs.size,
|
||||||
modified = attrs.modified,
|
modified = attrs.modified,
|
||||||
@@ -836,15 +739,8 @@ end
|
|||||||
function vfs.fstat(fd)
|
function vfs.fstat(fd)
|
||||||
local file = kernel.currentTask.fd[fd]
|
local file = kernel.currentTask.fd[fd]
|
||||||
if not file then error("EBADF") end
|
if not file then error("EBADF") end
|
||||||
local attrs
|
local disk, diskPath = resolvePath(file.path)
|
||||||
if file.meta.etype == 0x02 then
|
local attrs = disk:attributes(diskPath)
|
||||||
attrs = { size=0, modified=0, created=0 }
|
|
||||||
else
|
|
||||||
local disk, diskPath = resolvePath(file.path, true)
|
|
||||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
|
||||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
size = attrs.size,
|
size = attrs.size,
|
||||||
modified = attrs.modified,
|
modified = attrs.modified,
|
||||||
@@ -873,14 +769,6 @@ function vfs.listdir(path)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for k,v in pairs(kernel.unixSockets) do
|
|
||||||
local p=normalizePath(path)
|
|
||||||
if k:match("^(.*)/[^/]+$")==p then
|
|
||||||
seen[v.name]=true
|
|
||||||
table.insert(out, v.name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local mp
|
local mp
|
||||||
if diskPath == "/" then
|
if diskPath == "/" then
|
||||||
mp = ".meta"
|
mp = ".meta"
|
||||||
@@ -909,7 +797,6 @@ function vfs.mkdir(path)
|
|||||||
local parentMeta = getFileMeta(parent)
|
local parentMeta = getFileMeta(parent)
|
||||||
checkperms(parentMeta, "w")
|
checkperms(parentMeta, "w")
|
||||||
local disk, diskPath = resolvePath(path)
|
local disk, diskPath = resolvePath(path)
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
disk:makeDirectory(diskPath)
|
disk:makeDirectory(diskPath)
|
||||||
local task = kernel.currentTask
|
local task = kernel.currentTask
|
||||||
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||||
@@ -931,13 +818,8 @@ function vfs.remove(path)
|
|||||||
|
|
||||||
local meta = getFileMeta(path, true)
|
local meta = getFileMeta(path, true)
|
||||||
|
|
||||||
if kernel.unixSockets[namei(path)] then
|
if kernel.unixSockets and kernel.unixSockets[path] then
|
||||||
if kernel.uid ~= 0 then
|
kernel.unixSockets[path] = nil
|
||||||
if kernel.unixSockets[namei(path)].meta.owner~=kernel.uid then
|
|
||||||
error("EACCES")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
kernel.unixSockets[namei(path)] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if meta.etype == 0x01 then
|
if meta.etype == 0x01 then
|
||||||
@@ -946,7 +828,6 @@ function vfs.remove(path)
|
|||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
local name = norm:match("[^/]+$")
|
local name = norm:match("[^/]+$")
|
||||||
local disk, parentDiskPath = resolveMount(parent)
|
local disk, parentDiskPath = resolveMount(parent)
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
local mp
|
local mp
|
||||||
if parentDiskPath == "/" then mp = ".meta"
|
if parentDiskPath == "/" then mp = ".meta"
|
||||||
else mp = parentDiskPath:gsub("^/+", "") .. "/.meta" end
|
else mp = parentDiskPath:gsub("^/+", "") .. "/.meta" end
|
||||||
@@ -963,7 +844,6 @@ function vfs.remove(path)
|
|||||||
if f2.close then f2.close() end
|
if f2.close then f2.close() end
|
||||||
else
|
else
|
||||||
local disk, diskPath = resolvePath(path)
|
local disk, diskPath = resolvePath(path)
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
disk:remove(diskPath)
|
disk:remove(diskPath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -972,8 +852,6 @@ function vfs.symlink(target, linkPath)
|
|||||||
if type(target) ~= "string" or type(linkPath) ~= "string" then error("EINVAL") end
|
if type(target) ~= "string" or type(linkPath) ~= "string" then error("EINVAL") end
|
||||||
local norm = normalizePath(linkPath)
|
local norm = normalizePath(linkPath)
|
||||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
local disk = resolveMount(linkPath)
|
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
local name = norm:match("[^/]+$")
|
local name = norm:match("[^/]+$")
|
||||||
if not name then error("EINVAL") end
|
if not name then error("EINVAL") end
|
||||||
@@ -1003,13 +881,7 @@ function vfs.readlink(path)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.access(path, mode)
|
function vfs.access(path, mode)
|
||||||
local meta
|
local meta = getFileMeta(path)
|
||||||
if kernel.unixSockets[normalizePath(path)] then
|
|
||||||
meta = kernel.unixSockets[normalizePath(path)].meta
|
|
||||||
else
|
|
||||||
meta = getFileMeta(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, #mode do
|
for i = 1, #mode do
|
||||||
checkperms(meta, mode:sub(i,i))
|
checkperms(meta, mode:sub(i,i))
|
||||||
end
|
end
|
||||||
@@ -1020,8 +892,6 @@ local function updateMeta(path, fn, noFollow)
|
|||||||
local real = namei(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
local norm = real
|
local norm = real
|
||||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
local disk = resolveMount(path)
|
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
local name = norm:match("[^/]+$")
|
local name = norm:match("[^/]+$")
|
||||||
if not name then error("EINVAL") end
|
if not name then error("EINVAL") end
|
||||||
@@ -1048,9 +918,6 @@ local function updateMeta(path, fn, noFollow)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.chmod(path, perms)
|
function vfs.chmod(path, perms)
|
||||||
if kernel.unixSockets[namei(path)] then error("EINVAL") end
|
|
||||||
local disk = resolveMount(path)
|
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
local meta = getFileMeta(path)
|
local meta = getFileMeta(path)
|
||||||
local euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
local euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||||
if euid ~= 0 and euid ~= meta.owner then error("EACCES") end
|
if euid ~= 0 and euid ~= meta.owner then error("EACCES") end
|
||||||
@@ -1060,14 +927,10 @@ end
|
|||||||
function vfs.fchmod(fd, perms)
|
function vfs.fchmod(fd, perms)
|
||||||
local file = kernel.currentTask.fd[fd]
|
local file = kernel.currentTask.fd[fd]
|
||||||
if not file then error("EBADF") end
|
if not file then error("EBADF") end
|
||||||
if file.meta.etype==0x02 then error("EINVAL") end
|
|
||||||
vfs.chmod(file.path, perms)
|
vfs.chmod(file.path, perms)
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.chown(path, uid, gid)
|
function vfs.chown(path, uid, gid)
|
||||||
if kernel.unixSockets[namei(path)] then error("EINVAL") end
|
|
||||||
local disk = resolveMount(path)
|
|
||||||
if disk:isReadOnly() then error("ERDONLY") end
|
|
||||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||||
if _euid ~= 0 then error("EPERM") end
|
if _euid ~= 0 then error("EPERM") end
|
||||||
updateMeta(path, function(e) e.owner = uid; e.group = gid end)
|
updateMeta(path, function(e) e.owner = uid; e.group = gid end)
|
||||||
@@ -1076,14 +939,12 @@ end
|
|||||||
function vfs.fchown(fd, uid, gid)
|
function vfs.fchown(fd, uid, gid)
|
||||||
local file = kernel.currentTask.fd[fd]
|
local file = kernel.currentTask.fd[fd]
|
||||||
if not file then error("EBADF") end
|
if not file then error("EBADF") end
|
||||||
if file.meta.etype==0x02 then error("EINVAL") end
|
|
||||||
vfs.chown(file.path, uid, gid)
|
vfs.chown(file.path, uid, gid)
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.exists(path)
|
function vfs.exists(path)
|
||||||
if kernel.unixSockets[namei(path)] then return true end
|
|
||||||
local meta = getFileMeta(path, true)
|
local meta = getFileMeta(path, true)
|
||||||
if meta.etype == 0x01 or meta.etype == 0x02 then return true end
|
if meta.etype == 0x01 then return true end
|
||||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||||
if not ok then return false end
|
if not ok then return false end
|
||||||
if disk:type(diskPath) then
|
if disk:type(diskPath) then
|
||||||
@@ -1096,9 +957,6 @@ end
|
|||||||
function vfs.type(path)
|
function vfs.type(path)
|
||||||
local meta = getFileMeta(path, true)
|
local meta = getFileMeta(path, true)
|
||||||
if meta.etype == 0x01 then return "symlink" end
|
if meta.etype == 0x01 then return "symlink" end
|
||||||
if kernel.unixSockets[namei(path)] then
|
|
||||||
return "socket"
|
|
||||||
end
|
|
||||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||||
if not ok then return nil end
|
if not ok then return nil end
|
||||||
return disk:type(diskPath)
|
return disk:type(diskPath)
|
||||||
@@ -1151,12 +1009,6 @@ function vfs.devctl(fd, method, ...)
|
|||||||
return kernel.currentTask.fd[fd].handle[method](...)
|
return kernel.currentTask.fd[fd].handle[method](...)
|
||||||
end
|
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
|
vfs.resolveMount = resolveMount
|
||||||
|
|
||||||
local sys = kernel.syscalls
|
local sys = kernel.syscalls
|
||||||
@@ -1189,7 +1041,6 @@ sys["chroot"] = vfs.chroot
|
|||||||
sys["dup"] = vfs.dup
|
sys["dup"] = vfs.dup
|
||||||
sys["dup2"] = vfs.dup2
|
sys["dup2"] = vfs.dup2
|
||||||
sys["devctl"] = vfs.devctl
|
sys["devctl"] = vfs.devctl
|
||||||
sys["devlst"] = vfs.devlst
|
|
||||||
sys["symlink"] = vfs.symlink
|
sys["symlink"] = vfs.symlink
|
||||||
sys["readlink"] = vfs.readlink
|
sys["readlink"] = vfs.readlink
|
||||||
sys["access"] = vfs.access
|
sys["access"] = vfs.access
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
--: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
|
||||||
+8
-94
@@ -50,7 +50,7 @@ function proxy:type(path, mode)
|
|||||||
if type(step[steps[#steps]]) == "table" then
|
if type(step[steps[#steps]]) == "table" then
|
||||||
return "directory"
|
return "directory"
|
||||||
end
|
end
|
||||||
error("ENOENT")
|
error(type(step[steps[#steps]]))
|
||||||
end
|
end
|
||||||
|
|
||||||
function proxy:list(path)
|
function proxy:list(path)
|
||||||
@@ -140,91 +140,11 @@ function data.zero(op, mode)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function buildMeta(entries, opts)
|
if kernel.EFI:getEEPROM() then
|
||||||
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)
|
function data.eeprom(op, mode)
|
||||||
if op=="type" then
|
if op=="type" then
|
||||||
return "character device"
|
return "character device"
|
||||||
elseif op=="open" then
|
elseif op=="open" then
|
||||||
if kernel.uid~=0 then error("EACCES") end
|
|
||||||
if mode=="r" then
|
if mode=="r" then
|
||||||
local ptr,eeprom=1,kernel.EFI:getEEPROM()
|
local ptr,eeprom=1,kernel.EFI:getEEPROM()
|
||||||
return {
|
return {
|
||||||
@@ -234,6 +154,7 @@ if kernel.EFI.getEEPROM then
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
elseif mode=="w" then
|
elseif mode=="w" then
|
||||||
|
if kernel.uid~=0 then error("EACCES") end
|
||||||
local firstwrite=true
|
local firstwrite=true
|
||||||
return {
|
return {
|
||||||
write=function(data)
|
write=function(data)
|
||||||
@@ -245,6 +166,7 @@ if kernel.EFI.getEEPROM then
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
elseif mode=="a" then
|
elseif mode=="a" then
|
||||||
|
if kernel.uid~=0 then error("EACCES") end
|
||||||
return {
|
return {
|
||||||
write=function(data)
|
write=function(data)
|
||||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||||
@@ -256,12 +178,11 @@ if kernel.EFI.getEEPROM then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if kernel.EFI.getNvram then
|
if kernel.EFI:getNvram() then
|
||||||
function data.nvram(op, mode)
|
function data.nvram(op, mode)
|
||||||
if op=="type" then
|
if op=="type" then
|
||||||
return "character device"
|
return "character device"
|
||||||
elseif op=="open" then
|
elseif op=="open" then
|
||||||
if kernel.uid~=0 then error("EACCES") end
|
|
||||||
if mode=="r" then
|
if mode=="r" then
|
||||||
local ptr,nvram=1,kernel.EFI:getNvram()
|
local ptr,nvram=1,kernel.EFI:getNvram()
|
||||||
return {
|
return {
|
||||||
@@ -271,6 +192,7 @@ if kernel.EFI.getNvram then
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
elseif mode=="w" then
|
elseif mode=="w" then
|
||||||
|
if kernel.uid~=0 then error("EACCES") end
|
||||||
local firstwrite=true
|
local firstwrite=true
|
||||||
return {
|
return {
|
||||||
write=function(data)
|
write=function(data)
|
||||||
@@ -282,6 +204,7 @@ if kernel.EFI.getNvram then
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
elseif mode=="a" then
|
elseif mode=="a" then
|
||||||
|
if kernel.uid~=0 then error("EACCES") end
|
||||||
return {
|
return {
|
||||||
write=function(data)
|
write=function(data)
|
||||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||||
@@ -293,16 +216,7 @@ if kernel.EFI.getNvram then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
data["disk"]={["by-id"]={}, ["by-path"]={}, ["by-label"]={}}
|
data["disk"]={}
|
||||||
-- 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={}
|
||||||
kernel.devfs.data=data
|
kernel.devfs.data=data
|
||||||
kernel.devfs.proxy=proxy
|
kernel.devfs.proxy=proxy
|
||||||
+2
-3
@@ -6,7 +6,7 @@ local data = {}
|
|||||||
|
|
||||||
proxy.address = "procfs0000"
|
proxy.address = "procfs0000"
|
||||||
proxy.isvirt = true
|
proxy.isvirt = true
|
||||||
proxy.isReadOnly = function() return true end
|
proxy.isReadOnly = function() return false end
|
||||||
proxy.spaceUsed = function() return 0 end
|
proxy.spaceUsed = function() return 0 end
|
||||||
proxy.spaceTotal = function() return 0 end
|
proxy.spaceTotal = function() return 0 end
|
||||||
proxy.makeDirectory = function() error("EACCES") end
|
proxy.makeDirectory = function() error("EACCES") end
|
||||||
@@ -114,8 +114,7 @@ local function newtaskproxy(task)
|
|||||||
},
|
},
|
||||||
children={
|
children={
|
||||||
[".meta"]=strFile(buildMeta(children))
|
[".meta"]=strFile(buildMeta(children))
|
||||||
},
|
}
|
||||||
pid=strFile(task.pid)
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
--: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
|
||||||
+4
-3
@@ -11,7 +11,7 @@ end
|
|||||||
|
|
||||||
for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
||||||
line = trim(line)
|
line = trim(line)
|
||||||
if line:sub(1,1) == "U" or line:sub(1,1) == "V" or line:sub(1,1) == "F" then
|
if line ~= "" and line:sub(1,1) == "U" then
|
||||||
local semicolon_pos
|
local semicolon_pos
|
||||||
for i = 3, #line do
|
for i = 3, #line do
|
||||||
if line:sub(i,i) == ";" then
|
if line:sub(i,i) == ";" then
|
||||||
@@ -25,9 +25,10 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
|||||||
else
|
else
|
||||||
local id = line:sub(3, semicolon_pos - 1)
|
local id = line:sub(3, semicolon_pos - 1)
|
||||||
local path = trim(line:sub(semicolon_pos + 1))
|
local path = trim(line:sub(semicolon_pos + 1))
|
||||||
kernel.log("Mounting '"..id.."' to '"..path.."'")
|
|
||||||
kernel.vfs.mount(path, id, nil, line:sub(1,1) == "F")
|
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
kernel.log("Mounted "..id.." to "..path)
|
||||||
|
if id ~= "$" then
|
||||||
|
kernel.vfs.mount(path, id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
local signal = {}
|
||||||
|
kernel.signal=signal
|
||||||
|
|
||||||
|
function signal.sigsend(pid, sig)
|
||||||
|
if sig<0 or sig>256 then error("EINVAL") end
|
||||||
|
local task = kernel.tasks[tostring(pid)]
|
||||||
|
if not task then error("ENOENT") end
|
||||||
|
if not task.sigq then return end
|
||||||
|
task.sigq[#task.sigq+1] = sig
|
||||||
|
end
|
||||||
|
|
||||||
|
function signal.sigcatch(handler)
|
||||||
|
kernel.currentTask.sigh=handler
|
||||||
|
if not kernel.currentTask.sigq then kernel.currentTask.sigq={} end
|
||||||
|
end
|
||||||
|
|
||||||
|
function signal.sigignore()
|
||||||
|
kernel.currentTask.sigh=nil
|
||||||
|
kernel.currentTask.sigq=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local s=kernel.syscalls
|
||||||
|
s["sigsend"] = signal.sigsend
|
||||||
|
s["sigcatch"] = signal.sigcatch
|
||||||
|
s["sigignore"] = signal.sigignore
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
--: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={}
|
||||||
|
kernel.socket=socket
|
||||||
|
|
||||||
|
|
||||||
|
kernel.log("Loaded socket module")
|
||||||
+8
-17
@@ -150,26 +150,17 @@ end
|
|||||||
local pepper = getFile("/etc/pam.d/secret")
|
local pepper = getFile("/etc/pam.d/secret")
|
||||||
|
|
||||||
local function genSalt()
|
local function genSalt()
|
||||||
return toHex(math.random(0,2^32))
|
local chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
|
||||||
|
local s = ""
|
||||||
|
for i = 1, 16 do
|
||||||
|
s = s .. chars:sub(math.random(1, #chars), math.random(1, #chars))
|
||||||
|
end
|
||||||
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
local function hashPassword(password, salt)
|
local function hashPassword(password, salt)
|
||||||
local key = (pepper .. salt)
|
local key = (pepper .. salt):sub(1, 32)
|
||||||
return blake2s(password..salt, key)
|
return blake2s(password, key)
|
||||||
end
|
|
||||||
|
|
||||||
if not kernel.vfs.exists("/etc/passwd") then
|
|
||||||
kernel.log("PASSWD FILE NOT FOUND CREATING...", "WARN", 0xFF8800)
|
|
||||||
local handle = kernel.vfs.open("/etc/passwd", "w")
|
|
||||||
kernel.vfs.write(handle, "0:0:root:/root:/bin/hysh")
|
|
||||||
kernel.vfs.close(handle)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not kernel.vfs.exists("/etc/shadow") then
|
|
||||||
kernel.log("SHADOW FILE NOT FOUND CREATING...", "WARN", 0xFF8800)
|
|
||||||
local handle = kernel.vfs.open("/etc/shadow", "w")
|
|
||||||
kernel.vfs.write(handle, "")
|
|
||||||
kernel.vfs.close(handle)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local passwdFile = getFile("/etc/passwd")
|
local passwdFile = getFile("/etc/passwd")
|
||||||
+169
-81
@@ -5,6 +5,7 @@ local sys = {}
|
|||||||
local nextpid = 2
|
local nextpid = 2
|
||||||
kernel.exitMain = false
|
kernel.exitMain = false
|
||||||
|
|
||||||
|
local resumeWithTimeout = coroutine.resumeWithTimeout
|
||||||
|
|
||||||
local function bit_is_set(num, bit)
|
local function bit_is_set(num, bit)
|
||||||
return math.floor(num / (2 ^ bit)) % 2 == 1
|
return math.floor(num / (2 ^ bit)) % 2 == 1
|
||||||
@@ -20,7 +21,7 @@ local function loadExecutable(path)
|
|||||||
local env = kernel.freshUserEnv()
|
local env = kernel.freshUserEnv()
|
||||||
|
|
||||||
local func, err = load(data, "@" .. path, "t", env)
|
local func, err = load(data, "@" .. path, "t", env)
|
||||||
if not func then kernel.log("Failed to load executable: " .. tostring(err).. " : ".. tostring(path)); error("ENOEXEC: " .. tostring(err)) end
|
if not func then error("ENOEXEC: " .. tostring(err)) end
|
||||||
|
|
||||||
local meta = kernel.vfs.lstat(path)
|
local meta = kernel.vfs.lstat(path)
|
||||||
local suid_set = bit_is_set(meta.perms, 6)
|
local suid_set = bit_is_set(meta.perms, 6)
|
||||||
@@ -30,18 +31,10 @@ local function loadExecutable(path)
|
|||||||
return func, euid, suid_set
|
return func, euid, suid_set
|
||||||
end
|
end
|
||||||
|
|
||||||
local function createTask(func, name, envars, args, tgid, real_uid, eff_uid, clearFds)
|
local function createTask(func, name, envars, args, tgid, real_uid, eff_uid)
|
||||||
local id = nextpid
|
local id = nextpid
|
||||||
nextpid = nextpid + 1
|
nextpid = nextpid + 1
|
||||||
|
|
||||||
local fds={}
|
|
||||||
if not clearFds then
|
|
||||||
for id, file in pairs(kernel.currentTask.fd) do
|
|
||||||
file.refcount=file.refcount+1
|
|
||||||
fds[id]=file
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
tasks[tostring(id)] = {
|
tasks[tostring(id)] = {
|
||||||
coro = coroutine.create(function()
|
coro = coroutine.create(function()
|
||||||
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {}))
|
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {}))
|
||||||
@@ -78,7 +71,7 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid, cle
|
|||||||
euid = eff_uid,
|
euid = eff_uid,
|
||||||
gid = (kernel.currentTask and kernel.currentTask.gid) or 0,
|
gid = (kernel.currentTask and kernel.currentTask.gid) or 0,
|
||||||
groups = (kernel.currentTask and kernel.currentTask.groups) or {},
|
groups = (kernel.currentTask and kernel.currentTask.groups) or {},
|
||||||
fd = fds,
|
fd = {},
|
||||||
sleep = 0,
|
sleep = 0,
|
||||||
ivs = 0,
|
ivs = 0,
|
||||||
vs = 0,
|
vs = 0,
|
||||||
@@ -100,14 +93,14 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid, cle
|
|||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.spawn(func, name, envars, args, tgid, clearFds)
|
function sys.spawn(func, name, envars, args, tgid)
|
||||||
local caller = kernel.currentTask
|
local caller = kernel.currentTask
|
||||||
local real_uid = caller and caller.uid or kernel.uid
|
local real_uid = caller and caller.uid or kernel.uid
|
||||||
local eff_uid = caller and caller.euid or real_uid
|
local eff_uid = caller and caller.euid or real_uid
|
||||||
return createTask(func, name, envars, args, tgid, real_uid, eff_uid, clearFds)
|
return createTask(func, name, envars, args, tgid, real_uid, eff_uid)
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.execspawn(path, name, envars, args, tgid, keepFds)
|
function sys.execspawn(path, name, envars, args, tgid)
|
||||||
local func, euid, suid_active = loadExecutable(path, kernel._U)
|
local func, euid, suid_active = loadExecutable(path, kernel._U)
|
||||||
|
|
||||||
local caller = kernel.currentTask
|
local caller = kernel.currentTask
|
||||||
@@ -121,7 +114,7 @@ function sys.execspawn(path, name, envars, args, tgid, keepFds)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
return createTask(func, name or path, envars, args, tgid, real_uid, euid, not keepFds)
|
return createTask(func, name or path, envars, args, tgid, real_uid, euid)
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.exec(path, args, envars)
|
function sys.exec(path, args, envars)
|
||||||
@@ -136,7 +129,7 @@ function sys.exec(path, args, envars)
|
|||||||
|
|
||||||
task.euid = euid
|
task.euid = euid
|
||||||
task.args = args or {}
|
task.args = args or {}
|
||||||
task.envars = envars or task.envars or {}
|
task.envars = envars or task.envars
|
||||||
task.name = path
|
task.name = path
|
||||||
|
|
||||||
task.coro = coroutine.create(function()
|
task.coro = coroutine.create(function()
|
||||||
@@ -157,11 +150,13 @@ function sys.exec(path, args, envars)
|
|||||||
tasks[tostring(task.pid)].status = "Z"
|
tasks[tostring(task.pid)].status = "Z"
|
||||||
end)
|
end)
|
||||||
task.syscallReturn = {}
|
task.syscallReturn = {}
|
||||||
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.sleep(s)
|
function sys.sleep(s)
|
||||||
kernel.currentTask.status = "S"
|
kernel.currentTask.status = "S"
|
||||||
kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000
|
kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000
|
||||||
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.getTask(pid)
|
function sys.getTask(pid)
|
||||||
@@ -209,16 +204,12 @@ function sys.collect(pid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.kill(pid, force)
|
function sys.kill(pid)
|
||||||
local task = tasks[tostring(pid)]
|
local task = tasks[tostring(pid)]
|
||||||
if not task then
|
if not task then
|
||||||
return false, "Task does not exist"
|
return false, "Task does not exist"
|
||||||
elseif task.status == "Z" then
|
elseif task.status == "Z" then
|
||||||
return false, "Task is already dead"
|
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
|
end
|
||||||
local caller = kernel.currentTask
|
local caller = kernel.currentTask
|
||||||
local ceuid = caller and (caller.euid or caller.uid) or kernel.uid
|
local ceuid = caller and (caller.euid or caller.uid) or kernel.uid
|
||||||
@@ -233,16 +224,10 @@ function sys.stop(pid)
|
|||||||
local task = tasks[tostring(pid)]
|
local task = tasks[tostring(pid)]
|
||||||
if not task then
|
if not task then
|
||||||
return false, "Task does not exist"
|
return false, "Task does not exist"
|
||||||
elseif task.status ~= "R" and task.status ~= "S" then
|
elseif task.status ~= "R" then
|
||||||
return false, "Cannot stop non-running task"
|
return false, "Cannot stop non-running task"
|
||||||
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
|
||||||
return false, "Different user"
|
|
||||||
else
|
else
|
||||||
if task.status == "S" then
|
task.status = "T"
|
||||||
task.status = "ST"
|
|
||||||
else
|
|
||||||
task.status = "T"
|
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -251,16 +236,10 @@ function sys.continue(pid)
|
|||||||
local task = tasks[tostring(pid)]
|
local task = tasks[tostring(pid)]
|
||||||
if not task then
|
if not task then
|
||||||
return false, "Task does not exist"
|
return false, "Task does not exist"
|
||||||
elseif task.status ~= "T" and task.status ~= "ST" then
|
elseif task.status ~= "T" then
|
||||||
return false, "Task is not stopped"
|
return false, "Task is not stopped"
|
||||||
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
|
||||||
return false, "Different user"
|
|
||||||
else
|
else
|
||||||
if task.status == "ST" then
|
task.status = "R"
|
||||||
task.status = "S"
|
|
||||||
else
|
|
||||||
task.status = "R"
|
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -308,24 +287,23 @@ end
|
|||||||
|
|
||||||
function sys.getuid() return kernel.currentTask.uid end
|
function sys.getuid() return kernel.currentTask.uid end
|
||||||
|
|
||||||
function sys.reapDeadTasks()
|
local function reapDeadTasks()
|
||||||
for pid, task in pairs(tasks) do
|
for pid, task in pairs(tasks) do
|
||||||
if task.status == "Z" and not task.reapTime then
|
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.coro = nil
|
task.ivs = nil
|
||||||
task.ivs = nil
|
task.vs = nil
|
||||||
task.vs = nil
|
task.args = nil
|
||||||
task.args = nil
|
task.envars = nil
|
||||||
task.envars = nil
|
task.cwd = nil
|
||||||
task.cwd = nil
|
task.numRuns = nil
|
||||||
task.numRuns = nil
|
task.totalTime = nil
|
||||||
task.totalTime = nil
|
task.lastTime = nil
|
||||||
task.lastTime = nil
|
task.timeSlice = nil
|
||||||
task.timeSlice = nil
|
|
||||||
task.syscallReturn = nil
|
task.syscallReturn = nil
|
||||||
task.sleep = nil
|
task.sleep = nil
|
||||||
task.fd = nil
|
task.fd = nil
|
||||||
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
||||||
|
|
||||||
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
||||||
and task.status == "Z" then
|
and task.status == "Z" then
|
||||||
@@ -345,41 +323,151 @@ function sys.reapDeadTasks()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.execPerTask(function(task)
|
local alpha = 0.85
|
||||||
kernel.currentTask = task
|
local C_target = 0.01
|
||||||
kernel.uid = task.euid or task.uid
|
local Tmin = 0.0005
|
||||||
kernel.process = task.name
|
local Tmax = 0.5
|
||||||
|
local lambda_budget = 0.08
|
||||||
|
local lambda_clamp = 0.03
|
||||||
|
local lambda_var = 0.02
|
||||||
|
local k_min = 0.5
|
||||||
|
local k_max = 0.5
|
||||||
|
local B = 0.01
|
||||||
|
|
||||||
if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then
|
function kernel.main()
|
||||||
task.status = "R"
|
while not kernel.exitMain do
|
||||||
task.sleep = 0
|
local N = 0
|
||||||
end
|
local Tmin_hit = 0
|
||||||
|
local Tmax_hit = 0
|
||||||
|
local totalTaskTime = 0
|
||||||
|
local taskTimes = {}
|
||||||
|
|
||||||
if task.status == "ST" and kernel.EFI:getEpochMs() >= task.sleep then
|
for pid, task in pairs(tasks) do
|
||||||
task.status = "T"
|
if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||||
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.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.status = "R"
|
||||||
task.io=nil
|
task.sleep = 0
|
||||||
elseif #ret>1 then
|
end
|
||||||
task.syscallReturn = {true, table.unpack(ret, 2)}
|
|
||||||
task.status = "R"
|
if task.status == "R" then
|
||||||
task.io=nil
|
kernel.currentTask = task
|
||||||
|
|
||||||
|
kernel.uid = task.euid or task.uid
|
||||||
|
kernel.process = task.name
|
||||||
|
N = N + 1
|
||||||
|
|
||||||
|
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
||||||
|
|
||||||
|
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
||||||
|
local coro = coroutine.create(task.sigh)
|
||||||
|
local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) }
|
||||||
|
while coroutine.status(coro) ~= "dead" do
|
||||||
|
if sigret[1] == false then break end
|
||||||
|
if sigret[2] == "syscall" then
|
||||||
|
local scname = sigret[3]
|
||||||
|
local sysret
|
||||||
|
if kernel.syscalls[scname] then
|
||||||
|
sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(sigret, 4)) }
|
||||||
|
else
|
||||||
|
sysret = { false, "Unknown syscall: " .. tostring(scname) }
|
||||||
|
end
|
||||||
|
if not sysret[1] then
|
||||||
|
sigret = { coroutine.resume(coro, false, sysret[2]) }
|
||||||
|
else
|
||||||
|
sigret = { coroutine.resume(coro, true, table.unpack(sysret, 2)) }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
sigret = { coroutine.resume(coro) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if task.status == "R" then
|
||||||
|
local startTime = kernel.EFI:getEpochMs()
|
||||||
|
local ret
|
||||||
|
|
||||||
|
if kernel.config.preempt then
|
||||||
|
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||||
|
else
|
||||||
|
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
local elapsed = kernel.EFI:getEpochMs() - startTime
|
||||||
|
task.lastTime = elapsed
|
||||||
|
task.totalTime = (task.totalTime or 0) + elapsed
|
||||||
|
task.numRuns = (task.numRuns or 0) + 1
|
||||||
|
|
||||||
|
taskTimes[#taskTimes+1] = elapsed
|
||||||
|
totalTaskTime = totalTaskTime + elapsed
|
||||||
|
|
||||||
|
if elapsed <= Tmin then Tmin_hit = Tmin_hit + 1 end
|
||||||
|
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
||||||
|
|
||||||
|
if ret[1] == "error" or ret[1] == false then
|
||||||
|
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 0xFF0000)
|
||||||
|
task.status = "Z"
|
||||||
|
task.exit = "processHandlerException: " .. tostring(ret[2])
|
||||||
|
|
||||||
|
elseif ret[1] == "timeout" then
|
||||||
|
task.ivs = task.ivs + 1
|
||||||
|
task.syscallReturn = {}
|
||||||
|
|
||||||
|
elseif ret[1] == "success" or ret[1] == true then
|
||||||
|
task.vs = task.vs + 1
|
||||||
|
|
||||||
|
if ret[2] == "syscall" then
|
||||||
|
local scname = ret[3]
|
||||||
|
if kernel.syscalls[scname] then
|
||||||
|
if kernel.config.debugSyscalls then
|
||||||
|
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 0x00FFFF)
|
||||||
|
for i = 4, #ret do
|
||||||
|
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 0x00FFFF)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(ret, 4)) }
|
||||||
|
|
||||||
|
if kernel.config.debugSyscalls then
|
||||||
|
if not sysret[1] then
|
||||||
|
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 0xFF0000)
|
||||||
|
else
|
||||||
|
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 0x00FFFF)
|
||||||
|
for i = 2, #sysret do
|
||||||
|
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
||||||
|
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not sysret[1] then
|
||||||
|
task.syscallReturn = { false, sysret[2] }
|
||||||
|
else
|
||||||
|
task.syscallReturn = { true, table.unpack(sysret, 2) }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
task.syscallReturn = { false, "Unknown syscall: " .. tostring(scname) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
|
||||||
|
local T_prev_var = 0
|
||||||
|
for _, t in ipairs(taskTimes) do
|
||||||
|
T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
|
||||||
|
end
|
||||||
|
if N > 0 then T_prev_var = T_prev_var / N end
|
||||||
|
|
||||||
|
if N > 0 then
|
||||||
|
local f_clamp = k_min * (Tmin_hit / N) - k_max * (Tmax_hit / N)
|
||||||
|
local B_budget = (C_target * (N ^ (alpha - 1))) / math.max(T_prev_avg, 1e-8)
|
||||||
|
B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp - lambda_var * T_prev_var
|
||||||
|
end
|
||||||
|
|
||||||
|
reapDeadTasks()
|
||||||
end
|
end
|
||||||
end,1)
|
end
|
||||||
|
|
||||||
local sysc = kernel.syscalls
|
local sysc = kernel.syscalls
|
||||||
sysc["spawn"] = sys.spawn
|
sysc["spawn"] = sys.spawn
|
||||||
-21
@@ -19,25 +19,4 @@ function printInline(...)
|
|||||||
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
|
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
|
||||||
output = output:sub(1, -2)
|
output = output:sub(1, -2)
|
||||||
syscall.write(1, output)
|
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
|
end
|
||||||
-1
@@ -25,7 +25,6 @@ kernel.tasks["1"] = {
|
|||||||
else
|
else
|
||||||
kernel.panic("Init system exited: " .. tostring(err))
|
kernel.panic("Init system exited: " .. tostring(err))
|
||||||
end
|
end
|
||||||
kernel.saveLog()
|
|
||||||
end),
|
end),
|
||||||
|
|
||||||
name = "sysinit",
|
name = "sysinit",
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
--: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
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.5.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Lua
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Bit32 package for Hyperion
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
blake2s package for Hyperion
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Hyperion
|
|
||||||
Astronand
|
|
||||||
Spsf
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
--: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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
core utilities for user management
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1.0.0
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user