From 711ac1bd2473b0ba7c7a1083382882fdb7f28ad5 Mon Sep 17 00:00:00 2001 From: XenHat Date: Tue, 11 Mar 2025 23:07:38 -0400 Subject: [PATCH 1/3] First draft of Linux game detection fixes Tested against https://github.com/OpenAsar/arrpc/blob/2234e9c9111f4c42ebcc3aa6a2215bfd979eef77/src/process/detectable.json --- src/process/index.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/process/index.js b/src/process/index.js index f445024..ac923d6 100644 --- a/src/process/index.js +++ b/src/process/index.js @@ -11,6 +11,9 @@ const DetectableDB = JSON.parse(fs.readFileSync(join(__dirname, 'detectable.json import * as Natives from './native/index.js'; const Native = Natives[process.platform]; +function basename(str) { + return str.substr(str.lastIndexOf('/') + 1); +} const timestamps = {}, names = {}, pids = {}; export default class ProcessServer { @@ -34,11 +37,12 @@ export default class ProcessServer { // log(`got processed in ${(performance.now() - startTime).toFixed(2)}ms`); - for (const [ pid, _path, args ] of processes) { + for (const [ pid, _path, args, _cwdPath = '' ] of processes) { const path = _path.toLowerCase().replaceAll('\\', '/'); + const cwdPath = _cwdPath.toLowerCase().replaceAll('\\', '/'); const toCompare = []; const splitPath = path.split('/'); - for (let i = 1; i < splitPath.length; i++) { + for (let i = 1; i < splitPath.length || i == 1; i++) { toCompare.push(splitPath.slice(-i).join('/')); } @@ -47,12 +51,27 @@ export default class ProcessServer { toCompare.push(p.replace('.x64', '')); toCompare.push(p.replace('x64', '')); toCompare.push(p.replace('_64', '')); + toCompare.push(p.replace('.exe', '')); } for (const { executables, id, name } of DetectableDB) { if (executables?.some(x => { if (x.is_launcher) return false; - if (x.name[0] === '>' ? x.name.substring(1) !== toCompare[0] : !toCompare.some(y => x.name === y)) return false; + // I can't figure how to not make 'sbin/init' NOT match 'Divinity Original Sin' with a substring match, so this ugly hack have to do for now + for (const comp of toCompare) { + const asdf = comp.includes('.exe') + if (asdf) { + // TODO: Do the reverse; check if x.name contains game/ or /games and THEN check against game/comp and games/comp + const alternative1 = 'game/' + comp + const alternative2 = 'games/' + comp + const ghjk = x.name.includes(alternative1) + const zxc = x.name.includes(alternative2) + if (ghjk || zxc) { + return true + } + } + } + if (x.name[0] === '>' ? x.name.substring(1) !== toCompare[0] : !toCompare.some(y => x.name === y || `${cwdPath}/${y}`.includes(`/${x.name}`))) return false; if (args && x.arguments) return args.join(" ").indexOf(x.arguments) > -1; return true; })) { From dec22a715ab04e2574b9d5e2bace83e79b644866 Mon Sep 17 00:00:00 2001 From: XenHat Date: Tue, 11 Mar 2025 23:09:39 -0400 Subject: [PATCH 2/3] Add substantial performance improvements --- src/process/index.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/process/index.js b/src/process/index.js index ac923d6..b04229d 100644 --- a/src/process/index.js +++ b/src/process/index.js @@ -54,11 +54,23 @@ export default class ProcessServer { toCompare.push(p.replace('.exe', '')); } + // remove duplicates to process + const UniqueToCompare = [] + for (const u of toCompare) { + if (!UniqueToCompare.includes(u)) { + UniqueToCompare.push(u) + } + } + + if (UniqueToCompare.length < 1) { // Skip empty path + continue + } + for (const { executables, id, name } of DetectableDB) { if (executables?.some(x => { if (x.is_launcher) return false; // I can't figure how to not make 'sbin/init' NOT match 'Divinity Original Sin' with a substring match, so this ugly hack have to do for now - for (const comp of toCompare) { + for (const comp of UniqueToCompare) { const asdf = comp.includes('.exe') if (asdf) { // TODO: Do the reverse; check if x.name contains game/ or /games and THEN check against game/comp and games/comp @@ -71,7 +83,7 @@ export default class ProcessServer { } } } - if (x.name[0] === '>' ? x.name.substring(1) !== toCompare[0] : !toCompare.some(y => x.name === y || `${cwdPath}/${y}`.includes(`/${x.name}`))) return false; + if (x.name[0] === '>' ? x.name.substring(1) !== UniqueToCompare[0] : !UniqueToCompare.some(y => x.name === y || `${cwdPath}/${y}`.includes(`/${x.name}`))) return false; if (args && x.arguments) return args.join(" ").indexOf(x.arguments) > -1; return true; })) { From 2c597343280c3928a5d594cee73b0ad298426888 Mon Sep 17 00:00:00 2001 From: XenHat Date: Tue, 11 Mar 2025 23:15:20 -0400 Subject: [PATCH 3/3] add missing changes to linux.js --- src/process/native/linux.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/process/native/linux.js b/src/process/native/linux.js index ed45681..0dc7f4d 100644 --- a/src/process/native/linux.js +++ b/src/process/native/linux.js @@ -1,8 +1,14 @@ -import { readdir, readFile } from "fs/promises"; +import { readdir, readFile, readlink } from "fs/promises"; export const getProcesses = async () => (await Promise.all( (await readdir("/proc")).map(pid => (+pid > 0) && readFile(`/proc/${pid}/cmdline`, 'utf8') - .then(path => [+pid, path.split("\0")[0], path.split("\0").slice(1)], () => 0) + .then(async path => { + let cwdPath; + try { + cwdPath = await readlink(`/proc/${pid}/cwd`); + } catch (err) {}; + return [+pid, path.split("\0")[0], path.split("\0").slice(1), cwdPath] + }, () => 0) ) )).filter(x => x); \ No newline at end of file