@sjawhar/pi-legion-envoy 5.17.2 → 5.17.3
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.
- package/dist/legion.js +234 -56
- package/package.json +1 -1
package/dist/legion.js
CHANGED
|
@@ -33473,7 +33473,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
33473
33473
|
// package.json
|
|
33474
33474
|
var package_default = {
|
|
33475
33475
|
name: "@sjawhar/pi-legion-envoy",
|
|
33476
|
-
version: "5.17.
|
|
33476
|
+
version: "5.17.3",
|
|
33477
33477
|
type: "module",
|
|
33478
33478
|
omp: {
|
|
33479
33479
|
extensions: [
|
|
@@ -41507,6 +41507,51 @@ var FILE_COMMANDS = new Set([
|
|
|
41507
41507
|
"chgrp"
|
|
41508
41508
|
]);
|
|
41509
41509
|
var SIGNAL_COMMANDS = new Set(["kill", "pkill", "killall", "killall5"]);
|
|
41510
|
+
var FIND_VALUED_PREDICATES = new Set([
|
|
41511
|
+
"-amin",
|
|
41512
|
+
"-anewer",
|
|
41513
|
+
"-atime",
|
|
41514
|
+
"-cmin",
|
|
41515
|
+
"-cnewer",
|
|
41516
|
+
"-ctime",
|
|
41517
|
+
"-fls",
|
|
41518
|
+
"-fprint",
|
|
41519
|
+
"-fprint0",
|
|
41520
|
+
"-fprintf",
|
|
41521
|
+
"-fstype",
|
|
41522
|
+
"-gid",
|
|
41523
|
+
"-group",
|
|
41524
|
+
"-ilname",
|
|
41525
|
+
"-iname",
|
|
41526
|
+
"-inum",
|
|
41527
|
+
"-ipath",
|
|
41528
|
+
"-iregex",
|
|
41529
|
+
"-iwholename",
|
|
41530
|
+
"-links",
|
|
41531
|
+
"-lname",
|
|
41532
|
+
"-maxdepth",
|
|
41533
|
+
"-mindepth",
|
|
41534
|
+
"-mmin",
|
|
41535
|
+
"-mtime",
|
|
41536
|
+
"-name",
|
|
41537
|
+
"-newer",
|
|
41538
|
+
"-newerat",
|
|
41539
|
+
"-newerct",
|
|
41540
|
+
"-newermt",
|
|
41541
|
+
"-path",
|
|
41542
|
+
"-perm",
|
|
41543
|
+
"-printf",
|
|
41544
|
+
"-regex",
|
|
41545
|
+
"-regextype",
|
|
41546
|
+
"-samefile",
|
|
41547
|
+
"-size",
|
|
41548
|
+
"-type",
|
|
41549
|
+
"-uid",
|
|
41550
|
+
"-used",
|
|
41551
|
+
"-user",
|
|
41552
|
+
"-wholename",
|
|
41553
|
+
"-xtype"
|
|
41554
|
+
]);
|
|
41510
41555
|
var FUNCTION_OUTPUT_SILENT = {
|
|
41511
41556
|
":": true,
|
|
41512
41557
|
break: true,
|
|
@@ -42166,6 +42211,43 @@ function literalText(exp) {
|
|
|
42166
42211
|
return;
|
|
42167
42212
|
return exp.map((piece) => piece.text).join("");
|
|
42168
42213
|
}
|
|
42214
|
+
function readableWord(arg) {
|
|
42215
|
+
const whole = literalText(arg.exp);
|
|
42216
|
+
if (whole !== undefined)
|
|
42217
|
+
return { text: whole, whole: true };
|
|
42218
|
+
let text = "";
|
|
42219
|
+
for (const piece of arg.exp) {
|
|
42220
|
+
if (piece.kind !== "literal")
|
|
42221
|
+
break;
|
|
42222
|
+
text += piece.text;
|
|
42223
|
+
}
|
|
42224
|
+
return { text, whole: false };
|
|
42225
|
+
}
|
|
42226
|
+
function mayBeOption(arg, matches) {
|
|
42227
|
+
const { text, whole } = readableWord(arg);
|
|
42228
|
+
if (whole)
|
|
42229
|
+
return matches(text);
|
|
42230
|
+
return text === "" || /^--?[a-zA-Z-]*$/.test(text);
|
|
42231
|
+
}
|
|
42232
|
+
function valueInWord(arg, count) {
|
|
42233
|
+
const pieces = [];
|
|
42234
|
+
let dropped = 0;
|
|
42235
|
+
for (const piece of arg.exp) {
|
|
42236
|
+
if (dropped >= count) {
|
|
42237
|
+
pieces.push(piece);
|
|
42238
|
+
continue;
|
|
42239
|
+
}
|
|
42240
|
+
if (piece.kind !== "literal")
|
|
42241
|
+
return;
|
|
42242
|
+
if (piece.text.length + dropped <= count) {
|
|
42243
|
+
dropped += piece.text.length;
|
|
42244
|
+
continue;
|
|
42245
|
+
}
|
|
42246
|
+
pieces.push({ ...piece, text: piece.text.slice(count - dropped) });
|
|
42247
|
+
dropped = count;
|
|
42248
|
+
}
|
|
42249
|
+
return dropped < count || pieces.length === 0 ? undefined : pieces;
|
|
42250
|
+
}
|
|
42169
42251
|
function visitParts(parts, st, ctx) {
|
|
42170
42252
|
for (const part of parts ?? []) {
|
|
42171
42253
|
switch (part.type) {
|
|
@@ -43087,6 +43169,7 @@ function operands(list, valued, longValued = []) {
|
|
|
43087
43169
|
return { options, operands: found };
|
|
43088
43170
|
}
|
|
43089
43171
|
function unwrap2(argv, st, ctx, site) {
|
|
43172
|
+
const alts = [];
|
|
43090
43173
|
let list = argv;
|
|
43091
43174
|
let state = st;
|
|
43092
43175
|
for (let guard = 0;guard < 16; guard += 1) {
|
|
@@ -43095,13 +43178,19 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43095
43178
|
break;
|
|
43096
43179
|
const base = path4.basename(name);
|
|
43097
43180
|
const rest = list.slice(1);
|
|
43098
|
-
const skip = (valued, longValued = []) => {
|
|
43181
|
+
const skip = (valued, longValued = [], positional = false) => {
|
|
43099
43182
|
let i = 0;
|
|
43100
43183
|
for (;i < rest.length; i += 1) {
|
|
43101
|
-
const
|
|
43184
|
+
const arg = rest[i];
|
|
43185
|
+
const text = literalText(arg.exp);
|
|
43102
43186
|
if (text === "--")
|
|
43103
43187
|
return rest.slice(i + 1);
|
|
43104
|
-
if (text === undefined
|
|
43188
|
+
if (text === undefined) {
|
|
43189
|
+
if (positional || !mayBeOption(arg, (option) => option.startsWith("-")))
|
|
43190
|
+
break;
|
|
43191
|
+
continue;
|
|
43192
|
+
}
|
|
43193
|
+
if (!text.startsWith("-") || text === "-")
|
|
43105
43194
|
break;
|
|
43106
43195
|
if (text.startsWith("--")) {
|
|
43107
43196
|
if (!text.includes("=") && longValued.includes(text))
|
|
@@ -43115,8 +43204,10 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43115
43204
|
}
|
|
43116
43205
|
return rest.slice(i);
|
|
43117
43206
|
};
|
|
43118
|
-
if ((base === "busybox" || base === "toybox") && rest[0] !== undefined)
|
|
43207
|
+
if ((base === "busybox" || base === "toybox") && rest[0] !== undefined && literalText(rest[0].exp) !== undefined) {
|
|
43119
43208
|
list = rest;
|
|
43209
|
+
continue;
|
|
43210
|
+
}
|
|
43120
43211
|
if (base === "sudo" || base === "doas")
|
|
43121
43212
|
list = skip("ughpCDrtUT", ["--user", "--group"]);
|
|
43122
43213
|
else if (base === "nice")
|
|
@@ -43128,15 +43219,23 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43128
43219
|
else if (base === "command") {
|
|
43129
43220
|
const flags = rest.map((arg) => literalText(arg.exp));
|
|
43130
43221
|
if (flags[0] === "-v" || flags[0] === "-V")
|
|
43131
|
-
return { argv: [], st: state };
|
|
43222
|
+
return { argv: [], st: state, alts };
|
|
43132
43223
|
list = skip("");
|
|
43133
43224
|
} else if (base === "stdbuf")
|
|
43134
43225
|
list = skip("ioe", ["--input", "--output", "--error"]);
|
|
43135
43226
|
else if (base === "ionice")
|
|
43136
43227
|
list = skip("cnt", ["--class", "--classdata"]);
|
|
43137
43228
|
else if (base === "timeout") {
|
|
43138
|
-
const
|
|
43139
|
-
list =
|
|
43229
|
+
const stopped = skip("sk", ["--signal", "--kill-after"], true);
|
|
43230
|
+
list = stopped.slice(1);
|
|
43231
|
+
for (let at = rest.length - stopped.length;at < rest.length; at += 1) {
|
|
43232
|
+
if (literalText(rest[at]?.exp) !== undefined)
|
|
43233
|
+
break;
|
|
43234
|
+
alts.push(rest.slice(at + 1));
|
|
43235
|
+
}
|
|
43236
|
+
const read = skip("sk", ["--signal", "--kill-after"]);
|
|
43237
|
+
if (read.length !== stopped.length)
|
|
43238
|
+
alts.push(read.slice(1));
|
|
43140
43239
|
} else if (base === "env") {
|
|
43141
43240
|
let i = 0;
|
|
43142
43241
|
const overlay = new Map;
|
|
@@ -43176,7 +43275,7 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43176
43275
|
overlay.set(arg.exp[0].text.slice(0, arg.exp[0].text.indexOf("=")), [
|
|
43177
43276
|
unknown2("an `env` assignment")
|
|
43178
43277
|
]);
|
|
43179
|
-
} else
|
|
43278
|
+
} else if (text === undefined && mayBeOption(arg, (option) => option.startsWith("-"))) {} else
|
|
43180
43279
|
break;
|
|
43181
43280
|
}
|
|
43182
43281
|
if (i !== -1)
|
|
@@ -43193,7 +43292,7 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
43193
43292
|
} else
|
|
43194
43293
|
break;
|
|
43195
43294
|
}
|
|
43196
|
-
return { argv: list, st: state };
|
|
43295
|
+
return { argv: list, st: state, alts };
|
|
43197
43296
|
}
|
|
43198
43297
|
function runFunction(name, definition, args2, outer, ctx) {
|
|
43199
43298
|
if (outer.runningFunctions.has(name))
|
|
@@ -43278,6 +43377,9 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43278
43377
|
const unwrapped = unwrap2(invocation.args, outer, ctx, invocation.site);
|
|
43279
43378
|
const argv = unwrapped.argv;
|
|
43280
43379
|
const st = unwrapped.st;
|
|
43380
|
+
for (const other of unwrapped.alts) {
|
|
43381
|
+
dispatch({ ...invocation, args: other }, clone2(outer), ctx);
|
|
43382
|
+
}
|
|
43281
43383
|
const name = literalText(argv[0]?.exp);
|
|
43282
43384
|
if (name === undefined)
|
|
43283
43385
|
return;
|
|
@@ -43425,15 +43527,21 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43425
43527
|
const leading = head[0];
|
|
43426
43528
|
const spaced = literalText(head) === "-v";
|
|
43427
43529
|
const joined = !spaced && leading?.kind === "literal" && leading.text.startsWith("-v") && (leading.text.length > 2 || head.length > 1);
|
|
43428
|
-
|
|
43429
|
-
|
|
43530
|
+
const first = rest[0];
|
|
43531
|
+
const mayBeV = !spaced && !joined && first !== undefined && rest[1] !== undefined && mayBeOption(first, (text) => text.startsWith("-v"));
|
|
43532
|
+
if (spaced || joined || mayBeV) {
|
|
43533
|
+
const variable = spaced || mayBeV ? literalText(rest[1]?.exp) : literalText([
|
|
43430
43534
|
{ ...leading, text: leading?.text.slice(2) ?? "" },
|
|
43431
43535
|
...head.slice(1)
|
|
43432
43536
|
]);
|
|
43433
|
-
const printed = rest.slice(spaced ? 2 : 1);
|
|
43537
|
+
const printed = rest.slice(spaced || mayBeV ? 2 : 1);
|
|
43434
43538
|
const [format, value, ...others] = printed;
|
|
43435
43539
|
let assigned;
|
|
43436
|
-
if (
|
|
43540
|
+
if (mayBeV) {
|
|
43541
|
+
assigned = [
|
|
43542
|
+
unknown2(`\`$${variable ?? "?"}\` (printf with an option word the guard cannot read, which may be \`-v\`)`)
|
|
43543
|
+
];
|
|
43544
|
+
} else if (literalText(format?.exp) === "%s" && value !== undefined && others.length === 0) {
|
|
43437
43545
|
assigned = value.exp;
|
|
43438
43546
|
} else {
|
|
43439
43547
|
const text = printfText(printed, MAX_VALUE_LENGTH);
|
|
@@ -43564,22 +43672,29 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43564
43672
|
case "tar":
|
|
43565
43673
|
case "unzip": {
|
|
43566
43674
|
const extracting = base === "unzip" || rest.some((arg, index) => {
|
|
43567
|
-
const text =
|
|
43568
|
-
|
|
43675
|
+
const { text, whole } = readableWord(arg);
|
|
43676
|
+
if (!whole && index === 0 && /^[A-Za-z]*$/.test(text))
|
|
43677
|
+
return true;
|
|
43678
|
+
return mayBeOption(arg, (mode) => mode === "--extract" || mode === "--get" || mode.startsWith("-") && !mode.startsWith("--") && mode.includes("x") || index === 0 && /^[A-Za-z]*x[A-Za-z]*$/.test(mode));
|
|
43569
43679
|
});
|
|
43570
43680
|
if (!extracting)
|
|
43571
43681
|
return;
|
|
43572
43682
|
const targetDirectories = [];
|
|
43573
43683
|
const short = base === "tar" ? "-C" : "-d";
|
|
43574
43684
|
const long = base === "tar" ? "--directory" : "--destination";
|
|
43685
|
+
const letter = short.slice(1);
|
|
43575
43686
|
for (const [index, arg] of rest.entries()) {
|
|
43576
|
-
const text =
|
|
43577
|
-
|
|
43687
|
+
const { text, whole } = readableWord(arg);
|
|
43688
|
+
const clusterAt = text.startsWith("-") && !text.startsWith("--") ? text.indexOf(letter, 1) : -1;
|
|
43689
|
+
const carried = text.startsWith(`${long}=`) ? valueInWord(arg, long.length + 1) : clusterAt !== -1 && (!whole || text.length > clusterAt + 1) ? valueInWord(arg, clusterAt + 1) : undefined;
|
|
43690
|
+
if (carried !== undefined) {
|
|
43691
|
+
targetDirectories.push({ text: arg.text, exp: carried });
|
|
43692
|
+
continue;
|
|
43693
|
+
}
|
|
43694
|
+
if (clusterAt !== -1 || mayBeOption(arg, (option) => option === short || option === long)) {
|
|
43578
43695
|
const target = rest[index + 1];
|
|
43579
43696
|
if (target !== undefined)
|
|
43580
43697
|
targetDirectories.push(target);
|
|
43581
|
-
} else if (text?.startsWith(`${long}=`)) {
|
|
43582
|
-
targetDirectories.push({ text: arg.text, exp: [literal2(text.slice(long.length + 1))] });
|
|
43583
43698
|
}
|
|
43584
43699
|
}
|
|
43585
43700
|
checkTargets(base, "extract and overwrite in", targetDirectories, true, st, ctx, site);
|
|
@@ -43627,41 +43742,73 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43627
43742
|
case "killall":
|
|
43628
43743
|
case "killall5":
|
|
43629
43744
|
throw new Refusal(site.snippet, site.line, `${base} selects processes by name or pattern, which reaches other agents' processes on a ` + "shared machine; a pane signals only processes it started. Stop a process you started " + 'with the hub tool (`op: "stop"`), or `kill` the pid of a child you started from this pane');
|
|
43630
|
-
case "fuser":
|
|
43631
|
-
|
|
43745
|
+
case "fuser": {
|
|
43746
|
+
const kills = rest.some((arg) => mayBeOption(arg, (text) => /^-[a-zA-Z]*k/.test(text) || text === "--kill"));
|
|
43747
|
+
const readable2 = rest.every((arg) => literalText(arg.exp) !== undefined);
|
|
43748
|
+
const mayBeSeveral = rest.some((arg) => arg.fields === "unknown");
|
|
43749
|
+
if (kills && (readable2 || mayBeSeveral || rest.length > 1)) {
|
|
43632
43750
|
throw new Refusal(site.snippet, site.line, "`fuser -k` kills every process using a file, other agents' included; a pane signals only " + "processes it started");
|
|
43633
43751
|
}
|
|
43634
43752
|
return;
|
|
43753
|
+
}
|
|
43635
43754
|
case "tmux": {
|
|
43636
43755
|
let socket;
|
|
43637
43756
|
let socketIsPath = false;
|
|
43638
|
-
|
|
43639
|
-
|
|
43640
|
-
|
|
43641
|
-
|
|
43642
|
-
|
|
43643
|
-
|
|
43644
|
-
|
|
43645
|
-
|
|
43646
|
-
|
|
43757
|
+
let current = { words: [], speculative: false };
|
|
43758
|
+
const segments = [current];
|
|
43759
|
+
for (const arg of rest) {
|
|
43760
|
+
const word = literalText(arg.exp);
|
|
43761
|
+
const trailing = word !== ";" && word !== undefined && word.endsWith(";");
|
|
43762
|
+
if (trailing)
|
|
43763
|
+
current.words.push({ text: arg.text, exp: [literal2(word.slice(0, -1))] });
|
|
43764
|
+
else if (word !== ";")
|
|
43765
|
+
current.words.push(arg);
|
|
43766
|
+
if (word === ";" || trailing) {
|
|
43767
|
+
current = { words: [], speculative: false };
|
|
43768
|
+
segments.push(current);
|
|
43769
|
+
} else if (word === undefined || arg.fields === "unknown") {
|
|
43770
|
+
current = { words: [], speculative: true };
|
|
43771
|
+
segments.push(current);
|
|
43647
43772
|
}
|
|
43648
43773
|
}
|
|
43649
43774
|
const killCommands = ["kill-server", "kill-session", "kill-window", "kill-pane"];
|
|
43650
43775
|
const respawnCommands = ["respawn-pane", "respawn-window"];
|
|
43651
|
-
const
|
|
43652
|
-
|
|
43653
|
-
if (text === undefined)
|
|
43776
|
+
const names = (word, commands) => {
|
|
43777
|
+
if (word === undefined)
|
|
43654
43778
|
return false;
|
|
43779
|
+
const { text, whole } = readableWord(word);
|
|
43655
43780
|
const compact = text.replace("-", "");
|
|
43656
|
-
|
|
43657
|
-
|
|
43658
|
-
|
|
43659
|
-
|
|
43660
|
-
|
|
43661
|
-
|
|
43662
|
-
|
|
43663
|
-
|
|
43664
|
-
|
|
43781
|
+
const reachable = commands.filter((command) => command.replace("-", "").startsWith(compact));
|
|
43782
|
+
return whole ? reachable.length === 1 : reachable.length > 0;
|
|
43783
|
+
};
|
|
43784
|
+
let killing;
|
|
43785
|
+
for (const segment of segments) {
|
|
43786
|
+
const words = segment.words;
|
|
43787
|
+
let subcommand;
|
|
43788
|
+
for (let i = 0;i < words.length; i += 1) {
|
|
43789
|
+
const arg = words[i];
|
|
43790
|
+
const { text, whole } = readableWord(arg);
|
|
43791
|
+
const attached = (option) => text.startsWith(option) && (!whole || text.length > option.length) ? valueInWord(arg, option.length) : undefined;
|
|
43792
|
+
const carried = attached("-L") ?? attached("-S") ?? attached("--socket=");
|
|
43793
|
+
if (carried !== undefined) {
|
|
43794
|
+
socket = { text: arg.text, exp: carried };
|
|
43795
|
+
socketIsPath = !text.startsWith("-L");
|
|
43796
|
+
} else if (text === "-L" || text === "-S" || text === "--socket") {
|
|
43797
|
+
socket = words[i + 1];
|
|
43798
|
+
socketIsPath = text !== "-L";
|
|
43799
|
+
i += 1;
|
|
43800
|
+
} else if (text === "-f" || text === "-T") {
|
|
43801
|
+
i += 1;
|
|
43802
|
+
} else if (subcommand === undefined && !text.startsWith("-")) {
|
|
43803
|
+
subcommand = arg;
|
|
43804
|
+
}
|
|
43805
|
+
}
|
|
43806
|
+
if (segment.speculative && (subcommand === undefined || readableWord(subcommand).text === ""))
|
|
43807
|
+
continue;
|
|
43808
|
+
const respawning = names(subcommand, respawnCommands) && words.some((arg) => mayBeOption(arg, (text) => text === "-k"));
|
|
43809
|
+
if (names(subcommand, killCommands) || respawning)
|
|
43810
|
+
killing ??= subcommand;
|
|
43811
|
+
}
|
|
43665
43812
|
if (killing === undefined)
|
|
43666
43813
|
return;
|
|
43667
43814
|
let resolvedSocket;
|
|
@@ -43685,13 +43832,19 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43685
43832
|
if (resolvedSocket !== undefined && judgePath(resolvedSocket, st, ctx, { follow: true, overwrite: false }).ok) {
|
|
43686
43833
|
return;
|
|
43687
43834
|
}
|
|
43688
|
-
throw new Refusal(site.snippet, site.line, `\`tmux ${
|
|
43835
|
+
throw new Refusal(site.snippet, site.line, `\`tmux ${killing.text}\` needs a socket path inside this pane's roots; the ` + "resolved socket can end panes and processes this pane did not start");
|
|
43836
|
+
}
|
|
43837
|
+
case "busybox":
|
|
43838
|
+
case "toybox": {
|
|
43839
|
+
if (rest.length === 0)
|
|
43840
|
+
return;
|
|
43841
|
+
throw new Refusal(site.snippet, site.line, `the guard cannot read the applet \`${rest[0].text}\` ${base} would run, and the ` + "applets it carries include `rm`, `sh` and `killall`, which reach paths and processes " + `this pane did not start; name the applet (\`${base} rm \u2026\`) so it can be checked`);
|
|
43689
43842
|
}
|
|
43690
43843
|
default:
|
|
43691
43844
|
break;
|
|
43692
43845
|
}
|
|
43693
|
-
if (SHELLS.has(base)
|
|
43694
|
-
runShell(
|
|
43846
|
+
if (SHELLS.has(base)) {
|
|
43847
|
+
runShell(rest, invocation, st, ctx);
|
|
43695
43848
|
return;
|
|
43696
43849
|
}
|
|
43697
43850
|
const interpreter = interpreterLanguage(base);
|
|
@@ -43721,8 +43874,9 @@ function changeDirectory(target, st, ctx) {
|
|
|
43721
43874
|
function declaration(builtin, list, st, ctx, site) {
|
|
43722
43875
|
const options = list.map((arg) => literalText(arg.exp) ?? "").filter((text) => /^[-+][a-zA-Z]+$/.test(text));
|
|
43723
43876
|
const option = (letter) => options.some((text) => text.startsWith("-") && text.includes(letter));
|
|
43724
|
-
|
|
43725
|
-
|
|
43877
|
+
const mayBeNameref = list.some((arg) => mayBeOption(arg, (text) => /^-[a-zA-Z]*n/.test(text)));
|
|
43878
|
+
if (builtin !== "export" && mayBeNameref) {
|
|
43879
|
+
throw new Refusal(site.snippet, site.line, option("n") ? "the guard does not follow a nameref (`declare -n`), whose writes land in the variable it names" : `an option word \`${builtin}\` carries that the guard cannot read may be \`-n\`, a nameref ` + "whose writes land in the variable it names and which the guard does not follow; write " + "the option as a literal");
|
|
43726
43880
|
}
|
|
43727
43881
|
if (option("f") || option("F"))
|
|
43728
43882
|
return;
|
|
@@ -43907,11 +44061,20 @@ function checkRecursiveMode(program, list, st, ctx, site) {
|
|
|
43907
44061
|
}
|
|
43908
44062
|
found.push(arg);
|
|
43909
44063
|
}
|
|
43910
|
-
if (!recursive)
|
|
43911
|
-
return;
|
|
43912
|
-
const targets = reference ? found : found.slice(1);
|
|
43913
44064
|
const verb = program === "chmod" ? "recursively change the mode of" : "recursively change the owner of";
|
|
43914
|
-
|
|
44065
|
+
if (recursive) {
|
|
44066
|
+
checkTargets(`${program} -R`, verb, reference ? found : found.slice(1), true, st, ctx, site);
|
|
44067
|
+
return;
|
|
44068
|
+
}
|
|
44069
|
+
for (const [index, arg] of found.entries()) {
|
|
44070
|
+
if (!mayBeOption(arg, (text) => /^-[A-Za-z]*R/.test(text)))
|
|
44071
|
+
continue;
|
|
44072
|
+
const others = arg.fields === "unknown" ? found : found.filter((_, at) => at !== index);
|
|
44073
|
+
const targets = reference || arg.fields === "unknown" ? others : others.slice(1);
|
|
44074
|
+
if (targets.length === 0)
|
|
44075
|
+
continue;
|
|
44076
|
+
checkTargets(`${program} -R`, verb, targets, true, st, ctx, site);
|
|
44077
|
+
}
|
|
43915
44078
|
}
|
|
43916
44079
|
function checkFind(list, st, ctx, site) {
|
|
43917
44080
|
let i = 0;
|
|
@@ -43926,17 +44089,27 @@ function checkFind(list, st, ctx, site) {
|
|
|
43926
44089
|
break;
|
|
43927
44090
|
}
|
|
43928
44091
|
const starts = [];
|
|
44092
|
+
let rootsBeforePredicate;
|
|
43929
44093
|
for (;i < list.length; i += 1) {
|
|
43930
|
-
const
|
|
44094
|
+
const arg = list[i];
|
|
44095
|
+
const text = literalText(arg.exp);
|
|
43931
44096
|
if (text !== undefined && (text.startsWith("-") || text === "(" || text === "!" || text === ")"))
|
|
43932
44097
|
break;
|
|
43933
|
-
|
|
44098
|
+
if (rootsBeforePredicate === undefined && mayBeOption(arg, (option) => option.startsWith("-"))) {
|
|
44099
|
+
rootsBeforePredicate = [...starts];
|
|
44100
|
+
}
|
|
44101
|
+
starts.push(arg);
|
|
43934
44102
|
}
|
|
43935
44103
|
const targets = starts.length > 0 ? starts : [{ text: ".", exp: [literal2(".")] }];
|
|
43936
44104
|
const expression = list.slice(i).map((arg) => literalText(arg.exp));
|
|
43937
44105
|
let action;
|
|
43938
44106
|
let shell;
|
|
44107
|
+
let consumedByPredicate = false;
|
|
43939
44108
|
for (const [index, word] of expression.entries()) {
|
|
44109
|
+
const isValue = consumedByPredicate;
|
|
44110
|
+
consumedByPredicate = word !== undefined && FIND_VALUED_PREDICATES.has(word);
|
|
44111
|
+
if (word === undefined && !isValue)
|
|
44112
|
+
action ??= "find with a predicate the guard cannot read";
|
|
43940
44113
|
if (word === "-delete")
|
|
43941
44114
|
action = "find -delete";
|
|
43942
44115
|
if (word !== "-exec" && word !== "-execdir" && word !== "-ok" && word !== "-okdir")
|
|
@@ -43953,8 +44126,13 @@ function checkFind(list, st, ctx, site) {
|
|
|
43953
44126
|
shell = inner.argv;
|
|
43954
44127
|
}
|
|
43955
44128
|
}
|
|
43956
|
-
if (action === undefined)
|
|
44129
|
+
if (action === undefined) {
|
|
44130
|
+
if (rootsBeforePredicate === undefined)
|
|
44131
|
+
return;
|
|
44132
|
+
const under = rootsBeforePredicate.length > 0 ? rootsBeforePredicate : [{ text: ".", exp: [literal2(".")] }];
|
|
44133
|
+
checkTargets("find with a root the guard cannot read, which may be a predicate", "delete or change what it finds under", under, false, st, ctx, site);
|
|
43957
44134
|
return;
|
|
44135
|
+
}
|
|
43958
44136
|
checkTargets(action, "delete or change what it finds under", targets, false, st, ctx, site);
|
|
43959
44137
|
if (shell === undefined)
|
|
43960
44138
|
return;
|
|
@@ -44231,7 +44409,7 @@ function runInterpreter(base, language, list, invocation, st, ctx) {
|
|
|
44231
44409
|
for (;i < words.length; i += 1) {
|
|
44232
44410
|
const word = words[i];
|
|
44233
44411
|
if (word === undefined)
|
|
44234
|
-
|
|
44412
|
+
continue;
|
|
44235
44413
|
if (codeFlags.includes(word)) {
|
|
44236
44414
|
runCode(language, list[i + 1], invocation, st, ctx, site);
|
|
44237
44415
|
return;
|