diff --git a/atlas_os/MMC.lua b/atlas_os/MMC.lua index 6c32c05..005c1f4 100644 --- a/atlas_os/MMC.lua +++ b/atlas_os/MMC.lua @@ -9,6 +9,169 @@ local SEG_SIZE = 8192 local MAX_INODES = 64 local ROOT_INO = 1 +local _unpack = table.unpack or unpack + +-- === LZ4 compression (pure Lua) === + +function lz4Compress(data) + local n = #data + if n == 0 then return "" end + local ht, res, ip, anchor = {}, {}, 1, 1 + local hashSize = 4096 + local function hash4(p) + return (((data:byte(p) * 256 + data:byte(p + 1)) * 256 + data:byte(p + 2)) * 256 + data:byte(p + 3)) % hashSize + end + while ip + 3 <= n do + local h = hash4(ip) + local ref = ht[h] + ht[h] = ip + if ref and ip - ref <= 65535 and data:byte(ref) == data:byte(ip) + and data:byte(ref + 1) == data:byte(ip + 1) + and data:byte(ref + 2) == data:byte(ip + 2) + and data:byte(ref + 3) == data:byte(ip + 3) then + local ml = 4 + while ip + ml <= n and data:byte(ref + ml) == data:byte(ip + ml) do ml = ml + 1 end + local litLen = ip - anchor + local matchLen = ml - 4 + local tokLit = litLen < 15 and litLen or 15 + local tokMatch = matchLen < 15 and matchLen or 15 + res[#res + 1] = string.char(tokLit * 16 + tokMatch) + if litLen >= 15 then + local e = litLen - 15 + while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end + res[#res + 1] = string.char(e) + end + if litLen > 0 then res[#res + 1] = data:sub(anchor, ip - 1) end + local off = ip - ref + res[#res + 1] = string.char(off % 256) + res[#res + 1] = string.char(math.floor(off / 256)) + if matchLen >= 15 then + local e = matchLen - 15 + while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end + res[#res + 1] = string.char(e) + end + ip = ip + ml + anchor = ip + else + ip = ip + 1 + end + end + local last = n - anchor + 1 + if last > 0 then + local tokLit = last < 15 and last or 15 + res[#res + 1] = string.char(tokLit * 16) + if last >= 15 then + local e = last - 15 + while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end + res[#res + 1] = string.char(e) + end + res[#res + 1] = data:sub(anchor, n) + end + return table.concat(res) +end + +function lz4Decompress(compressed) + local pos, out, oi = 1, {}, 1 + local n = #compressed + while pos <= n do + local token = compressed:byte(pos); pos = pos + 1 + local litLen = math.floor(token / 16) + if litLen == 15 then + local s + repeat s = compressed:byte(pos); pos = pos + 1; litLen = litLen + s until s < 255 + end + for _ = 1, litLen do out[oi] = compressed:byte(pos); oi = oi + 1; pos = pos + 1 end + if pos > n then break end + local off = compressed:byte(pos) + compressed:byte(pos + 1) * 256; pos = pos + 2 + local matchLen = (token % 16) + 4 + if matchLen == 19 then + local s + repeat s = compressed:byte(pos); pos = pos + 1; matchLen = matchLen + s until s < 255 + end + local mp = oi - off + for _ = 1, matchLen do out[oi] = out[mp]; oi = oi + 1; mp = mp + 1 end + end + return string.char(_unpack(out)) +end + +local b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +local b64dec = {} +for i = 1, 64 do b64dec[b64:sub(i, i)] = i - 1 end + +function encode(s) + local out, i, n = {}, 1, #s + while i <= n do + local a, b, c = s:byte(i), s:byte(i + 1), s:byte(i + 2) + out[#out + 1] = b64:sub(math.floor(a / 4) + 1, math.floor(a / 4) + 1) + out[#out + 1] = b64:sub((a % 4) * 16 + math.floor((b or 0) / 16) + 1, (a % 4) * 16 + math.floor((b or 0) / 16) + 1) + if i + 1 > n then + out[#out + 1] = "=" + else + out[#out + 1] = b64:sub(((b or 0) % 16) * 4 + math.floor((c or 0) / 64) + 1, ((b or 0) % 16) * 4 + math.floor((c or 0) / 64) + 1) + end + if i + 2 > n then + out[#out + 1] = "=" + else + out[#out + 1] = b64:sub(((c or 0) % 64) + 1, ((c or 0) % 64) + 1) + end + i = i + 3 + end + return table.concat(out) +end + +function decode(str) + local out, i, n = {}, 1, #str + while i <= n and str:sub(i, i) ~= "=" do + local a = b64dec[str:sub(i, i)] or 0 + local b = b64dec[str:sub(i + 1, i + 1)] or 0 + local c = b64dec[str:sub(i + 2, i + 2)] or 0 + local d = b64dec[str:sub(i + 3, i + 3)] or 0 + out[#out + 1] = string.char(a * 4 + math.floor(b / 16)) + if str:sub(i + 2, i + 2) ~= "=" then + out[#out + 1] = string.char((b % 16) * 16 + math.floor(c / 4)) + end + if str:sub(i + 3, i + 3) ~= "=" then + out[#out + 1] = string.char((c % 4) * 64 + d) + end + i = i + 4 + end + return table.concat(out) +end + +local function escRaw(s) + s = s:gsub("\x01", "\x01\x01") + s = s:gsub("\n", "\x01n") + return s +end + +local function unescRaw(s) + local out, i, n = {}, 1, #s + while i <= n do + local b = s:byte(i) + if b == 1 then + i = i + 1 + out[#out + 1] = s:byte(i) == 1 and "\x01" or "\n" + else + out[#out + 1] = s:sub(i, i) + end + i = i + 1 + end + return table.concat(out) +end + +function compressStr(s) + local lz = encode(lz4Compress(s)) + if #lz < #s then return lz end + return "\x01" .. escRaw(s) +end + +function decompressStr(c) + if c:byte(1) == 1 then return unescRaw(c:sub(2)) end + return lz4Decompress(decode(c)) +end + +-- ================================ + local function parseMsg(msg) local p = msg:find("|") return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil @@ -29,7 +192,7 @@ local files = {} local users = {} local sb = { seg_size = SEG_SIZE, max_inodes = MAX_INODES, root_ino = ROOT_INO } -local function fsSerialize() +function fsSerialize() local lines = {} lines[#lines + 1] = "V|1" lines[#lines + 1] = "S|" .. sb.seg_size .. "|" .. sb.max_inodes .. "|" .. sb.root_ino @@ -47,7 +210,7 @@ local function fsSerialize() end lines[#lines + 1] = "D|" .. ino.ino .. "|" .. table.concat(entries, "|") elseif ino.typ == "f" and files[ino.ino] then - lines[#lines + 1] = "F|" .. ino.ino .. "|" .. files[ino.ino] + lines[#lines + 1] = "Z|" .. ino.ino .. "|" .. files[ino.ino] end end end @@ -96,15 +259,15 @@ local function fsDeserialize(str) end dirs[ino] = entries end - elseif typ == "F" then + elseif typ == "Z" then local parts = split(rest, "|") if #parts >= 2 then local ino = tonumber(parts[1]) - local content = parts[2] or "" + local b64 = parts[2] or "" for i = 3, #parts do - content = content .. "|" .. parts[i] + b64 = b64 .. "|" .. parts[i] end - files[ino] = content + files[ino] = b64 end end end @@ -161,8 +324,8 @@ local function processReq(req) local ino = findInodeByPath(path) if not ino then return "ERR|" .. seqStr .. "ENOENT" end if ino.typ ~= "f" then return "ERR|" .. seqStr .. "EISDIR" end - local content = files[ino.ino] or "" - local data = content:sub(offset + 1, offset + len) + local raw = decompressStr(files[ino.ino]) or "" + local data = raw:sub(offset + 1, offset + len) return "OK|" .. seqStr .. data elseif op == "LS" then @@ -197,187 +360,110 @@ local function processReq(req) return "ERR|" .. seqStr .. "EINVAL" end -local function defaultFS() +-- Exported FS API for external tools (generators, tests) +FS = {} + +function FS.init() inodes = {} dirs = {} files = {} users = {} + sb = { seg_size = SEG_SIZE, max_inodes = MAX_INODES, root_ino = ROOT_INO } + inodes[1] = { ino = 1, typ = "d", mode = "755", uid = 0, gid = 0, size = 0, mtime = 0 } + dirs[1] = { { name = ".", ino = 1 }, { name = "..", ino = 1 } } +end - users[0] = { uid = 0, name = "root", gid = 0, home = "/", hash = "-" } - users[100] = { uid = 100, name = "captain", gid = 10, home = "/home/captain", hash = "-" } +function FS.addUser(uid, name, gid, home, hash) + users[uid] = { uid = uid, name = name, gid = gid, home = home, hash = hash or "-" } +end - local function mkIno(num, typ, mode, uid, gid, size) - inodes[num] = { ino = num, typ = typ, mode = mode, uid = uid, gid = gid, size = size or 0, mtime = 0 } +function FS.resolve(path) + return findInodeByPath(path) +end + +function FS.serialize() + return fsSerialize() +end + +function FS.deserialize(str) + return fsDeserialize(str) +end + +function FS.mkdir(path, mode, uid, gid) + local parentPath, name = path:match("^(.*)/([^/]+)$") + if not name then + parentPath, name = "/", path:match("^/?(.+)$") or path end - - local function mkDir(num, entries) - dirs[num] = entries + local parent = findInodeByPath(parentPath) + if not parent then return nil, "parent not found" end + if parent.typ ~= "d" then return nil, "not a directory" end + local ino + for i = 1, MAX_INODES do + if not inodes[i] then ino = i; break end end + if not ino then return nil, "no free inodes" end + inodes[ino] = { ino = ino, typ = "d", mode = mode or "755", uid = uid or 0, gid = gid or 0, size = 0, mtime = 0 } + dirs[ino] = { { name = ".", ino = ino }, { name = "..", ino = parent.ino } } + table.insert(dirs[parent.ino], { name = name, ino = ino }) + return ino +end - local function mkFile(num, content) - files[num] = content or "" - local sz = #(content or "") - if inodes[num] then inodes[num].size = sz end +function FS.mkfile(path, content, mode, uid, gid) + local parentPath, name = path:match("^(.*)/([^/]+)$") + if not name then + parentPath, name = "/", path:match("^/?(.+)$") or path end + local parent = findInodeByPath(parentPath) + if not parent then return nil, "parent not found" end + if parent.typ ~= "d" then return nil, "not a directory" end + local ino + for i = 1, MAX_INODES do + if not inodes[i] then ino = i; break end + end + if not ino then return nil, "no free inodes" end + content = content or "" + inodes[ino] = { ino = ino, typ = "f", mode = mode or "644", uid = uid or 0, gid = gid or 0, size = #content, mtime = 0 } + files[ino] = compressStr(content) + table.insert(dirs[parent.ino], { name = name, ino = ino }) + return ino +end - mkIno(1, "d", "755", 0, 0, 0) - mkDir(1, { { name = ".", ino = 1 }, { name = "..", ino = 1 }, { name = "home", ino = 2 }, { name = "etc", ino = 4 } }) +function FS.write(path, content) + local ino = findInodeByPath(path) + if not ino then return nil, "not found" end + if ino.typ ~= "f" then return nil, "not a file" end + content = content or "" + files[ino.ino] = compressStr(content) + inodes[ino.ino].size = #content + return true +end - mkIno(2, "d", "755", 0, 0, 0) - mkDir(2, { { name = ".", ino = 2 }, { name = "..", ino = 1 }, { name = "captain", ino = 5 } }) +function FS.read(path) + local ino = findInodeByPath(path) + if not ino then return nil, "not found" end + if ino.typ ~= "f" then return nil, "not a file" end + return decompressStr(files[ino.ino]) +end - mkIno(5, "d", "700", 100, 10, 0) - mkDir(5, { { name = ".", ino = 5 }, { name = "..", ino = 2 }, { name = "readme.txt", ino = 3 } }) +function FS.ls(path) + local ino = findInodeByPath(path or "/") + if not ino then return nil, "not found" end + if ino.typ ~= "d" then return nil, "not a directory" end + local result = {} + for _, e in ipairs(dirs[ino.ino]) do + result[#result + 1] = e.name + end + return result +end - mkIno(3, "f", "644", 100, 10, 0) - mkFile(3, "Welcome to AtlasOS v2.0!\n") - - mkIno(4, "d", "755", 0, 0, 0) - mkDir(4, { { name = ".", ino = 4 }, { name = "..", ino = 1 }, { name = "man", ino = 6 } }) - - mkIno(6, "d", "755", 0, 0, 0) - mkDir(6, { - { name = ".", ino = 6 }, { name = "..", ino = 4 }, - { name = "help", ino = 7 }, { name = "echo", ino = 8 }, - { name = "clear", ino = 9 }, { name = "color", ino = 10 }, - { name = "status", ino = 11 }, { name = "ls", ino = 12 }, - { name = "cat", ino = 13 }, { name = "cd", ino = 14 }, - { name = "stat", ino = 15 }, { name = "man", ino = 16 }, - }) - - mkIno(7, "f", "644", 0, 0, 0) - mkFile(7, [[NAME - help - display help information - -SYNOPSIS - help - -DESCRIPTION - Show a list of all available commands with their usage - and description. -]]) - - mkIno(8, "f", "644", 0, 0, 0) - mkFile(8, [[NAME - echo - display a line of text - -SYNOPSIS - echo - -DESCRIPTION - Write the given text to the terminal output. -]]) - - mkIno(9, "f", "644", 0, 0, 0) - mkFile(9, [[NAME - clear - clear the terminal screen - -SYNOPSIS - clear - -DESCRIPTION - Clear all text from the terminal display. -]]) - - mkIno(10, "f", "644", 0, 0, 0) - mkFile(10, [[NAME - color - set terminal text color - -SYNOPSIS - color - -DESCRIPTION - Change the text color for subsequent output. - Each value must be 0-255 (red, green, blue). -]]) - - mkIno(11, "f", "644", 0, 0, 0) - mkFile(11, [[NAME - status - show system status - -SYNOPSIS - status - -DESCRIPTION - Display system information including current user, - working directory, and memory usage. -]]) - - mkIno(12, "f", "644", 0, 0, 0) - mkFile(12, [[NAME - ls - list directory contents - -SYNOPSIS - ls [-la] [path] - -DESCRIPTION - List contents of a directory. If no path is given, - list the current directory. - -OPTIONS - -a Include hidden entries (. and ..) - -l Long format (detailed listing) -]]) - - mkIno(13, "f", "644", 0, 0, 0) - mkFile(13, [[NAME - cat - concatenate and display files - -SYNOPSIS - cat - -DESCRIPTION - Read a file and display its contents on the terminal. -]]) - - mkIno(14, "f", "644", 0, 0, 0) - mkFile(14, [[NAME - cd - change the working directory - -SYNOPSIS - cd [path] - -DESCRIPTION - Change the current working directory. If no path - is given, go to root (/). Supports both absolute - and relative paths. -]]) - - mkIno(15, "f", "644", 0, 0, 0) - mkFile(15, [[NAME - stat - show file metadata - -SYNOPSIS - stat - -DESCRIPTION - Display metadata for a file or directory, including - inode number, type, permissions, owner, group, size, - and modification time. -]]) - - mkIno(16, "f", "644", 0, 0, 0) - mkFile(16, [[NAME - man - display manual page - -SYNOPSIS - man - -DESCRIPTION - Display the manual page for a command. Manual pages - are stored in /etc/man/. - -EXAMPLE - man ls - man cat - -SEE ALSO - help -]]) - - local str = fsSerialize() - out[5] = str - out[6] = 1 +function FS.stat(path) + local ino = findInodeByPath(path) + if not ino then return nil, "not found" end + local result = {} + for k, v in pairs(ino) do + result[k] = v + end + return result end local fsLoaded = false @@ -393,7 +479,8 @@ function upd() fsLoaded = true else fsLoaded = true - defaultFS() + FS.init() + FS.addUser(0, "root", 0, "/", "-") writePending = true end end diff --git a/atlas_os/tools/example.txt b/atlas_os/tools/example.txt new file mode 100644 index 0000000..87f156f --- /dev/null +++ b/atlas_os/tools/example.txt @@ -0,0 +1,211 @@ +Это читайте, мужик молодец + +Добро пожаловать в официальный перевод полного руководства по Neurotrauma! + +Если в данный момент вы находитесь в экстренной медицинской ситуации и рядом нет медицинских работников, немедленно перейдите в раздел первой помощи. + +Если вы испытываете беспокойство или необычные симптомы, немедленно обратитесь к ближайшему медицинскому специалисту. + +Помните! Всегда носите шлем! + +Понимание того, как функционирует человеческий организм - или как в нем происходят сбои - может занять некоторое время. +Цель этого руководства - предоставить начинающим врачам важнейшую информацию, пока они не накопят достаточно опыта. + +Врачи всегда должны иметь при себе медицинский сканер - вы не узнаете, что именно вызывает все симптомы у вашего пациента, пока не просканируете его (или не будете обладать обширными знаниями)! + +Упаковываем аптечку первой помощи +Аптечка первой помощи для экспедиции +должна содержать следующее (более подходящие вещи находятся слева): + + Эластичный бинт или обычный + Шовный материал + По крайне мере 1 жгут + Пакет с кровью (предпочтительно O-), Раствор Рингера, физраствор или адреналин + Каликсанид + Антипарализант + +Рекомендуется также взять с собой в экспедицию следующее: + + Полностью укомплектованный хирургический набор -> более подробно в 13: Хирургические процедуры и вы + Эндоваскулярный баллон + Медицинский стент + Гипс + +Эти предметы могут спасти жизнь пациента при катастрофическом не перекрывающемся кровотечении из шеи или аорты, требующем немедленного хирургического вмешательства. + +Аптечка первой помощи при несчастных случаях на подлодке +должна содержать следующее (более подходящие вещи находятся слева): + + Эластичный бинт или обычный + Шовный материал + По крайне мере 1 жгут + Пакет с кровью (предпочтительно O-), Раствор Рингера, физраствор или адреналин + Дефибриллятор + Гипс + +Мод Neurotrauma: 1:Оказание первой помощи +Непосредственные опасности +отсортированы от наиболее до наименее серьезных + +Разрыв аорты +Оказание первой помощи +Лечение +Прогноз + + Опиоид + Скальпель + Эндоваскулярный баллон + Медицинский стент + Шовный материал + + Опиоид + Скальпель + Эндоваскулярный баллон + Медицинский стент + Шовный материал + +Мрачный + +Кровотечение из сонной артерии +Оказание первой помощи +Лечение +Прогноз +Операция +Операция +Мрачный + +В огне +Оказание первой помощи +Лечение +Прогноз +Огнетушитель, вода или любой водолазный костюм +См. ожог +Зависит от того, как долго пациент горел + +Артериальное кровотечение +Оказание первой помощи +Лечение +Прогноз +Жгут +Операция +Тревожный + +Остановка сердца +Оказание первой помощи +Лечение +Прогноз +СЛР или дефибриллятор +СЛР или дефибриллятор +Данная болезнь является признаком чего-то худшего + +Остановка дыхания +Оказание первой помощи +Лечение +Прогноз +СЛР +СЛР +Данная болезнь является признаком чего-то худшего + +Припадок +Оказание первой помощи +Лечение +Прогноз +Удаление из небезопасной среды +Лечение первопричин +Данная болезнь является признаком чего-то худшего + +Рвота кровью +Оказание первой помощи +Лечение +Прогноз +Внутривенные жидкости +Операция +Данная болезнь является признаком чего-то худшего + +Переломы +Оказание первой помощи +Лечение +Прогноз +Бинт + гипс +Остеосинтетическая операция +Выживите + +Ожоги +Оказание первой помощи +Лечение +Прогноз +Эластичный бинт или обычный +Эластичный бинт или обычный, антибиотическая мазь в тяжёлых случаях +Частый источник заражения + +Раны (укусы, огнестрельные раны, рваные раны) +Оказание первой помощи +Лечение +Прогноз +Шовный материал +Шовный материал +Потенциальный источник заражения + +Вывихи +Оказание первой помощи +Лечение +Прогноз +Эластичный бинт или обычный +Удары гаечным ключом (используйте в качестве лечения, как бинт) +(сначала нужно ввести опиаты) +Мучительная боль + +Травма от удара тупым предметом +Оказание первой помощи +Лечение +Прогноз +Эластичный бинт или обычный +Операция с полустерильными плоскогубцами +Не проходит без первой помощи или лечения + +После оказания себе первой помощи обратитесь к врачу, как только сможете +Мод Neurotrauma: 2:Симптомы и причины +В ПРОЦЕССЕ ДОРАБОТКИ!!! + +В приведенной выше таблице вы можете найти симптом, который у вас может быть или вам интересно узнать, и посетить соответствующую главу данного руководства. +Мод Neurotrauma: 3: Мозг +Состояния и симптомы заболеваний головного мозга +отсортированы от наиболее до наименее тяжелых + +Нейротравма +Первая помощь +Лечение +Прогноз +Вызвано +Вызывает +Отсутствует +Маннитол (требуется длительное время) +Главный антагонист. Вызвано низким притоком кислорода к мозгу. Непременная смерть при длительном кислородном голодании. +Гипоксемия, инсульт +Потеря сознания, остановка дыхания, смерть + +Инсульт(в оф. переводе мода "удар") +Первая помощь +Лечение +Прогноз +Вызвано +Вызывает +Отсутствует +Операция +Инсульт следует лечить как можно скорее, чтобы свести к минимуму риск смерти. +Гипертония +Нейротравма, кома, судороги, боль, головная боль + +Кома +Первая помощь +Лечение +Прогноз +Вызвано +Вызывает +Отсутствует +Авто пульс и много времени +Основные причины следует лечить как можно скорее, иначе пациент может впасть в стойкое вегетативное состояние. +Остановка сердца, инсульт, ацидоз +Остановка сердца, остановка дыхания, потеря сознания + +Рвота кровью \ No newline at end of file diff --git a/atlas_os/tools/generate_init_fs.lua b/atlas_os/tools/generate_init_fs.lua new file mode 100644 index 0000000..a721081 --- /dev/null +++ b/atlas_os/tools/generate_init_fs.lua @@ -0,0 +1,140 @@ +-- generate_init_fs.lua +-- Генерирует начальный образ SEG0 с man-страницами в /etc/man/ +-- Использует экспортированное FS API из MMC.lua +-- Запуск: lua tools/generate_init_fs.lua > tools/init.amem + +local base = arg and arg[0] and arg[0]:match("(.+)/") or "." +dofile(base .. "/../MMC.lua") + +FS.init() + +FS.addUser(0, "root", 0, "/", "-") +FS.addUser(100, "captain", 10, "/home/captain", "-") + +FS.mkdir("/home", "755", 0, 0) +FS.mkdir("/home/captain", "700", 100, 10) +FS.mkfile("/home/captain/readme.txt", "Welcome to AtlasOS v2.0!\n", "644", 100, 10) +FS.mkdir("/etc", "755", 0, 0) +FS.mkdir("/etc/man", "755", 0, 0) + +FS.mkfile("/etc/man/help", [[NAME + help - display help information + +SYNOPSIS + help + +DESCRIPTION + Show a list of all available commands with their usage + and description. +]], "644", 0, 0) + +FS.mkfile("/etc/man/echo", [[NAME + echo - display a line of text + +SYNOPSIS + echo + +DESCRIPTION + Write the given text to the terminal output. +]], "644", 0, 0) + +FS.mkfile("/etc/man/clear", [[NAME + clear - clear the terminal screen + +SYNOPSIS + clear + +DESCRIPTION + Clear all text from the terminal display. +]], "644", 0, 0) + +FS.mkfile("/etc/man/color", [[NAME + color - set terminal text color + +SYNOPSIS + color + +DESCRIPTION + Change the text color for subsequent output. + Each value must be 0-255 (red, green, blue). +]], "644", 0, 0) + +FS.mkfile("/etc/man/status", [[NAME + status - show system status + +SYNOPSIS + status + +DESCRIPTION + Display system information including current user, + working directory, and memory usage. +]], "644", 0, 0) + +FS.mkfile("/etc/man/ls", [[NAME + ls - list directory contents + +SYNOPSIS + ls [-la] [path] + +DESCRIPTION + List contents of a directory. If no path is given, + list the current directory. + +OPTIONS + -a Include hidden entries (. and ..) + -l Long format (detailed listing) +]], "644", 0, 0) + +FS.mkfile("/etc/man/cat", [[NAME + cat - concatenate and display files + +SYNOPSIS + cat + +DESCRIPTION + Read a file and display its contents on the terminal. +]], "644", 0, 0) + +FS.mkfile("/etc/man/cd", [[NAME + cd - change the working directory + +SYNOPSIS + cd [path] + +DESCRIPTION + Change the current working directory. If no path + is given, go to root (/). Supports both absolute + and relative paths. +]], "644", 0, 0) + +FS.mkfile("/etc/man/stat", [[NAME + stat - show file metadata + +SYNOPSIS + stat + +DESCRIPTION + Display metadata for a file or directory, including + inode number, type, permissions, owner, group, size, + and modification time. +]], "644", 0, 0) + +FS.mkfile("/etc/man/man", [[NAME + man - display manual page + +SYNOPSIS + man + +DESCRIPTION + Display the manual page for a command. Manual pages + are stored in /etc/man/. + +EXAMPLE + man ls + man cat + +SEE ALSO + help +]], "644", 0, 0) + +print(FS.serialize()) diff --git a/atlas_os/tools/make_init_memory.sh b/atlas_os/tools/make_init_memory.sh new file mode 100755 index 0000000..2d11c71 --- /dev/null +++ b/atlas_os/tools/make_init_memory.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# make_init_memory.sh +# Генерирует стартовый образ памяти SEG0 и сохраняет в init.amem + +lua generate_init_fs.lua > init.amem +echo "init.amem создан ($(wc -c < init.amem) байт)"