@push.rocks/smartdaemon 2.21.0 → 3.0.0
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_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/classes.systemdtransientscope.js +1 -1
- package/dist_ts/classes.systemdunit.js +1 -1
- package/dist_ts/classes.systemdunitfile.js +1 -1
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/smartdaemon.classes.commanderror.d.ts +25 -0
- package/dist_ts/smartdaemon.classes.commanderror.js +27 -0
- package/dist_ts/smartdaemon.classes.systemdmanager.d.ts +12 -0
- package/dist_ts/smartdaemon.classes.systemdmanager.js +63 -30
- package/dist_ts/smartdaemon.paths.js +1 -1
- package/dist_ts/smartdaemon.plugins.d.ts +1 -3
- package/dist_ts/smartdaemon.plugins.js +2 -4
- package/dist_ts/systemd.definition.d.ts +3 -3
- package/dist_ts/systemd.userenvironment.d.ts +1 -1
- package/dist_ts_systemdruntime/classes.systemdnotifier.d.ts +82 -0
- package/dist_ts_systemdruntime/classes.systemdnotifier.js +217 -0
- package/dist_ts_systemdruntime/classes.systemdruntimeerror.d.ts +31 -0
- package/dist_ts_systemdruntime/classes.systemdruntimeerror.js +9 -0
- package/dist_ts_systemdruntime/index.d.ts +5 -0
- package/dist_ts_systemdruntime/index.js +14 -0
- package/dist_ts_systemdruntime/systemdruntime.libc.d.ts +87 -0
- package/dist_ts_systemdruntime/systemdruntime.libc.js +92 -0
- package/dist_ts_systemdruntime/systemdruntime.listen.d.ts +46 -0
- package/dist_ts_systemdruntime/systemdruntime.listen.js +136 -0
- package/dist_ts_systemdruntime/systemdruntime.validation.d.ts +13 -0
- package/dist_ts_systemdruntime/systemdruntime.validation.js +29 -0
- package/package.json +19 -8
- package/readme.md +119 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +1 -0
- package/ts/smartdaemon.classes.commanderror.ts +23 -0
- package/ts/smartdaemon.classes.systemdmanager.ts +78 -34
- package/ts/smartdaemon.plugins.ts +0 -4
- package/ts_systemdruntime/classes.systemdnotifier.ts +287 -0
- package/ts_systemdruntime/classes.systemdruntimeerror.ts +53 -0
- package/ts_systemdruntime/index.ts +22 -0
- package/ts_systemdruntime/systemdruntime.libc.ts +121 -0
- package/ts_systemdruntime/systemdruntime.listen.ts +153 -0
- package/ts_systemdruntime/systemdruntime.validation.ts +41 -0
- package/dist_ts/smartdamon.logging.d.ts +0 -2
- package/dist_ts/smartdamon.logging.js +0 -14
- package/ts/smartdamon.logging.ts +0 -15
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from './smartdaemon.plugins.js';
|
|
2
2
|
import * as paths from './smartdaemon.paths.js';
|
|
3
3
|
import { SmartDaemon } from './smartdaemon.classes.smartdaemon.js';
|
|
4
|
+
import { SmartDaemonCommandError } from './smartdaemon.classes.commanderror.js';
|
|
4
5
|
import { SmartDaemonService, } from './smartdaemon.classes.service.js';
|
|
5
6
|
export class SmartDaemonSystemdManager {
|
|
6
7
|
// STATIC
|
|
@@ -16,6 +17,7 @@ export class SmartDaemonSystemdManager {
|
|
|
16
17
|
}
|
|
17
18
|
constructor(smartdaemonRefArg, sudoPasswordArg) {
|
|
18
19
|
this.shouldExecute = false;
|
|
20
|
+
/** Whether this process runs as root; set by the first privileged operation's check. */
|
|
19
21
|
this.isRoot = false;
|
|
20
22
|
this.smartdaemonRef = smartdaemonRefArg;
|
|
21
23
|
this.smartshellInstance = new plugins.smartshell.Smartshell({
|
|
@@ -23,18 +25,27 @@ export class SmartDaemonSystemdManager {
|
|
|
23
25
|
});
|
|
24
26
|
this.smartFs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
|
|
25
27
|
this.sudoPassword = sudoPasswordArg;
|
|
26
|
-
// Check if we're running as root
|
|
27
|
-
this.checkIsRoot().then(isRoot => {
|
|
28
|
-
this.isRoot = isRoot;
|
|
29
|
-
if (!isRoot) {
|
|
30
|
-
console.log('Not running as root. Sudo will be used for privileged operations.');
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
28
|
}
|
|
34
29
|
async checkIsRoot() {
|
|
35
30
|
const result = await this.smartshellInstance.exec('id -u');
|
|
36
31
|
return result.stdout.trim() === '0';
|
|
37
32
|
}
|
|
33
|
+
/** Checks once whether this process runs as root and sets `isRoot`; later calls reuse that check. */
|
|
34
|
+
ensureRootStatus() {
|
|
35
|
+
if (!this.rootStatus) {
|
|
36
|
+
this.rootStatus = this.checkIsRoot().then((isRoot) => {
|
|
37
|
+
this.isRoot = isRoot;
|
|
38
|
+
if (!isRoot) {
|
|
39
|
+
console.log('Not running as root. Sudo will be used for privileged operations.');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// A failed check is not memoized, so the next privileged operation asks again.
|
|
43
|
+
this.rootStatus.catch(() => {
|
|
44
|
+
this.rootStatus = undefined;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return this.rootStatus;
|
|
48
|
+
}
|
|
38
49
|
async checkElegibility() {
|
|
39
50
|
if (plugins.os.platform() === 'linux') {
|
|
40
51
|
this.shouldExecute = true;
|
|
@@ -45,30 +56,50 @@ export class SmartDaemonSystemdManager {
|
|
|
45
56
|
}
|
|
46
57
|
return this.shouldExecute;
|
|
47
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Runs a command, through sudo when this process is not root and the command does not start with
|
|
61
|
+
* `sudo` already. With a `sudoPassword`, sudo reads it from standard input (`sudo -k -S -p ''`):
|
|
62
|
+
* it never reaches argv, the environment or a terminal. Rejects with `SmartDaemonCommandError`
|
|
63
|
+
* when the command does not exit 0.
|
|
64
|
+
*/
|
|
48
65
|
async execute(commandArg) {
|
|
49
|
-
if (await this.checkElegibility()) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
if (!(await this.checkElegibility())) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
await this.ensureRootStatus();
|
|
70
|
+
if (this.isRoot || commandArg.startsWith('sudo')) {
|
|
71
|
+
return await this.runChecked(commandArg);
|
|
72
|
+
}
|
|
73
|
+
if (!this.sudoPassword) {
|
|
74
|
+
return await this.runChecked(`sudo ${commandArg}`);
|
|
75
|
+
}
|
|
76
|
+
// -k ignores cached credentials, so sudo reads the password line whenever its policy asks for
|
|
77
|
+
// one; ending stdin right after it makes a rejected password fail instead of waiting for a retry.
|
|
78
|
+
const sudoCommand = `sudo -k -S -p '' -- ${commandArg}`;
|
|
79
|
+
const interactiveExec = await this.smartshellInstance.execInteractiveControl(sudoCommand);
|
|
80
|
+
let writeError;
|
|
81
|
+
try {
|
|
82
|
+
await interactiveExec.sendLine(this.sudoPassword);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// sudo can exit before reading stdin (EPIPE); its exit status below decides the outcome.
|
|
86
|
+
writeError = error;
|
|
87
|
+
}
|
|
88
|
+
interactiveExec.endInput();
|
|
89
|
+
const result = await interactiveExec.finalPromise;
|
|
90
|
+
this.assertSucceeded(sudoCommand, result, writeError);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
async runChecked(commandArg) {
|
|
94
|
+
const result = await this.smartshellInstance.exec(commandArg);
|
|
95
|
+
this.assertSucceeded(commandArg, result);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
assertSucceeded(commandArg, resultArg, causeArg) {
|
|
99
|
+
if (resultArg.exitCode === 0 && !resultArg.signal) {
|
|
100
|
+
return;
|
|
71
101
|
}
|
|
102
|
+
throw new SmartDaemonCommandError(commandArg, resultArg.exitCode, resultArg.signal, resultArg.stderr, causeArg === undefined ? undefined : { cause: causeArg });
|
|
72
103
|
}
|
|
73
104
|
/**
|
|
74
105
|
* gets all services that are already present
|
|
@@ -101,6 +132,7 @@ export class SmartDaemonSystemdManager {
|
|
|
101
132
|
if (await this.checkElegibility()) {
|
|
102
133
|
const content = this.smartdaemonRef.templateManager.generateUnitFileForService(serviceArg);
|
|
103
134
|
const targetPath = SmartDaemonSystemdManager.createFilePathFromServiceName(serviceArg.name);
|
|
135
|
+
await this.ensureRootStatus();
|
|
104
136
|
if (this.isRoot) {
|
|
105
137
|
// Direct write when running as root
|
|
106
138
|
await this.smartFs.file(targetPath).encoding('utf8').mode(0o644).write(content);
|
|
@@ -117,6 +149,7 @@ export class SmartDaemonSystemdManager {
|
|
|
117
149
|
async deleteService(serviceArg) {
|
|
118
150
|
if (await this.checkElegibility()) {
|
|
119
151
|
const filePath = SmartDaemonSystemdManager.createFilePathFromServiceName(serviceArg.name);
|
|
152
|
+
await this.ensureRootStatus();
|
|
120
153
|
if (this.isRoot) {
|
|
121
154
|
await this.smartFs.file(filePath).delete();
|
|
122
155
|
}
|
|
@@ -145,4 +178,4 @@ export class SmartDaemonSystemdManager {
|
|
|
145
178
|
}
|
|
146
179
|
}
|
|
147
180
|
}
|
|
148
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
181
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYWVtb24uY2xhc3Nlcy5zeXN0ZW1kbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0ZGFlbW9uLmNsYXNzZXMuc3lzdGVtZG1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssS0FBSyxNQUFNLHdCQUF3QixDQUFDO0FBQ2hELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUNuRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNoRixPQUFPLEVBRUwsa0JBQWtCLEdBQ25CLE1BQU0sa0NBQWtDLENBQUM7QUFFMUMsTUFBTSxPQUFPLHlCQUF5QjtJQUNwQyxTQUFTO2FBQ00seUJBQW9CLEdBQUcsYUFBYSxBQUFoQixDQUFpQjtJQUU3QyxNQUFNLENBQUMsZ0NBQWdDLENBQUMsY0FBc0I7UUFDbkUsT0FBTyxHQUFHLHlCQUF5QixDQUFDLG9CQUFvQixJQUFJLGNBQWMsRUFBRSxDQUFDO0lBQy9FLENBQUM7SUFFTSxNQUFNLENBQUMsNkJBQTZCLENBQUMsY0FBc0I7UUFDaEUsT0FBTyxHQUFHLHlCQUF5QixDQUFDLGdDQUFnQyxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUM7SUFDakcsQ0FBQztJQUVNLE1BQU0sQ0FBQyw2QkFBNkIsQ0FBQyxjQUFzQjtRQUNoRSxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUN0QixLQUFLLENBQUMsVUFBVSxFQUNoQix5QkFBeUIsQ0FBQyw2QkFBNkIsQ0FBQyxjQUFjLENBQUMsQ0FDeEUsQ0FBQztJQUNKLENBQUM7SUFhRCxZQUFZLGlCQUE4QixFQUFFLGVBQXdCO1FBTjdELGtCQUFhLEdBQVksS0FBSyxDQUFDO1FBQ3RDLHdGQUF3RjtRQUNqRixXQUFNLEdBQVksS0FBSyxDQUFDO1FBSzdCLElBQUksQ0FBQyxj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
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as plugins from './smartdaemon.plugins.js';
|
|
2
2
|
export const packageDir = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '../');
|
|
3
3
|
export const systemdDir = plugins.path.join('/lib/systemd/system/');
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYWVtb24ucGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhZW1vbi5wYXRocy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBRXBELE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FDekMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsd0JBQXdCLENBQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQy9ELEtBQUssQ0FDTixDQUFDO0FBQ0YsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUMifQ==
|
|
@@ -9,9 +9,7 @@ export type { Stats } from 'node:fs';
|
|
|
9
9
|
export { path, childProcess, fs, fsConstants, crypto, util, os };
|
|
10
10
|
import * as lik from '@push.rocks/lik';
|
|
11
11
|
import * as smartfs from '@push.rocks/smartfs';
|
|
12
|
-
import * as smartlog from '@push.rocks/smartlog';
|
|
13
|
-
import * as smartlogDestinationLocal from '@push.rocks/smartlog/destination-local';
|
|
14
12
|
import * as smartmarkdown from '@push.rocks/smartmarkdown/iso';
|
|
15
13
|
import * as smartpath from '@push.rocks/smartpath';
|
|
16
14
|
import * as smartshell from '@push.rocks/smartshell';
|
|
17
|
-
export { lik, smartfs,
|
|
15
|
+
export { lik, smartfs, smartmarkdown, smartpath, smartshell, };
|
|
@@ -10,11 +10,9 @@ export { path, childProcess, fs, fsConstants, crypto, util, os };
|
|
|
10
10
|
// @pushrocks scope
|
|
11
11
|
import * as lik from '@push.rocks/lik';
|
|
12
12
|
import * as smartfs from '@push.rocks/smartfs';
|
|
13
|
-
import * as smartlog from '@push.rocks/smartlog';
|
|
14
|
-
import * as smartlogDestinationLocal from '@push.rocks/smartlog/destination-local';
|
|
15
13
|
import * as smartmarkdown from '@push.rocks/smartmarkdown/iso';
|
|
16
14
|
import * as smartpath from '@push.rocks/smartpath';
|
|
17
15
|
import * as smartshell from '@push.rocks/smartshell';
|
|
18
|
-
export { lik, smartfs,
|
|
16
|
+
export { lik, smartfs, smartmarkdown, smartpath, smartshell, };
|
|
19
17
|
// third party
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYWVtb24ucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0ZGFlbW9uLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sS0FBSyxZQUFZLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN2QyxPQUFPLEVBQUUsU0FBUyxJQUFJLFdBQVcsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNuRCxPQUFPLEtBQUssTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUN0QyxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUc5QixPQUFPLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxFQUFFLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUM7QUFFakUsbUJBQW1CO0FBQ25CLE9BQU8sS0FBSyxHQUFHLE1BQU0saUJBQWlCLENBQUM7QUFDdkMsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQUMvQyxPQUFPLEtBQUssYUFBYSxNQUFNLCtCQUErQixDQUFDO0FBQy9ELE9BQU8sS0FBSyxTQUFTLE1BQU0sdUJBQXVCLENBQUM7QUFDbkQsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsR0FBRyxFQUNILE9BQU8sRUFDUCxhQUFhLEVBQ2IsU0FBUyxFQUNULFVBQVUsR0FDWCxDQUFDO0FBRUYsY0FBYyJ9
|
|
@@ -58,10 +58,10 @@ export interface ISystemdServiceCredential {
|
|
|
58
58
|
source?: string;
|
|
59
59
|
}
|
|
60
60
|
/** Linux capabilities systemd 255 knows by name, for `capabilityBoundingSet` and `ambientCapabilities`. */
|
|
61
|
-
export declare const systemdCapabilities: readonly [
|
|
61
|
+
export declare const systemdCapabilities: readonly ['CAP_AUDIT_CONTROL', 'CAP_AUDIT_READ', 'CAP_AUDIT_WRITE', 'CAP_BLOCK_SUSPEND', 'CAP_BPF', 'CAP_CHECKPOINT_RESTORE', 'CAP_CHOWN', 'CAP_DAC_OVERRIDE', 'CAP_DAC_READ_SEARCH', 'CAP_FOWNER', 'CAP_FSETID', 'CAP_IPC_LOCK', 'CAP_IPC_OWNER', 'CAP_KILL', 'CAP_LEASE', 'CAP_LINUX_IMMUTABLE', 'CAP_MAC_ADMIN', 'CAP_MAC_OVERRIDE', 'CAP_MKNOD', 'CAP_NET_ADMIN', 'CAP_NET_BIND_SERVICE', 'CAP_NET_BROADCAST', 'CAP_NET_RAW', 'CAP_PERFMON', 'CAP_SETFCAP', 'CAP_SETGID', 'CAP_SETPCAP', 'CAP_SETUID', 'CAP_SYSLOG', 'CAP_SYS_ADMIN', 'CAP_SYS_BOOT', 'CAP_SYS_CHROOT', 'CAP_SYS_MODULE', 'CAP_SYS_NICE', 'CAP_SYS_PACCT', 'CAP_SYS_PTRACE', 'CAP_SYS_RAWIO', 'CAP_SYS_RESOURCE', 'CAP_SYS_TIME', 'CAP_SYS_TTY_CONFIG', 'CAP_WAKE_ALARM'];
|
|
62
62
|
export type TSystemdCapability = typeof systemdCapabilities[number];
|
|
63
63
|
/** Socket address families a definition may allow with `restrictAddressFamilies`. */
|
|
64
|
-
export declare const systemdAddressFamilies: readonly [
|
|
64
|
+
export declare const systemdAddressFamilies: readonly ['AF_INET', 'AF_INET6', 'AF_NETLINK', 'AF_PACKET', 'AF_UNIX', 'AF_VSOCK'];
|
|
65
65
|
export type TSystemdAddressFamily = typeof systemdAddressFamilies[number];
|
|
66
66
|
/**
|
|
67
67
|
* Internal bounds of a definition's `environment`: variables, and UTF-8 bytes of `NAME=value` in
|
|
@@ -82,7 +82,7 @@ export declare const renderServiceRelations: (options: {
|
|
|
82
82
|
startup?: TSystemdServiceStartup;
|
|
83
83
|
dependencies?: ISystemdServiceDependencies;
|
|
84
84
|
install?: ISystemdServiceInstallTargets;
|
|
85
|
-
}, unitName: string, restart: string, scope:
|
|
85
|
+
}, unitName: string, restart: string, scope: 'system' | 'user', fail: (option: 'startup' | 'dependencies' | 'install') => never) => {
|
|
86
86
|
unit: string[];
|
|
87
87
|
service: string[];
|
|
88
88
|
install: string[];
|
|
@@ -36,4 +36,4 @@ export declare const isUserManagerEnvironment: (environment: ISystemdUserEnviron
|
|
|
36
36
|
* the path must be its own real path and a directory owned by that uid without group or other
|
|
37
37
|
* permissions. `absent` is a directory that does not exist; every other refusal is `unsafe`.
|
|
38
38
|
*/
|
|
39
|
-
export declare const inspectRuntimeDirectory: (runtimeDirectory: string) => Promise<
|
|
39
|
+
export declare const inspectRuntimeDirectory: (runtimeDirectory: string) => Promise<'private' | 'absent' | 'unsafe'>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** `NOTIFY_BUFFER_MAX` (`PIPE_BUF`): systemd ignores a longer notification message. */
|
|
2
|
+
export declare const notifyMessageMaximumBytes = 4096;
|
|
3
|
+
export interface ISystemdEnvironmentOptions {
|
|
4
|
+
/** The environment to read; `process.env` by default. */
|
|
5
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
6
|
+
}
|
|
7
|
+
export interface ISystemdNotifierEnvironmentOptions extends ISystemdEnvironmentOptions {
|
|
8
|
+
/** Remove `NOTIFY_SOCKET` from the environment, so no child inherits it. Default `false`. */
|
|
9
|
+
readonly take?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ISystemdStoreDescriptorsOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the manager watches the stored descriptors and drops one that reports `POLLHUP` or
|
|
14
|
+
* `POLLERR` (`FDPOLL=`). Default `true`, as in systemd; `false` sends `FDPOLL=0`, for descriptors
|
|
15
|
+
* that are not pollable or always report hang-up, such as namespace descriptors.
|
|
16
|
+
*/
|
|
17
|
+
readonly poll?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Takes `NOTIFY_SOCKET` out of the environment: the validated address, or null when it is unset or
|
|
21
|
+
* empty. An address that is set but invalid is removed as well and then refused
|
|
22
|
+
* (`notify_socket_invalid`).
|
|
23
|
+
*/
|
|
24
|
+
export declare const takeSystemdNotifySocket: (optionsArg?: ISystemdEnvironmentOptions) => string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Sends `sd_notify(3)` messages to a service manager's notification socket: one `AF_UNIX`
|
|
27
|
+
* `SOCK_DGRAM` datagram per message, descriptors attached as `SCM_RIGHTS`. Every call is synchronous
|
|
28
|
+
* and either delivers the whole message to the socket or throws a `SystemdRuntimeError`; whether
|
|
29
|
+
* the manager acts on it depends on the unit's `NotifyAccess=`. Fields and descriptor names are
|
|
30
|
+
* validated before sending, because systemd ignores a message it cannot parse without telling the
|
|
31
|
+
* sender.
|
|
32
|
+
*/
|
|
33
|
+
export declare class SystemdNotifier {
|
|
34
|
+
/**
|
|
35
|
+
* The notifier for the unit that started this process, or null when `NOTIFY_SOCKET` is unset or
|
|
36
|
+
* empty — the process was not started by a service manager that listens. The caller decides what
|
|
37
|
+
* that means; nothing is sent silently nowhere. An invalid `NOTIFY_SOCKET` throws
|
|
38
|
+
* `notify_socket_invalid`.
|
|
39
|
+
*/
|
|
40
|
+
static fromEnvironment(optionsArg?: ISystemdNotifierEnvironmentOptions): SystemdNotifier | null;
|
|
41
|
+
/** The notification socket: an absolute path, or an abstract name written `@name`. */
|
|
42
|
+
readonly socketAddress: string;
|
|
43
|
+
constructor(socketAddressArg: string);
|
|
44
|
+
/** `READY=1`, with an optional `STATUS=`. */
|
|
45
|
+
ready(statusArg?: string): void;
|
|
46
|
+
/** `STATUS=`: free-form text the manager shows as the unit's status. */
|
|
47
|
+
status(textArg: string): void;
|
|
48
|
+
/** `STOPPING=1`, with an optional `STATUS=`. */
|
|
49
|
+
stopping(statusArg?: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* `RELOADING=1` with `MONOTONIC_USEC=` (`CLOCK_MONOTONIC` now), with an optional `STATUS=`. The
|
|
52
|
+
* service sends `ready()` once the reload finished.
|
|
53
|
+
*/
|
|
54
|
+
reloading(statusArg?: string): void;
|
|
55
|
+
/** `WATCHDOG=1`: keeps a `WatchdogSec=` unit alive. */
|
|
56
|
+
watchdog(): void;
|
|
57
|
+
/**
|
|
58
|
+
* `EXTEND_TIMEOUT_USEC=`: asks the manager to wait `microsecondsArg` longer for the current start,
|
|
59
|
+
* runtime-start, stop or watchdog deadline, with an optional `STATUS=`.
|
|
60
|
+
*/
|
|
61
|
+
extendTimeout(microsecondsArg: number, statusArg?: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* `FDSTORE=1` with `FDNAME=`: the manager keeps duplicates of `descriptorsArg` (1–253) under
|
|
64
|
+
* `nameArg` in the unit's descriptor store (`FileDescriptorStoreMax=`) and passes them to the
|
|
65
|
+
* next main process through `LISTEN_FDS`. Storing does not replace descriptors already stored
|
|
66
|
+
* under the name; `replaceDescriptors()` does.
|
|
67
|
+
*/
|
|
68
|
+
storeDescriptors(nameArg: string, descriptorsArg: readonly number[], optionsArg?: ISystemdStoreDescriptorsOptions): void;
|
|
69
|
+
/** `FDSTOREREMOVE=1` with `FDNAME=`: the manager closes every descriptor stored under `nameArg`. */
|
|
70
|
+
removeDescriptors(nameArg: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Removes the descriptors stored under `nameArg`, then stores `descriptorsArg` under it: two
|
|
73
|
+
* messages, handled by the manager in order. Between them the store holds nothing under the name.
|
|
74
|
+
*/
|
|
75
|
+
replaceDescriptors(nameArg: string, descriptorsArg: readonly number[], optionsArg?: ISystemdStoreDescriptorsOptions): void;
|
|
76
|
+
/**
|
|
77
|
+
* Sends one message: `NAME=value` fields in insertion order, joined by newlines, and up to 253
|
|
78
|
+
* descriptors. Names are upper-case (`A–Z`, digits, `_`); values carry no newline or NUL; the
|
|
79
|
+
* message is at most 4096 bytes.
|
|
80
|
+
*/
|
|
81
|
+
send(fieldsArg: Readonly<Record<string, string>>, descriptorsArg?: readonly number[]): void;
|
|
82
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { SystemdRuntimeError } from './classes.systemdruntimeerror.js';
|
|
2
|
+
import { controlSpace, descriptorsPerMessageMaximum, libcConstants, socketAddressLength, systemdLibc, writeSocketAddress, } from './systemdruntime.libc.js';
|
|
3
|
+
import { assertSystemdDescriptor, assertSystemdNotifySocketAddress, isSystemdDescriptorName, } from './systemdruntime.validation.js';
|
|
4
|
+
/** `NOTIFY_BUFFER_MAX` (`PIPE_BUF`): systemd ignores a longer notification message. */
|
|
5
|
+
export const notifyMessageMaximumBytes = 4096;
|
|
6
|
+
/**
|
|
7
|
+
* Takes `NOTIFY_SOCKET` out of the environment: the validated address, or null when it is unset or
|
|
8
|
+
* empty. An address that is set but invalid is removed as well and then refused
|
|
9
|
+
* (`notify_socket_invalid`).
|
|
10
|
+
*/
|
|
11
|
+
export const takeSystemdNotifySocket = (optionsArg = {}) => {
|
|
12
|
+
const env = optionsArg.env ?? process.env;
|
|
13
|
+
const address = env.NOTIFY_SOCKET;
|
|
14
|
+
delete env.NOTIFY_SOCKET;
|
|
15
|
+
if (address === undefined || address === '')
|
|
16
|
+
return null;
|
|
17
|
+
assertSystemdNotifySocketAddress(address);
|
|
18
|
+
return address;
|
|
19
|
+
};
|
|
20
|
+
const fieldNamePattern = /^[A-Z][A-Z0-9_]*$/;
|
|
21
|
+
/**
|
|
22
|
+
* Sends `sd_notify(3)` messages to a service manager's notification socket: one `AF_UNIX`
|
|
23
|
+
* `SOCK_DGRAM` datagram per message, descriptors attached as `SCM_RIGHTS`. Every call is synchronous
|
|
24
|
+
* and either delivers the whole message to the socket or throws a `SystemdRuntimeError`; whether
|
|
25
|
+
* the manager acts on it depends on the unit's `NotifyAccess=`. Fields and descriptor names are
|
|
26
|
+
* validated before sending, because systemd ignores a message it cannot parse without telling the
|
|
27
|
+
* sender.
|
|
28
|
+
*/
|
|
29
|
+
export class SystemdNotifier {
|
|
30
|
+
/**
|
|
31
|
+
* The notifier for the unit that started this process, or null when `NOTIFY_SOCKET` is unset or
|
|
32
|
+
* empty — the process was not started by a service manager that listens. The caller decides what
|
|
33
|
+
* that means; nothing is sent silently nowhere. An invalid `NOTIFY_SOCKET` throws
|
|
34
|
+
* `notify_socket_invalid`.
|
|
35
|
+
*/
|
|
36
|
+
static fromEnvironment(optionsArg = {}) {
|
|
37
|
+
const env = optionsArg.env ?? process.env;
|
|
38
|
+
const address = optionsArg.take === true ? takeSystemdNotifySocket({ env }) : env.NOTIFY_SOCKET;
|
|
39
|
+
if (address === undefined || address === null || address === '')
|
|
40
|
+
return null;
|
|
41
|
+
return new SystemdNotifier(address);
|
|
42
|
+
}
|
|
43
|
+
constructor(socketAddressArg) {
|
|
44
|
+
assertSystemdNotifySocketAddress(socketAddressArg);
|
|
45
|
+
this.socketAddress = socketAddressArg;
|
|
46
|
+
}
|
|
47
|
+
/** `READY=1`, with an optional `STATUS=`. */
|
|
48
|
+
ready(statusArg) {
|
|
49
|
+
this.send({ READY: '1', ...(statusArg === undefined ? {} : { STATUS: statusArg }) });
|
|
50
|
+
}
|
|
51
|
+
/** `STATUS=`: free-form text the manager shows as the unit's status. */
|
|
52
|
+
status(textArg) {
|
|
53
|
+
this.send({ STATUS: textArg });
|
|
54
|
+
}
|
|
55
|
+
/** `STOPPING=1`, with an optional `STATUS=`. */
|
|
56
|
+
stopping(statusArg) {
|
|
57
|
+
this.send({ STOPPING: '1', ...(statusArg === undefined ? {} : { STATUS: statusArg }) });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `RELOADING=1` with `MONOTONIC_USEC=` (`CLOCK_MONOTONIC` now), with an optional `STATUS=`. The
|
|
61
|
+
* service sends `ready()` once the reload finished.
|
|
62
|
+
*/
|
|
63
|
+
reloading(statusArg) {
|
|
64
|
+
this.send({
|
|
65
|
+
RELOADING: '1',
|
|
66
|
+
MONOTONIC_USEC: String(monotonicMicroseconds()),
|
|
67
|
+
...(statusArg === undefined ? {} : { STATUS: statusArg }),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** `WATCHDOG=1`: keeps a `WatchdogSec=` unit alive. */
|
|
71
|
+
watchdog() {
|
|
72
|
+
this.send({ WATCHDOG: '1' });
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* `EXTEND_TIMEOUT_USEC=`: asks the manager to wait `microsecondsArg` longer for the current start,
|
|
76
|
+
* runtime-start, stop or watchdog deadline, with an optional `STATUS=`.
|
|
77
|
+
*/
|
|
78
|
+
extendTimeout(microsecondsArg, statusArg) {
|
|
79
|
+
if (!Number.isSafeInteger(microsecondsArg) || microsecondsArg <= 0) {
|
|
80
|
+
throw new SystemdRuntimeError('notify_field_invalid', 'EXTEND_TIMEOUT_USEC must be a positive integer.');
|
|
81
|
+
}
|
|
82
|
+
this.send({
|
|
83
|
+
EXTEND_TIMEOUT_USEC: String(microsecondsArg),
|
|
84
|
+
...(statusArg === undefined ? {} : { STATUS: statusArg }),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* `FDSTORE=1` with `FDNAME=`: the manager keeps duplicates of `descriptorsArg` (1–253) under
|
|
89
|
+
* `nameArg` in the unit's descriptor store (`FileDescriptorStoreMax=`) and passes them to the
|
|
90
|
+
* next main process through `LISTEN_FDS`. Storing does not replace descriptors already stored
|
|
91
|
+
* under the name; `replaceDescriptors()` does.
|
|
92
|
+
*/
|
|
93
|
+
storeDescriptors(nameArg, descriptorsArg, optionsArg = {}) {
|
|
94
|
+
assertDescriptorName(nameArg);
|
|
95
|
+
assertStoredDescriptors(descriptorsArg);
|
|
96
|
+
this.send({ FDSTORE: '1', FDNAME: nameArg, ...(optionsArg.poll === false ? { FDPOLL: '0' } : {}) }, descriptorsArg);
|
|
97
|
+
}
|
|
98
|
+
/** `FDSTOREREMOVE=1` with `FDNAME=`: the manager closes every descriptor stored under `nameArg`. */
|
|
99
|
+
removeDescriptors(nameArg) {
|
|
100
|
+
assertDescriptorName(nameArg);
|
|
101
|
+
this.send({ FDSTOREREMOVE: '1', FDNAME: nameArg });
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Removes the descriptors stored under `nameArg`, then stores `descriptorsArg` under it: two
|
|
105
|
+
* messages, handled by the manager in order. Between them the store holds nothing under the name.
|
|
106
|
+
*/
|
|
107
|
+
replaceDescriptors(nameArg, descriptorsArg, optionsArg = {}) {
|
|
108
|
+
assertDescriptorName(nameArg);
|
|
109
|
+
assertStoredDescriptors(descriptorsArg);
|
|
110
|
+
this.removeDescriptors(nameArg);
|
|
111
|
+
this.storeDescriptors(nameArg, descriptorsArg, optionsArg);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Sends one message: `NAME=value` fields in insertion order, joined by newlines, and up to 253
|
|
115
|
+
* descriptors. Names are upper-case (`A–Z`, digits, `_`); values carry no newline or NUL; the
|
|
116
|
+
* message is at most 4096 bytes.
|
|
117
|
+
*/
|
|
118
|
+
send(fieldsArg, descriptorsArg = []) {
|
|
119
|
+
const entries = Object.entries(fieldsArg);
|
|
120
|
+
if (entries.length === 0) {
|
|
121
|
+
throw new SystemdRuntimeError('notify_field_invalid', 'A notification needs at least one field.');
|
|
122
|
+
}
|
|
123
|
+
for (const [name, value] of entries) {
|
|
124
|
+
if (!fieldNamePattern.test(name)) {
|
|
125
|
+
throw new SystemdRuntimeError('notify_field_invalid', `${JSON.stringify(name)} is not a notification field name.`);
|
|
126
|
+
}
|
|
127
|
+
if (typeof value !== 'string' || /[\n\0]/.test(value)) {
|
|
128
|
+
throw new SystemdRuntimeError('notify_field_invalid', `The ${name} value must be a string without newline or NUL.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
assertDescriptorList(descriptorsArg);
|
|
132
|
+
const payload = Buffer.from(entries.map(([name, value]) => `${name}=${value}`).join('\n'), 'utf8');
|
|
133
|
+
if (payload.length > notifyMessageMaximumBytes) {
|
|
134
|
+
throw new SystemdRuntimeError('notify_field_invalid', `The message is ${payload.length} bytes; systemd reads at most ${notifyMessageMaximumBytes}.`);
|
|
135
|
+
}
|
|
136
|
+
sendDatagram(this.socketAddress, payload, descriptorsArg);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const assertDescriptorName = (nameArg) => {
|
|
140
|
+
if (!isSystemdDescriptorName(nameArg, true)) {
|
|
141
|
+
throw new SystemdRuntimeError('descriptor_name_invalid', 'A descriptor name is 1–255 printable ASCII characters without ":".');
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
/** At most 253 valid descriptor numbers. */
|
|
145
|
+
const assertDescriptorList = (descriptorsArg) => {
|
|
146
|
+
if (descriptorsArg.length > descriptorsPerMessageMaximum) {
|
|
147
|
+
throw new SystemdRuntimeError('descriptor_invalid', `One message carries at most ${descriptorsPerMessageMaximum} descriptors.`);
|
|
148
|
+
}
|
|
149
|
+
descriptorsArg.forEach(assertSystemdDescriptor);
|
|
150
|
+
};
|
|
151
|
+
/** 1–253 valid descriptor numbers, as `FDSTORE=1` needs. */
|
|
152
|
+
const assertStoredDescriptors = (descriptorsArg) => {
|
|
153
|
+
if (descriptorsArg.length === 0) {
|
|
154
|
+
throw new SystemdRuntimeError('descriptor_invalid', 'FDSTORE=1 needs at least one descriptor.');
|
|
155
|
+
}
|
|
156
|
+
assertDescriptorList(descriptorsArg);
|
|
157
|
+
};
|
|
158
|
+
/** `CLOCK_MONOTONIC` in microseconds, as `MONOTONIC_USEC=` expects. */
|
|
159
|
+
const monotonicMicroseconds = () => {
|
|
160
|
+
const libc = systemdLibc();
|
|
161
|
+
const timespec = Buffer.alloc(16);
|
|
162
|
+
if (libc.functions.clock_gettime(libcConstants.CLOCK_MONOTONIC, timespec) !== 0) {
|
|
163
|
+
throw new SystemdRuntimeError('notify_failed', 'clock_gettime(CLOCK_MONOTONIC) failed.', { errno: libc.errno() });
|
|
164
|
+
}
|
|
165
|
+
return timespec.readBigInt64LE(0) * 1000000n + timespec.readBigInt64LE(8) / 1000n;
|
|
166
|
+
};
|
|
167
|
+
// One block holds the whole message, so every pointer inside it stays valid while the block is
|
|
168
|
+
// borrowed by the call: msghdr, iovec, sockaddr_un, control data, payload.
|
|
169
|
+
const iovecOffset = 56;
|
|
170
|
+
const addressOffset = 72;
|
|
171
|
+
const controlOffset = 184;
|
|
172
|
+
const sendDatagram = (addressArg, payloadArg, descriptorsArg) => {
|
|
173
|
+
const libc = systemdLibc();
|
|
174
|
+
const space = descriptorsArg.length === 0 ? 0 : controlSpace(descriptorsArg.length);
|
|
175
|
+
const payloadOffset = controlOffset + space;
|
|
176
|
+
const block = Buffer.alloc(payloadOffset + payloadArg.length);
|
|
177
|
+
const base = libc.ffi.getRawPointer(block);
|
|
178
|
+
writeSocketAddress(block, addressOffset, addressArg);
|
|
179
|
+
payloadArg.copy(block, payloadOffset);
|
|
180
|
+
block.writeBigUInt64LE(base + BigInt(addressOffset), 0);
|
|
181
|
+
block.writeUInt32LE(socketAddressLength(addressArg), 8);
|
|
182
|
+
block.writeBigUInt64LE(base + BigInt(iovecOffset), 16);
|
|
183
|
+
block.writeBigUInt64LE(1n, 24);
|
|
184
|
+
block.writeBigUInt64LE(base + BigInt(payloadOffset), iovecOffset);
|
|
185
|
+
block.writeBigUInt64LE(BigInt(payloadArg.length), iovecOffset + 8);
|
|
186
|
+
if (space > 0) {
|
|
187
|
+
block.writeBigUInt64LE(base + BigInt(controlOffset), 32);
|
|
188
|
+
block.writeBigUInt64LE(BigInt(space), 40);
|
|
189
|
+
block.writeBigUInt64LE(BigInt(16 + 4 * descriptorsArg.length), controlOffset);
|
|
190
|
+
block.writeInt32LE(libcConstants.SOL_SOCKET, controlOffset + 8);
|
|
191
|
+
block.writeInt32LE(libcConstants.SCM_RIGHTS, controlOffset + 12);
|
|
192
|
+
descriptorsArg.forEach((descriptor, index) => block.writeInt32LE(descriptor, controlOffset + 16 + 4 * index));
|
|
193
|
+
}
|
|
194
|
+
const socket = libc.functions.socket(libcConstants.AF_UNIX, libcConstants.SOCK_DGRAM | libcConstants.SOCK_CLOEXEC, 0);
|
|
195
|
+
if (socket < 0) {
|
|
196
|
+
throw new SystemdRuntimeError('notify_failed', 'socket(AF_UNIX, SOCK_DGRAM) failed.', { errno: libc.errno() });
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
let sent = libc.functions.sendmsg(socket, block, libcConstants.MSG_NOSIGNAL);
|
|
200
|
+
let errno = sent < 0n ? libc.errno() : 0;
|
|
201
|
+
while (sent < 0n && errno === libcConstants.EINTR) {
|
|
202
|
+
sent = libc.functions.sendmsg(socket, block, libcConstants.MSG_NOSIGNAL);
|
|
203
|
+
errno = sent < 0n ? libc.errno() : 0;
|
|
204
|
+
}
|
|
205
|
+
if (sent < 0n) {
|
|
206
|
+
throw new SystemdRuntimeError('notify_failed', `sendmsg to ${addressArg} failed.`, { errno });
|
|
207
|
+
}
|
|
208
|
+
if (sent !== BigInt(payloadArg.length)) {
|
|
209
|
+
throw new SystemdRuntimeError('notify_failed', `sendmsg to ${addressArg} sent ${sent} of ${payloadArg.length} bytes.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
// Linux releases the descriptor whatever close(2) reports; the socket is this call's alone.
|
|
214
|
+
libc.functions.close(socket);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kbm90aWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zeXN0ZW1kcnVudGltZS9jbGFzc2VzLnN5c3RlbWRub3RpZmllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUN2RSxPQUFPLEVBQ0wsWUFBWSxFQUNaLDRCQUE0QixFQUM1QixhQUFhLEVBQ2IsbUJBQW1CLEVBQ25CLFdBQVcsRUFDWCxrQkFBa0IsR0FDbkIsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGdDQUFnQyxFQUNoQyx1QkFBdUIsR0FDeEIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV4Qyx1RkFBdUY7QUFDdkYsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsSUFBSSxDQUFDO0FBcUI5Qzs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsQ0FBQyxVQUFVLEdBQStCLEVBQUUsRUFBaUIsRUFBRTtJQUNwRyxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUM7SUFDMUMsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLGFBQWEsQ0FBQztJQUNsQyxPQUFPLEdBQUcsQ0FBQyxhQUFhLENBQUM7SUFDekIsSUFBSSxPQUFPLEtBQUssU0FBUyxJQUFJLE9BQU8sS0FBSyxFQUFFO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDekQsZ0NBQWdDLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDMUMsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxnQkFBZ0IsR0FBRyxtQkFBbUIsQ0FBQztBQUU3Qzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFDMUI7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsZUFBZSxDQUFDLFVBQVUsR0FBdUMsRUFBRTtR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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a systemd runtime operation refused or failed:
|
|
3
|
+
*
|
|
4
|
+
* - `runtime_unsupported`: the runtime cannot make the call: Node.js older than 26, a platform
|
|
5
|
+
* other than Linux on x64 or arm64, a C library other than glibc (`libc.so.6`), `node:ffi`
|
|
6
|
+
* disabled (`--no-experimental-ffi`) or denied by the permission model (no `--allow-ffi`).
|
|
7
|
+
* - `notify_socket_invalid`: `NOTIFY_SOCKET` is not an `AF_UNIX` path or abstract name this
|
|
8
|
+
* module can address (`vsock:` addresses included).
|
|
9
|
+
* - `notify_field_invalid`: a notification field name or value systemd would not parse, or a
|
|
10
|
+
* message larger than systemd reads (4096 bytes).
|
|
11
|
+
* - `notify_failed`: the message could not be sent (`errno` names why).
|
|
12
|
+
* - `descriptor_name_invalid`: an `FDNAME=` systemd would refuse.
|
|
13
|
+
* - `descriptor_invalid`: a descriptor number that cannot exist, or a count outside 1–253.
|
|
14
|
+
* - `listen_environment_invalid`: `LISTEN_PID`, `LISTEN_FDS` or `LISTEN_FDNAMES` is malformed,
|
|
15
|
+
* `LISTEN_FDS` names a descriptor at or above the process's hard `RLIMIT_NOFILE`, or
|
|
16
|
+
* `getrlimit(RLIMIT_NOFILE)` failed, so the count cannot be bounded (`errno` names why).
|
|
17
|
+
* - `watchdog_environment_invalid`: `WATCHDOG_USEC` or `WATCHDOG_PID` is malformed.
|
|
18
|
+
* - `close_on_exec_failed`: a descriptor could not be marked close-on-exec (`errno` names why).
|
|
19
|
+
*/
|
|
20
|
+
export type TSystemdRuntimeErrorCode = 'runtime_unsupported' | 'notify_socket_invalid' | 'notify_field_invalid' | 'notify_failed' | 'descriptor_name_invalid' | 'descriptor_invalid' | 'listen_environment_invalid' | 'watchdog_environment_invalid' | 'close_on_exec_failed';
|
|
21
|
+
export interface ISystemdRuntimeErrorOptions {
|
|
22
|
+
/** The C library's `errno` after the failed call, when a call failed. */
|
|
23
|
+
readonly errno?: number;
|
|
24
|
+
readonly cause?: unknown;
|
|
25
|
+
}
|
|
26
|
+
export declare class SystemdRuntimeError extends Error {
|
|
27
|
+
readonly code: TSystemdRuntimeErrorCode;
|
|
28
|
+
/** The C library's `errno` after the failed call, or null when no call failed. */
|
|
29
|
+
readonly errno: number | null;
|
|
30
|
+
constructor(code: TSystemdRuntimeErrorCode, messageArg: string, optionsArg?: ISystemdRuntimeErrorOptions);
|
|
31
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export class SystemdRuntimeError extends Error {
|
|
2
|
+
constructor(code, messageArg, optionsArg = {}) {
|
|
3
|
+
super(`${messageArg}${optionsArg.errno === undefined ? '' : ` (errno ${optionsArg.errno})`}`, optionsArg.cause === undefined ? undefined : { cause: optionsArg.cause });
|
|
4
|
+
this.code = code;
|
|
5
|
+
this.name = 'SystemdRuntimeError';
|
|
6
|
+
this.errno = optionsArg.errno ?? null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kcnVudGltZWVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfc3lzdGVtZHJ1bnRpbWUvY2xhc3Nlcy5zeXN0ZW1kcnVudGltZWVycm9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQW9DQSxNQUFNLE9BQU8sbUJBQW9CLFNBQVEsS0FBSztJQUk1QyxZQUNrQixJQUE4QixFQUM5QyxVQUFrQixFQUNsQixVQUFVLEdBQWdDLEVBQUU7UUFFNUMsS0FBSyxDQUNILEdBQUcsVUFBVSxHQUFHLFVBQVUsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsVUFBVSxDQUFDLEtBQUssR0FBRyxFQUFFLEVBQ3RGLFVBQVUsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FDekUsQ0FBQztvQkFQYyxJQUFJO1FBUXBCLElBQUksQ0FBQyxJQUFJLEdBQUcscUJBQXFCLENBQUM7UUFDbEMsSUFBSSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQztJQUN4QyxDQUFDO0NBQ0YifQ==
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './classes.systemdruntimeerror.js';
|
|
2
|
+
export * from './classes.systemdnotifier.js';
|
|
3
|
+
export { type ISystemdListenDescriptor, type ISystemdProcessEnvironmentOptions, setCloseOnExec, systemdListenDescriptorsStart, takeSystemdListenDescriptors, watchdogIntervalUsec, } from './systemdruntime.listen.js';
|
|
4
|
+
export { systemdRuntimeNodeMajor } from './systemdruntime.libc.js';
|
|
5
|
+
export { isSystemdDescriptorName, isSystemdNotifySocketAddress } from './systemdruntime.validation.js';
|