Used for scheduling and check-in/check-out of patients to a facility under designated times.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
3.1 KiB

const { spawn } = require('child_process');
const whitespace = /\s+/;
const validFields = new Set([
'group', 'ppid', 'user', 'args', 'comm', 'rgroup', 'nice', 'pid', 'pgid', 'etime',
'ruser', 'time', 'tty', 'vsz'
]);
const lookup = async ({ pid, ppid, user, group, command, all, fields = ['pid', 'ppid', 'comm'] }) => {
if (! fields.every((field) => validFields.has(field))) {
throw new Error('ps - invalid field provided');
}
if (ppid && fields.indexOf('ppid') < 0) {
fields.push('ppid');
}
const fieldOptions = fields.reduce(reduceFieldsToOptions, [ ]);
if (pid || pid === 0) {
const output = await ps([ '-p', processPids(pid), ...fieldOptions ]);
return parseGrid(output);
}
if (ppid || ppid === 0) {
const pids = processPids(ppid);
const ppidSet = new Set(String(pids).split(','));
const output = await ps([ '-p', pids, ...fieldOptions ]);
const processes = parseGrid(output);
return processes.filter((proc) => {
return ppidSet.has(proc.ppid);
});
}
if (all) {
const output = await ps([ '-e', ...fieldOptions ]);
return parseGrid(output);
}
if (user) {
const output = await ps([ '-u', user, ...fieldOptions ]);
return parseGrid(output);
}
if (group) {
const output = await ps([ '-g', group, ...fieldOptions ]);
return parseGrid(output);
}
if (command) {
const output = await ps([ '-C', command, ...fieldOptions ]);
return parseGrid(output);
}
throw new Error('ps - must provide a search query; one of "pid", "ppid", "all", "user", "group", "command"');
};
// Export
module.exports = lookup;
lookup.lookup = lookup;
class Process {
constructor(fields) {
Object.assign(this, fields);
Object.freeze(this);
}
}
// Turns ['comm', 'pid'] into ['-o', 'comm', '-o', 'pid']
const reduceFieldsToOptions = (options, field) => {
options.push('-o', field);
return options;
};
const ps = (args, callback) => {
return new Promise((resolve, reject) => {
const child = spawn('ps', args);
let stdout = '';
let stderr = '';
child.on('error', (error) => {
reject(error);
});
child.stdout.on('data', (data) => stdout += data);
child.stderr.on('data', (data) => stderr += data);
child.on('close', (code) => {
stderr = stderr.trim();
if (stderr) {
return reject(new Error(stderr));
}
resolve(stdout.trim());
});
});
};
const isValidPid = (pid) => {
const int = parseInt(pid, 10);
return ! isNaN(int) && String(int) === String(pid);
};
const processPids = (pid) => {
if (Array.isArray(pid)) {
if (! pid.every(isValidPid)) {
throw new Error('ps - pid must be a valid integer value');
}
return pid.join(',');
}
if (! isValidPid(pid)) {
throw new Error('ps - pid must be a valid integer value');
}
return pid;
}
// Parses the resulting output from ps into `Process` objects
const parseGrid = (output) => {
if (! output) {
return [ ];
}
const lines = output.split('\n');
const header = lines.shift()
.trim()
.split(whitespace)
.map((col) => col.toLowerCase());
return lines.map((line) => {
const proc = { };
line.trim().split(whitespace).forEach((item, index) => {
if (item) {
proc[header[index]] = item;
}
});
return new Process(proc);
});
};