shellsim 0.1.15__tar.gz → 0.1.17__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shellsim-0.1.15 → shellsim-0.1.17}/Cargo.lock +1 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/Cargo.toml +1 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/PKG-INFO +1 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/python/native/Cargo.lock +2 -2
- {shellsim-0.1.15 → shellsim-0.1.17}/python/native/Cargo.toml +1 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/builtins.rs +453 -13
- shellsim-0.1.17/src/commands/find.rs +619 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/fs.rs +479 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/system.rs +314 -13
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/text.rs +1123 -28
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/unavailable.rs +0 -3
- {shellsim-0.1.15 → shellsim-0.1.17}/src/exec.rs +308 -26
- {shellsim-0.1.15 → shellsim-0.1.17}/src/interp.rs +28 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/compiler.rs +0 -2
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/heap.rs +6 -1
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/asyncio.py +100 -25
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/calls.rs +1 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/iteration.rs +43 -22
- {shellsim-0.1.15 → shellsim-0.1.17}/src/shell.rs +108 -11
- shellsim-0.1.15/src/commands/find.rs +0 -323
- {shellsim-0.1.15 → shellsim-0.1.17}/LICENSE +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/README.md +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/pyproject.toml +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/native/src/lib.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/__init__.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/__main__.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/_api.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/_cli.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/py.typed +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/python/shellsim/python.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/rust-toolchain.toml +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/bin/shellsim-python.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/clock.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/archives.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/awk/ast.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/awk/eval.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/awk/lexer.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/awk/parser.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/awk.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/dd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/echo.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/apply.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/commit.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/compare.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/config.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/conflict.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/diff.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/ignore.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/import.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/log.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/merge.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/mod.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/plumbing.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/rebase.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/refs.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/repo.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/stash.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/switch.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/git/worktree.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/hashing.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/makecmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/mod.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/net.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/options.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/patch.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/pkg.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/printf.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/proc.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/regex_compat.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/rgcmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/sed.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/sort.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/tarcmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/util.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/commands/zipcmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/descriptors.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/expand.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/harness.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/harness_manager.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/hashes.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/host_ingest.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/jqcmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/lib.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/main.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/mcp.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/net.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/netcmd.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/process.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/pseudo_fs.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/ast.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/bytecode.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/filesystem.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/http.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/lexer.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/mapping.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/mod.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/native.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/number.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/object_model.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/parser.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/process.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/protocol.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/slice.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/source.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/argparse.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/asyncio.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/base64.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/bisect.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/collections.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/core.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/dataclasses.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/enum.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/frozen.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/functools.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/hashlib.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/heapq.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/http.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/importlib.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/itertools.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/json.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/math.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/mod.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/numpy.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/os.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/pytest.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/re.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/abc.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/base64.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/cmath.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/codecs.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/collections.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/complex.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/copy.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/csv.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/datetime.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/glob.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/hashlib.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/http.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/http_client.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/importlib.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/io.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/json.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/logging.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/numpy_random.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/os.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/pathlib.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/pytest.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/random.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/shutil.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/statistics.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/struct.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/subprocess.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/tempfile.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/textwrap.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/urllib.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/urllib_error.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/urllib_request.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/uuid.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/zipfile.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/source/zlib.py +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/string.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/struct.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/subprocess.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/sys.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/time.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/typing.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/unittest.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/vfs.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/stdlib/zlib.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/string.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/token.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/dispatch.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/host.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/namespace.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/native_runtime.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/objects.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm/operations.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/python/vm.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/resources.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/sandbox.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/scenario.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/scheduler.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/telemetry.rs +0 -0
- {shellsim-0.1.15 → shellsim-0.1.17}/src/vfs.rs +0 -0
|
@@ -406,7 +406,7 @@ dependencies = [
|
|
|
406
406
|
|
|
407
407
|
[[package]]
|
|
408
408
|
name = "shellsim"
|
|
409
|
-
version = "0.1.
|
|
409
|
+
version = "0.1.17"
|
|
410
410
|
dependencies = [
|
|
411
411
|
"base64",
|
|
412
412
|
"crc32fast",
|
|
@@ -427,7 +427,7 @@ dependencies = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "shellsim-python-bindings"
|
|
430
|
-
version = "0.1.
|
|
430
|
+
version = "0.1.17"
|
|
431
431
|
dependencies = [
|
|
432
432
|
"pyo3",
|
|
433
433
|
"serde",
|
|
@@ -17,7 +17,7 @@ pub fn register(m: &mut HashMap<&'static str, CommandSpec>) {
|
|
|
17
17
|
reg(m, &["set"], Trust::Real, cmd_set);
|
|
18
18
|
reg(m, &["declare", "typeset"], Trust::Real, cmd_declare);
|
|
19
19
|
reg(m, &["local"], Trust::Real, cmd_local);
|
|
20
|
-
|
|
20
|
+
reg(m, &["readonly"], Trust::Real, cmd_readonly);
|
|
21
21
|
reg_resumable(m, &["source", "."], Trust::Real, cmd_source, start_source);
|
|
22
22
|
reg_resumable(m, &["eval"], Trust::Real, cmd_eval, start_eval);
|
|
23
23
|
reg(m, &["exit"], Trust::Real, cmd_exit);
|
|
@@ -37,14 +37,16 @@ pub fn register(m: &mut HashMap<&'static str, CommandSpec>) {
|
|
|
37
37
|
reg(m, &["bg"], Trust::Real, cmd_bg);
|
|
38
38
|
reg(m, &["trap"], Trust::Real, cmd_trap);
|
|
39
39
|
reg(m, &["flock"], Trust::Partial, cmd_flock);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
40
|
+
reg(m, &["disown"], Trust::Real, cmd_disown);
|
|
41
|
+
reg(m, &["umask"], Trust::Partial, cmd_umask);
|
|
42
|
+
reg(m, &["ulimit"], Trust::Partial, cmd_ulimit);
|
|
43
|
+
reg(m, &["hash"], Trust::Real, cmd_hash);
|
|
44
|
+
reg(m, &["shopt"], Trust::Partial, cmd_shopt);
|
|
45
|
+
reg(m, &["exec"], Trust::Partial, cmd_exec);
|
|
46
|
+
reg_unsupported(m, &["complete", "bind", "history"]);
|
|
46
47
|
reg(m, &["kill"], Trust::Real, cmd_kill);
|
|
47
|
-
|
|
48
|
+
reg(m, &["killall"], Trust::Partial, cmd_killall);
|
|
49
|
+
reg(m, &["pkill"], Trust::Partial, cmd_pkill);
|
|
48
50
|
reg(m, &["which"], Trust::Real, cmd_which);
|
|
49
51
|
reg(m, &["type"], Trust::Real, cmd_type);
|
|
50
52
|
reg_resumable(m, &["command"], Trust::Real, cmd_command, start_command);
|
|
@@ -58,6 +60,266 @@ pub fn register(m: &mut HashMap<&'static str, CommandSpec>) {
|
|
|
58
60
|
reg(m, &["dirs"], Trust::Real, cmd_dirs);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
fn cmd_readonly(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
64
|
+
if args.is_empty() || args == ["-p"] {
|
|
65
|
+
for name in &interp.readonly {
|
|
66
|
+
let value = interp.get_var(name).unwrap_or_default();
|
|
67
|
+
wln(io.out, &format!("declare -r {name}=\"{value}\""));
|
|
68
|
+
}
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
let mut status = 0;
|
|
72
|
+
for argument in args.iter().filter(|argument| argument.as_str() != "--") {
|
|
73
|
+
if argument.starts_with('-') {
|
|
74
|
+
ewln(io.err, &format!("readonly: unsupported option {argument}"));
|
|
75
|
+
status = 2;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
let name = declare_name_of(argument);
|
|
79
|
+
if !shell_identifier(name) {
|
|
80
|
+
ewln(io.err, &format!("readonly: {name}: not a valid identifier"));
|
|
81
|
+
status = 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if let Some((raw_key, raw_value)) = split_decl_assign(argument) {
|
|
85
|
+
if interp.readonly.contains(name) {
|
|
86
|
+
ewln(io.err, &format!("readonly: {name}: readonly variable"));
|
|
87
|
+
status = 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
crate::exec::apply_assignment(interp, &raw_key, &raw_value);
|
|
91
|
+
} else if interp.get_var(name).is_none() && !interp.arrays.contains_key(name) {
|
|
92
|
+
interp.set_var(name, "");
|
|
93
|
+
}
|
|
94
|
+
interp.readonly.insert(name.to_string());
|
|
95
|
+
}
|
|
96
|
+
status
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn cmd_umask(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
100
|
+
match args {
|
|
101
|
+
[] => {
|
|
102
|
+
wln(io.out, &format!("{:04o}", interp.umask));
|
|
103
|
+
0
|
|
104
|
+
}
|
|
105
|
+
[flag] if flag == "-S" => {
|
|
106
|
+
let allowed = 0o777 & !interp.umask;
|
|
107
|
+
let triplet = |shift| {
|
|
108
|
+
let bits = (allowed >> shift) & 7_u16;
|
|
109
|
+
format!(
|
|
110
|
+
"{}{}{}",
|
|
111
|
+
if bits & 4_u16 != 0_u16 { "r" } else { "" },
|
|
112
|
+
if bits & 2_u16 != 0_u16 { "w" } else { "" },
|
|
113
|
+
if bits & 1_u16 != 0_u16 { "x" } else { "" }
|
|
114
|
+
)
|
|
115
|
+
};
|
|
116
|
+
wln(
|
|
117
|
+
io.out,
|
|
118
|
+
&format!("u={},g={},o={}", triplet(6), triplet(3), triplet(0)),
|
|
119
|
+
);
|
|
120
|
+
0
|
|
121
|
+
}
|
|
122
|
+
[value] => match u16::from_str_radix(
|
|
123
|
+
match value.trim_start_matches('0') {
|
|
124
|
+
"" if !value.is_empty() => "0",
|
|
125
|
+
digits => digits,
|
|
126
|
+
},
|
|
127
|
+
8,
|
|
128
|
+
) {
|
|
129
|
+
Ok(mask) if mask <= 0o777 => {
|
|
130
|
+
interp.umask = mask;
|
|
131
|
+
0
|
|
132
|
+
}
|
|
133
|
+
_ => {
|
|
134
|
+
ewln(io.err, &format!("umask: {value}: invalid octal mask"));
|
|
135
|
+
1
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
_ => {
|
|
139
|
+
ewln(io.err, "umask: usage: umask [-S] [octal-mask]");
|
|
140
|
+
2
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
fn cmd_ulimit(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
146
|
+
let limits = interp.resources.limits();
|
|
147
|
+
let selected = args.first().map(String::as_str).unwrap_or("-f");
|
|
148
|
+
if args.len() > 1 || !matches!(selected, "-a" | "-f" | "-n" | "-t" | "-v") {
|
|
149
|
+
ewln(
|
|
150
|
+
io.err,
|
|
151
|
+
"ulimit: setting limits and this option are not supported",
|
|
152
|
+
);
|
|
153
|
+
return 2;
|
|
154
|
+
}
|
|
155
|
+
let blocks = |bytes: u64| {
|
|
156
|
+
if bytes == u64::MAX {
|
|
157
|
+
"unlimited".into()
|
|
158
|
+
} else {
|
|
159
|
+
(bytes / 1024).to_string()
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
match selected {
|
|
163
|
+
"-a" => {
|
|
164
|
+
wln(
|
|
165
|
+
io.out,
|
|
166
|
+
&format!(
|
|
167
|
+
"file size (blocks, -f) {}",
|
|
168
|
+
blocks(limits.disk)
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
wln(io.out, "open files (-n) 1024");
|
|
172
|
+
wln(
|
|
173
|
+
io.out,
|
|
174
|
+
&format!("cpu time (seconds, -t) {}", limits.cpu),
|
|
175
|
+
);
|
|
176
|
+
wln(
|
|
177
|
+
io.out,
|
|
178
|
+
&format!(
|
|
179
|
+
"virtual memory (kbytes, -v) {}",
|
|
180
|
+
blocks(limits.memory)
|
|
181
|
+
),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
"-f" => wln(io.out, &blocks(limits.disk)),
|
|
185
|
+
"-n" => wln(io.out, "1024"),
|
|
186
|
+
"-t" => wln(io.out, &limits.cpu.to_string()),
|
|
187
|
+
"-v" => wln(io.out, &blocks(limits.memory)),
|
|
188
|
+
_ => unreachable!(),
|
|
189
|
+
}
|
|
190
|
+
0
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
fn cmd_hash(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
194
|
+
if args == ["-r"] {
|
|
195
|
+
interp.command_hash.clear();
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
if args.first().map(String::as_str) == Some("-t") {
|
|
199
|
+
let mut status = 0;
|
|
200
|
+
for name in &args[1..] {
|
|
201
|
+
if let Some(path) = interp.command_hash.get(name) {
|
|
202
|
+
wln(io.out, path);
|
|
203
|
+
} else {
|
|
204
|
+
ewln(io.err, &format!("hash: {name}: not found"));
|
|
205
|
+
status = 1;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return status;
|
|
209
|
+
}
|
|
210
|
+
if args.is_empty() {
|
|
211
|
+
for (name, path) in &interp.command_hash {
|
|
212
|
+
wln(io.out, &format!("{path}\t{name}"));
|
|
213
|
+
}
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
216
|
+
let mut status = 0;
|
|
217
|
+
for name in args {
|
|
218
|
+
let path = if crate::commands::is_registered(name) {
|
|
219
|
+
Some(format!("/usr/bin/{name}"))
|
|
220
|
+
} else if let crate::commands::util::ExecutableLookup::Found(path) =
|
|
221
|
+
crate::commands::util::resolve_executable(interp, name)
|
|
222
|
+
{
|
|
223
|
+
Some(path)
|
|
224
|
+
} else {
|
|
225
|
+
None
|
|
226
|
+
};
|
|
227
|
+
if let Some(path) = path {
|
|
228
|
+
interp.command_hash.insert(name.clone(), path);
|
|
229
|
+
} else {
|
|
230
|
+
ewln(io.err, &format!("hash: {name}: not found"));
|
|
231
|
+
status = 1;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
status
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const COMPAT_SHOPTS: &[&str] = &["expand_aliases", "sourcepath"];
|
|
238
|
+
|
|
239
|
+
fn cmd_shopt(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
240
|
+
let (mode, names) = match args.first().map(String::as_str) {
|
|
241
|
+
Some("-s") => ('s', &args[1..]),
|
|
242
|
+
Some("-u") => ('u', &args[1..]),
|
|
243
|
+
Some("-q") => ('q', &args[1..]),
|
|
244
|
+
Some(option) if option.starts_with('-') => {
|
|
245
|
+
ewln(io.err, &format!("shopt: unsupported option {option}"));
|
|
246
|
+
return 2;
|
|
247
|
+
}
|
|
248
|
+
_ => ('p', args),
|
|
249
|
+
};
|
|
250
|
+
let selected = if names.is_empty() {
|
|
251
|
+
COMPAT_SHOPTS
|
|
252
|
+
.iter()
|
|
253
|
+
.map(|name| (*name).to_string())
|
|
254
|
+
.collect::<Vec<_>>()
|
|
255
|
+
} else {
|
|
256
|
+
names.to_vec()
|
|
257
|
+
};
|
|
258
|
+
let mut status = 0;
|
|
259
|
+
for name in selected {
|
|
260
|
+
if !COMPAT_SHOPTS.contains(&name.as_str()) {
|
|
261
|
+
ewln(io.err, &format!("shopt: {name}: invalid shell option name"));
|
|
262
|
+
status = 1;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
match mode {
|
|
266
|
+
's' => {
|
|
267
|
+
interp.shell_options.insert(name);
|
|
268
|
+
}
|
|
269
|
+
'u' => {
|
|
270
|
+
interp.shell_options.remove(&name);
|
|
271
|
+
}
|
|
272
|
+
'q' => status |= i32::from(!interp.shell_options.contains(&name)),
|
|
273
|
+
_ => wln(
|
|
274
|
+
io.out,
|
|
275
|
+
&format!(
|
|
276
|
+
"{}\t{}",
|
|
277
|
+
name,
|
|
278
|
+
if interp.shell_options.contains(&name) {
|
|
279
|
+
"on"
|
|
280
|
+
} else {
|
|
281
|
+
"off"
|
|
282
|
+
}
|
|
283
|
+
),
|
|
284
|
+
),
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
status
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
fn cmd_disown(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
291
|
+
if args == ["-a"] {
|
|
292
|
+
interp.jobs.clear();
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
let position = match job_position(interp, args, "disown") {
|
|
296
|
+
Ok(position) => position,
|
|
297
|
+
Err(error) => {
|
|
298
|
+
ewln(io.err, &format!("disown: {error}"));
|
|
299
|
+
return 1;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
interp.jobs.remove(position);
|
|
303
|
+
0
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
fn cmd_exec(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
307
|
+
if args.is_empty() {
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
310
|
+
let argv = if args.first().map(String::as_str) == Some("--") {
|
|
311
|
+
&args[1..]
|
|
312
|
+
} else {
|
|
313
|
+
args
|
|
314
|
+
};
|
|
315
|
+
if argv.is_empty() {
|
|
316
|
+
return 0;
|
|
317
|
+
}
|
|
318
|
+
let status = crate::commands::run(interp, argv, std::mem::take(&mut io.stdin), io.out, io.err);
|
|
319
|
+
interp.exiting = Some(status);
|
|
320
|
+
status
|
|
321
|
+
}
|
|
322
|
+
|
|
61
323
|
const MAX_TRAP_STATE_BYTES: u64 = 1024 * 1024;
|
|
62
324
|
|
|
63
325
|
/// Validate the common descriptor-lock form. A shellsim process has no ambient competing host
|
|
@@ -469,6 +731,155 @@ fn cmd_kill(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i3
|
|
|
469
731
|
status
|
|
470
732
|
}
|
|
471
733
|
|
|
734
|
+
fn cmd_pkill(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
735
|
+
let mut signal = crate::process::Signal::Terminate;
|
|
736
|
+
let mut full = false;
|
|
737
|
+
let mut exact = false;
|
|
738
|
+
let mut index = 0;
|
|
739
|
+
while let Some(argument) = args.get(index) {
|
|
740
|
+
match argument.as_str() {
|
|
741
|
+
"-f" => full = true,
|
|
742
|
+
"-x" => exact = true,
|
|
743
|
+
"-s" | "--signal" => {
|
|
744
|
+
index += 1;
|
|
745
|
+
let Some(value) = args.get(index) else {
|
|
746
|
+
ewln(io.err, "pkill: signal name required");
|
|
747
|
+
return 2;
|
|
748
|
+
};
|
|
749
|
+
let Ok(Some(parsed)) = parse_signal(value) else {
|
|
750
|
+
ewln(io.err, &format!("pkill: invalid signal: {value}"));
|
|
751
|
+
return 2;
|
|
752
|
+
};
|
|
753
|
+
signal = parsed;
|
|
754
|
+
}
|
|
755
|
+
value if value.starts_with('-') && value.len() > 1 => {
|
|
756
|
+
let Ok(Some(parsed)) = parse_signal(&value[1..]) else {
|
|
757
|
+
ewln(io.err, &format!("pkill: unsupported option {value}"));
|
|
758
|
+
return 2;
|
|
759
|
+
};
|
|
760
|
+
signal = parsed;
|
|
761
|
+
}
|
|
762
|
+
_ => break,
|
|
763
|
+
}
|
|
764
|
+
index += 1;
|
|
765
|
+
}
|
|
766
|
+
let Some(pattern) = args.get(index) else {
|
|
767
|
+
ewln(io.err, "pkill: pattern required");
|
|
768
|
+
return 2;
|
|
769
|
+
};
|
|
770
|
+
if index + 1 != args.len() {
|
|
771
|
+
ewln(io.err, "pkill: too many patterns");
|
|
772
|
+
return 2;
|
|
773
|
+
}
|
|
774
|
+
let regex = match regex::Regex::new(pattern) {
|
|
775
|
+
Ok(regex) => regex,
|
|
776
|
+
Err(error) => {
|
|
777
|
+
ewln(io.err, &format!("pkill: invalid pattern: {error}"));
|
|
778
|
+
return 2;
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
let current = interp.pid;
|
|
782
|
+
let targets = interp
|
|
783
|
+
.processes
|
|
784
|
+
.iter()
|
|
785
|
+
.filter(|record| {
|
|
786
|
+
record.pid != current
|
|
787
|
+
&& !matches!(record.status, crate::process::ProcessStatus::Exited(_))
|
|
788
|
+
})
|
|
789
|
+
.filter(|record| {
|
|
790
|
+
let candidate = if full {
|
|
791
|
+
record.command.as_str()
|
|
792
|
+
} else {
|
|
793
|
+
record
|
|
794
|
+
.command
|
|
795
|
+
.split_whitespace()
|
|
796
|
+
.next()
|
|
797
|
+
.unwrap_or("")
|
|
798
|
+
.rsplit('/')
|
|
799
|
+
.next()
|
|
800
|
+
.unwrap_or("")
|
|
801
|
+
};
|
|
802
|
+
if exact {
|
|
803
|
+
regex
|
|
804
|
+
.find(candidate)
|
|
805
|
+
.is_some_and(|found| found.as_str() == candidate)
|
|
806
|
+
} else {
|
|
807
|
+
regex.is_match(candidate)
|
|
808
|
+
}
|
|
809
|
+
})
|
|
810
|
+
.map(|record| record.pid)
|
|
811
|
+
.collect::<Vec<_>>();
|
|
812
|
+
for pid in &targets {
|
|
813
|
+
let _ = interp.send_signal(*pid, signal);
|
|
814
|
+
}
|
|
815
|
+
i32::from(targets.is_empty())
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
fn cmd_killall(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
819
|
+
let mut signal = crate::process::Signal::Terminate;
|
|
820
|
+
let mut names = Vec::new();
|
|
821
|
+
let mut index = 0;
|
|
822
|
+
while let Some(argument) = args.get(index) {
|
|
823
|
+
match argument.as_str() {
|
|
824
|
+
"-s" | "--signal" => {
|
|
825
|
+
index += 1;
|
|
826
|
+
let Some(value) = args.get(index) else {
|
|
827
|
+
ewln(io.err, "killall: signal name required");
|
|
828
|
+
return 2;
|
|
829
|
+
};
|
|
830
|
+
let Ok(Some(parsed)) = parse_signal(value) else {
|
|
831
|
+
ewln(io.err, &format!("killall: invalid signal: {value}"));
|
|
832
|
+
return 2;
|
|
833
|
+
};
|
|
834
|
+
signal = parsed;
|
|
835
|
+
}
|
|
836
|
+
value if value.starts_with('-') => {
|
|
837
|
+
let Ok(Some(parsed)) = parse_signal(&value[1..]) else {
|
|
838
|
+
ewln(io.err, &format!("killall: unsupported option {value}"));
|
|
839
|
+
return 2;
|
|
840
|
+
};
|
|
841
|
+
signal = parsed;
|
|
842
|
+
}
|
|
843
|
+
name => names.push(name.to_string()),
|
|
844
|
+
}
|
|
845
|
+
index += 1;
|
|
846
|
+
}
|
|
847
|
+
if names.is_empty() {
|
|
848
|
+
ewln(io.err, "killall: process name required");
|
|
849
|
+
return 2;
|
|
850
|
+
}
|
|
851
|
+
let current = interp.pid;
|
|
852
|
+
let targets = interp
|
|
853
|
+
.processes
|
|
854
|
+
.iter()
|
|
855
|
+
.filter(|record| {
|
|
856
|
+
let command = record
|
|
857
|
+
.command
|
|
858
|
+
.split_whitespace()
|
|
859
|
+
.next()
|
|
860
|
+
.unwrap_or("")
|
|
861
|
+
.rsplit('/')
|
|
862
|
+
.next()
|
|
863
|
+
.unwrap_or("");
|
|
864
|
+
record.pid != current
|
|
865
|
+
&& !matches!(record.status, crate::process::ProcessStatus::Exited(_))
|
|
866
|
+
&& names.iter().any(|name| name == command)
|
|
867
|
+
})
|
|
868
|
+
.map(|record| record.pid)
|
|
869
|
+
.collect::<Vec<_>>();
|
|
870
|
+
for pid in &targets {
|
|
871
|
+
let _ = interp.send_signal(*pid, signal);
|
|
872
|
+
}
|
|
873
|
+
if targets.is_empty() {
|
|
874
|
+
for name in names {
|
|
875
|
+
ewln(io.err, &format!("killall: {name}: no process found"));
|
|
876
|
+
}
|
|
877
|
+
1
|
|
878
|
+
} else {
|
|
879
|
+
0
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
472
883
|
fn parse_signal(value: &str) -> Result<Option<crate::process::Signal>, String> {
|
|
473
884
|
if value == "0" {
|
|
474
885
|
Ok(None)
|
|
@@ -859,19 +1270,26 @@ fn print_directory_stack(interp: &CommandContext<'_>, one_per_line: bool, io: &m
|
|
|
859
1270
|
}
|
|
860
1271
|
}
|
|
861
1272
|
|
|
862
|
-
fn cmd_export(interp: &mut CommandContext<'_>, args: &[String],
|
|
1273
|
+
fn cmd_export(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
1274
|
+
let mut status = 0;
|
|
863
1275
|
for a in args {
|
|
864
1276
|
if let Some((k, v)) = a.split_once('=') {
|
|
1277
|
+
if interp.readonly.contains(k) {
|
|
1278
|
+
ewln(io.err, &format!("export: {k}: readonly variable"));
|
|
1279
|
+
status = 1;
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
865
1282
|
interp.set_var(k, v);
|
|
866
1283
|
interp.export(k);
|
|
867
1284
|
} else {
|
|
868
1285
|
interp.export(a);
|
|
869
1286
|
}
|
|
870
1287
|
}
|
|
871
|
-
|
|
1288
|
+
status
|
|
872
1289
|
}
|
|
873
1290
|
|
|
874
|
-
fn cmd_unset(interp: &mut CommandContext<'_>, args: &[String],
|
|
1291
|
+
fn cmd_unset(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
1292
|
+
let mut status = 0;
|
|
875
1293
|
for a in args {
|
|
876
1294
|
if a == "-v" || a == "-f" {
|
|
877
1295
|
continue;
|
|
@@ -880,18 +1298,28 @@ fn cmd_unset(interp: &mut CommandContext<'_>, args: &[String], _io: &mut Io) ->
|
|
|
880
1298
|
if let Some(br) = a.find('[') {
|
|
881
1299
|
if a.ends_with(']') {
|
|
882
1300
|
let name = &a[..br];
|
|
1301
|
+
if interp.readonly.contains(name) {
|
|
1302
|
+
ewln(io.err, &format!("unset: {name}: readonly variable"));
|
|
1303
|
+
status = 1;
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
883
1306
|
let key = &a[br + 1..a.len() - 1];
|
|
884
1307
|
let key = key.trim_matches('"').trim_matches('\'');
|
|
885
1308
|
interp.array_unset_elem(name, key);
|
|
886
1309
|
continue;
|
|
887
1310
|
}
|
|
888
1311
|
}
|
|
1312
|
+
if interp.readonly.contains(a) {
|
|
1313
|
+
ewln(io.err, &format!("unset: {a}: readonly variable"));
|
|
1314
|
+
status = 1;
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
889
1317
|
interp.vars.remove(a);
|
|
890
1318
|
interp.arrays.remove(a);
|
|
891
1319
|
interp.exported.remove(a);
|
|
892
1320
|
interp.funcs.remove(a);
|
|
893
1321
|
}
|
|
894
|
-
|
|
1322
|
+
status
|
|
895
1323
|
}
|
|
896
1324
|
|
|
897
1325
|
fn cmd_set(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
@@ -979,6 +1407,7 @@ fn cmd_declare(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) ->
|
|
|
979
1407
|
let mut assoc = false;
|
|
980
1408
|
let mut indexed = false;
|
|
981
1409
|
let mut print = false;
|
|
1410
|
+
let mut status = 0;
|
|
982
1411
|
for a in args {
|
|
983
1412
|
if a == "--" {
|
|
984
1413
|
continue;
|
|
@@ -991,6 +1420,11 @@ fn cmd_declare(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) ->
|
|
|
991
1420
|
}
|
|
992
1421
|
// operand: NAME, NAME=value, NAME=( … ), NAME[sub]=value
|
|
993
1422
|
let name = declare_name_of(a);
|
|
1423
|
+
if interp.readonly.contains(name) && split_decl_assign(a).is_some() {
|
|
1424
|
+
ewln(io.err, &format!("declare: {name}: readonly variable"));
|
|
1425
|
+
status = 1;
|
|
1426
|
+
continue;
|
|
1427
|
+
}
|
|
994
1428
|
// Establish the array kind first so a following literal lands in the right store.
|
|
995
1429
|
if assoc {
|
|
996
1430
|
interp.declare_assoc(name);
|
|
@@ -1012,7 +1446,7 @@ fn cmd_declare(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) ->
|
|
|
1012
1446
|
}
|
|
1013
1447
|
}
|
|
1014
1448
|
}
|
|
1015
|
-
|
|
1449
|
+
status
|
|
1016
1450
|
}
|
|
1017
1451
|
|
|
1018
1452
|
fn cmd_local(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
@@ -1845,14 +2279,17 @@ fn is_shell_builtin_name(name: &str) -> bool {
|
|
|
1845
2279
|
| "command"
|
|
1846
2280
|
| "continue"
|
|
1847
2281
|
| "declare"
|
|
2282
|
+
| "disown"
|
|
1848
2283
|
| "dirs"
|
|
1849
2284
|
| "echo"
|
|
1850
2285
|
| "eval"
|
|
2286
|
+
| "exec"
|
|
1851
2287
|
| "exit"
|
|
1852
2288
|
| "export"
|
|
1853
2289
|
| "false"
|
|
1854
2290
|
| "fg"
|
|
1855
2291
|
| "getopts"
|
|
2292
|
+
| "hash"
|
|
1856
2293
|
| "jobs"
|
|
1857
2294
|
| "kill"
|
|
1858
2295
|
| "let"
|
|
@@ -1868,12 +2305,15 @@ fn is_shell_builtin_name(name: &str) -> bool {
|
|
|
1868
2305
|
| "return"
|
|
1869
2306
|
| "set"
|
|
1870
2307
|
| "shift"
|
|
2308
|
+
| "shopt"
|
|
1871
2309
|
| "source"
|
|
1872
2310
|
| "test"
|
|
1873
2311
|
| "trap"
|
|
1874
2312
|
| "true"
|
|
1875
2313
|
| "type"
|
|
1876
2314
|
| "typeset"
|
|
2315
|
+
| "ulimit"
|
|
2316
|
+
| "umask"
|
|
1877
2317
|
| "unalias"
|
|
1878
2318
|
| "unset"
|
|
1879
2319
|
| "wait"
|