@depup/systeminformation 5.33.6-depup.0 → 5.33.10-depup.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/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/systeminformation
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [systeminformation](https://www.npmjs.com/package/systeminformation) @ 5.33.6 |
17
- | Processed | 2026-08-30 |
16
+ | Original | [systeminformation](https://www.npmjs.com/package/systeminformation) @ 5.33.10 |
17
+ | Processed | 2026-09-13 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 0 |
20
20
 
package/changes.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "bumped": {},
3
- "timestamp": "2026-08-30T00:59:35.001Z",
3
+ "timestamp": "2026-09-13T01:00:18.134Z",
4
4
  "totalUpdated": 0
5
5
  }
package/lib/audio.js CHANGED
@@ -55,7 +55,7 @@ function parseAudioType(str, input, output) {
55
55
  if (str.indexOf('mikr') >= 0) {
56
56
  result = 'Microphone';
57
57
  }
58
- if (str.indexOf('phone') >= 0) {
58
+ if (str.indexOf('phone') >= 0 && str.indexOf('headphone') < 0) {
59
59
  result = 'Phone';
60
60
  }
61
61
  if (str.indexOf('controll') >= 0) {
@@ -111,11 +111,16 @@ function parseLinuxAudioAlsa(stdout) {
111
111
  const lines = cards.split('\n');
112
112
  lines.forEach((line, i) => {
113
113
  // ' 1 [Device ]: USB-Audio - USB Audio Device'
114
- const card = line.match(/^\s*(\d+)\s+\[(.+?)\s*\]:\s*(\S+)\s+-\s+(.*)$/);
115
- if (card) {
114
+ const card = line.match(/^\s*(\d+)\s+\[(.+?)\s*\]:\s*(.*)$/);
115
+ if (card && card[3].trim()) {
116
116
  const index = card[1];
117
- const driver = card[3];
118
- const name = card[4].trim();
117
+ // some drivers (e.g. bcm2835) print an unterminated driver string, gluing the name to it
118
+ const sep = card[3].lastIndexOf(' - ');
119
+ const name = (sep >= 0 ? card[3].substring(sep + 3) : card[3]).trim();
120
+ let driver = (sep >= 0 ? card[3].substring(0, sep) : '').trim();
121
+ if (name && driver.endsWith(name)) {
122
+ driver = driver.substring(0, driver.length - name.length).trim();
123
+ }
119
124
  // second line holds the long name, which is prefixed with the manufacturer on USB devices
120
125
  const longName = (lines[i + 1] || '').trim();
121
126
  const manufacturer = longName.indexOf(name) > 0 ? longName.substring(0, longName.indexOf(name)).trim() : '';
package/lib/filesystem.js CHANGED
@@ -43,8 +43,20 @@ function fsSize(drive, callback) {
43
43
  }
44
44
 
45
45
  let macOsDisks = [];
46
+ const macOsFsTypes = new Map();
46
47
  let osMounts = [];
47
48
 
49
+ // macOS df has no type column, so the type used to be guessed from diskutil - which only ever
50
+ // produced APFS, HFS or NFS and therefore never recognised zfs, exfat, msdos or smbfs. mount
51
+ // knows the real type, so prefer it and keep the old names for the three it could produce.
52
+ function macOsFsType(fs) {
53
+ const type = macOsFsTypes.get(fs);
54
+ if (!type) {
55
+ return getmacOsFsType(fs);
56
+ }
57
+ return type === 'apfs' ? 'APFS' : type === 'hfs' ? 'HFS' : type === 'nfs' ? 'NFS' : type;
58
+ }
59
+
48
60
  function getmacOsFsType(fs) {
49
61
  if (!fs.startsWith('/')) {
50
62
  return 'NFS';
@@ -86,6 +98,59 @@ function fsSize(drive, callback) {
86
98
  return lines;
87
99
  }
88
100
 
101
+ // ZFS datasets share the pool, so df only reports what a dataset references itself - a parent
102
+ // holding its data in child datasets looks empty (#1017). Only `zfs list` knows the
103
+ // hierarchical usage, so query it once when a zfs mount is present.
104
+ function applyZfsUsage(data, cb) {
105
+ if (!data.some((item) => item.type === 'zfs')) {
106
+ return cb(data);
107
+ }
108
+ exec('zfs list -H -p -o name,used,avail,mountpoint', { ...util.execOptsLinux, timeout: 5000 }, (error, stdout) => {
109
+ if (error) {
110
+ // a truncated or timed out listing would correct only part of the datasets and leave the
111
+ // rest on their df values - correct none instead, so the result stays consistent
112
+ return cb(data);
113
+ }
114
+ const byMount = Object.create(null);
115
+ const byName = Object.create(null);
116
+ (stdout || '')
117
+ .toString()
118
+ .split('\n')
119
+ .forEach((line) => {
120
+ const parts = line.split('\t');
121
+ if (parts.length < 4) {
122
+ return;
123
+ }
124
+ const entry = { used: parseInt(parts[1], 10), available: parseInt(parts[2], 10) };
125
+ if (isNaN(entry.used) || isNaN(entry.available)) {
126
+ return;
127
+ }
128
+ byName[parts[0]] = entry;
129
+ const mount = parts[3].trim();
130
+ // several datasets can carry the same mountpoint (root-on-zfs boot environments all
131
+ // declare "/"), so the mount index is only a fallback - keep the first one
132
+ if (mount.startsWith('/') && !byMount[mount]) {
133
+ byMount[mount] = entry;
134
+ }
135
+ });
136
+ data.forEach((item) => {
137
+ if (item.type !== 'zfs') {
138
+ return;
139
+ }
140
+ // the fs column is the exact dataset name and therefore unambiguous, unlike the mountpoint
141
+ const dataset = byName[item.fs] || byMount[item.mount];
142
+ if (!dataset || !(dataset.used + dataset.available)) {
143
+ return;
144
+ }
145
+ item.used = dataset.used;
146
+ item.available = dataset.available;
147
+ item.size = dataset.used + dataset.available;
148
+ item.use = parseFloat(((100.0 * dataset.used) / item.size).toFixed(2));
149
+ });
150
+ cb(data);
151
+ });
152
+ }
153
+
89
154
  function parseDf(lines) {
90
155
  const data = [];
91
156
  // filesystem (first column) and mount point (last column) may contain spaces:
@@ -98,7 +163,7 @@ function fsSize(drive, callback) {
98
163
  const parts = line.trim().match(hasType ? dfWithType : dfNoType);
99
164
  if (parts && (parts[1].startsWith('/') || parts[hasType ? 6 : 5] === '/' || parts[1].indexOf('/') > 0 || parts[1].indexOf(':') === 1 || (!_darwin && !isLinuxTmpFs(parts[2])))) {
100
165
  const fs = parts[1];
101
- const fsType = hasType ? parts[2] : getmacOsFsType(parts[1]);
166
+ const fsType = hasType ? parts[2] : macOsFsType(parts[1]);
102
167
  const size = parseInt(parts[hasType ? 3 : 2], 10) * 1024;
103
168
  const used = parseInt(parts[hasType ? 4 : 3], 10) * 1024;
104
169
  const available = parseInt(parts[hasType ? 5 : 4], 10) * 1024;
@@ -142,11 +207,16 @@ function fsSize(drive, callback) {
142
207
  execSync('mount')
143
208
  .toString()
144
209
  .split('\n')
145
- .filter((line) => {
146
- return line.startsWith('/');
147
- })
148
210
  .forEach((line) => {
149
- osMounts[line.split(' ')[0]] = line.toLowerCase().indexOf('read-only') === -1;
211
+ // mount output: "<fs> on <mountpoint> (<type>, <options>)"
212
+ const fs = line.split(' ')[0];
213
+ const type = line.match(/\(([^),]+)[^)]*\)$/);
214
+ if (fs && type) {
215
+ macOsFsTypes.set(fs, type[1].trim().toLowerCase());
216
+ }
217
+ if (line.startsWith('/')) {
218
+ osMounts[fs] = line.toLowerCase().indexOf('read-only') === -1;
219
+ }
150
220
  });
151
221
  } catch {
152
222
  util.noop();
@@ -195,19 +265,23 @@ function fsSize(drive, callback) {
195
265
  });
196
266
  }
197
267
  if ((!error || data.length) && stdout.toString().trim() !== '') {
198
- if (callback) {
199
- callback(data);
200
- }
201
- resolve(data);
268
+ applyZfsUsage(data, (data) => {
269
+ if (callback) {
270
+ callback(data);
271
+ }
272
+ resolve(data);
273
+ });
202
274
  } else {
203
275
  exec('df -kPT 2>/dev/null', { maxBuffer: 1024 * 1024 }, (error, stdout) => {
204
276
  // fixed issue alpine fallback
205
277
  const lines = filterLines(stdout);
206
278
  data = parseDf(lines);
207
- if (callback) {
208
- callback(data);
209
- }
210
- resolve(data);
279
+ applyZfsUsage(data, (data) => {
280
+ if (callback) {
281
+ callback(data);
282
+ }
283
+ resolve(data);
284
+ });
211
285
  });
212
286
  }
213
287
  });
@@ -1722,6 +1796,10 @@ function diskLayout(callback) {
1722
1796
  const smartDev = JSON.parse(execSync('smartctl --scan -j').toString());
1723
1797
  if (smartDev && smartDev.devices && smartDev.devices.length > 0) {
1724
1798
  smartDev.devices.forEach((dev) => {
1799
+ // device names come from smartctl output - never let anything but a plain path reach the shell
1800
+ if (!/^[\w/.,:\\-]+$/.test(String(dev.name || ''))) {
1801
+ return;
1802
+ }
1725
1803
  workload.push(execPromiseSave(`smartctl -j -a ${dev.name}`, util.execOptsWin));
1726
1804
  });
1727
1805
  }
package/lib/graphics.js CHANGED
@@ -17,6 +17,7 @@ const fs = require('fs');
17
17
  const path = require('path');
18
18
  const exec = require('child_process').exec;
19
19
  const execSync = require('child_process').execSync;
20
+ const execFileSync = require('child_process').execFileSync;
20
21
  const util = require('./util');
21
22
 
22
23
  const _platform = process.platform;
@@ -481,14 +482,9 @@ function graphics(callback) {
481
482
  if (nvidiaSmiExe) {
482
483
  const nvidiaSmiOpts =
483
484
  '--query-gpu=driver_version,pci.sub_device_id,name,pci.bus_id,fan.speed,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu,temperature.memory,power.draw,power.limit,clocks.gr,clocks.mem --format=csv,noheader,nounits';
484
- const cmd = `"${nvidiaSmiExe}" ${nvidiaSmiOpts}`;
485
- if (_linux) {
486
- options.stdio = ['pipe', 'pipe', 'ignore'];
487
- }
485
+ options.stdio = ['pipe', 'pipe', 'ignore'];
488
486
  try {
489
- const sanitized = cmd + (_linux ? ' 2>/dev/null' : '') + (_windows ? ' 2> nul' : '');
490
- const res = execSync(sanitized, options).toString();
491
- return res;
487
+ return execFileSync(nvidiaSmiExe, nvidiaSmiOpts.split(' '), options).toString();
492
488
  } catch {
493
489
  util.noop();
494
490
  }
package/lib/internet.js CHANGED
@@ -166,6 +166,12 @@ function inetLatency(host, callback) {
166
166
  }
167
167
  return resolve(null);
168
168
  }
169
+ if (hostSanitized.startsWith('-')) {
170
+ if (callback) {
171
+ callback(null);
172
+ }
173
+ return resolve(null);
174
+ }
169
175
  let params;
170
176
  if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
171
177
  if (_linux) {
package/lib/network.js CHANGED
@@ -368,8 +368,8 @@ function getWindowsWiredProfilesInformation() {
368
368
 
369
369
  function getWindowsWirelessIfaceSSID(interfaceName) {
370
370
  try {
371
- const result = execSync(`netsh wlan show interface name="${interfaceName}" | findstr "SSID"`, util.execOptsWin);
372
- const SSID = result.split('\r\n').shift();
371
+ const result = execFileSync('netsh', ['wlan', 'show', 'interface', `name=${util.sanitizeString(interfaceName)}`], util.execOptsWin).toString();
372
+ const SSID = result.split('\r\n').find((l) => l.includes('SSID')) || '';
373
373
  const parseSSID = SSID.split(':').pop().trim();
374
374
  return parseSSID;
375
375
  } catch {
@@ -420,7 +420,7 @@ function getWindowsIEEE8021x(connectionType, iface, ifaces) {
420
420
  const SSID = getWindowsWirelessIfaceSSID(iface);
421
421
  if (SSID !== 'Unknown') {
422
422
  const ifaceSanitized = util.sanitizeString(SSID);
423
- const profiles = execSync(`netsh wlan show profiles "${ifaceSanitized}"`, util.execOptsWin).split('\r\n');
423
+ const profiles = execFileSync('netsh', ['wlan', 'show', 'profiles', ifaceSanitized], util.execOptsWin).toString().split('\r\n');
424
424
  i8021xState = (profiles.find((l) => l.indexOf('802.1X') >= 0) || '').trim();
425
425
  i8021xProtocol = (profiles.find((l) => l.indexOf('EAP') >= 0) || '').trim();
426
426
  }
@@ -943,7 +943,7 @@ function networkInterfaces(callback, rescan, defaultString) {
943
943
  ip6subnet = ip6linksubnet;
944
944
  }
945
945
  const iface = dev.split(':')[0].trim();
946
- const ifaceSanitized = util.sanitizeString(iface);
946
+ const ifaceSanitized = util.sanitizeString(iface, true);
947
947
  const cmd = `echo -n "addr_assign_type: "; cat /sys/class/net/${ifaceSanitized}/addr_assign_type 2>/dev/null; echo;
948
948
  echo -n "address: "; cat /sys/class/net/${ifaceSanitized}/address 2>/dev/null; echo;
949
949
  echo -n "addr_len: "; cat /sys/class/net/${ifaceSanitized}/addr_len 2>/dev/null; echo;
package/lib/osinfo.js CHANGED
@@ -18,7 +18,6 @@ const fs = require('fs');
18
18
  const util = require('./util');
19
19
  const exec = require('child_process').exec;
20
20
  const execSync = require('child_process').execSync;
21
- const execFile = require('child_process').execFile;
22
21
 
23
22
  const _platform = process.platform;
24
23
 
@@ -775,78 +774,47 @@ function versions(apps, callback) {
775
774
  });
776
775
  }
777
776
  if ({}.hasOwnProperty.call(appsObj.versions, 'postgresql')) {
778
- if (_linux) {
779
- exec('locate bin/postgres', (error, stdout) => {
780
- if (!error) {
781
- const safePath = /^[a-zA-Z0-9/_.-]+$/;
782
- const postgresqlBin = stdout
783
- .toString()
784
- .split('\n')
785
- .filter((p) => safePath.test(p.trim()))
786
- .sort();
787
- if (postgresqlBin.length) {
788
- execFile(postgresqlBin[postgresqlBin.length - 1], ['-V'], (error, stdout) => {
789
- if (!error) {
790
- const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
791
- appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
777
+ if (_windows) {
778
+ util.powerShell('Get-CimInstance Win32_Service | select caption | fl').then((stdout) => {
779
+ let serviceSections = stdout.split(/\n\s*\n/);
780
+ serviceSections.forEach((item) => {
781
+ if (item.trim() !== '') {
782
+ let lines = item.trim().split('\r\n');
783
+ let srvCaption = util.getValue(lines, 'caption', ':', true).toLowerCase();
784
+ if (srvCaption.indexOf('postgresql') > -1) {
785
+ const parts = srvCaption.split(' server ');
786
+ if (parts.length > 1) {
787
+ appsObj.versions.postgresql = parts[1];
792
788
  }
793
- functionProcessed();
794
- });
795
- } else {
796
- functionProcessed();
797
- }
798
- } else {
799
- exec('psql -V', (error, stdout) => {
800
- if (!error) {
801
- const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
802
- appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
803
- appsObj.versions.postgresql = appsObj.versions.postgresql.split('-')[0];
804
789
  }
805
- functionProcessed();
806
- });
807
- }
790
+ }
791
+ });
792
+ functionProcessed();
808
793
  });
809
794
  } else {
810
- if (_windows) {
811
- util.powerShell('Get-CimInstance Win32_Service | select caption | fl').then((stdout) => {
812
- let serviceSections = stdout.split(/\n\s*\n/);
813
- serviceSections.forEach((item) => {
814
- if (item.trim() !== '') {
815
- let lines = item.trim().split('\r\n');
816
- let srvCaption = util.getValue(lines, 'caption', ':', true).toLowerCase();
817
- if (srvCaption.indexOf('postgresql') > -1) {
818
- const parts = srvCaption.split(' server ');
819
- if (parts.length > 1) {
820
- appsObj.versions.postgresql = parts[1];
821
- }
822
- }
823
- }
824
- });
825
- functionProcessed();
826
- });
827
- } else {
828
- exec('postgres -V', (error, stdout) => {
829
- if (!error) {
830
- const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
831
- appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
832
- if (appsObj.versions.postgresql.includes('(') && postgresql.length >= 2 && !postgresql[postgresql.length - 2].includes('(')) {
833
- appsObj.versions.postgresql = postgresql[postgresql.length - 2];
834
- }
795
+ const parsePostgres = (stdout) => {
796
+ const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
797
+ let version = postgresql.length ? postgresql[postgresql.length - 1] : '';
798
+ if (version.includes('(') && postgresql.length >= 2 && !postgresql[postgresql.length - 2].includes('(')) {
799
+ version = postgresql[postgresql.length - 2];
800
+ }
801
+ return version.split('-')[0];
802
+ };
803
+ // no `locate`: its output is any user-writable path and must not be executed
804
+ const tryPostgres = (cmds) => {
805
+ if (!cmds.length) {
806
+ return functionProcessed();
807
+ }
808
+ exec(cmds[0], (error, stdout) => {
809
+ if (!error && stdout.toString().trim()) {
810
+ appsObj.versions.postgresql = parsePostgres(stdout);
835
811
  functionProcessed();
836
812
  } else {
837
- exec('pg_config --version', (error, stdout) => {
838
- if (!error) {
839
- const postgresql = stdout.toString().split('\n')[0].split(' ') || [];
840
- appsObj.versions.postgresql = postgresql.length ? postgresql[postgresql.length - 1] : '';
841
- if (appsObj.versions.postgresql.includes('(') && postgresql.length >= 2 && !postgresql[postgresql.length - 2].includes('(')) {
842
- appsObj.versions.postgresql = postgresql[postgresql.length - 2];
843
- }
844
- }
845
- functionProcessed();
846
- });
813
+ tryPostgres(cmds.slice(1));
847
814
  }
848
815
  });
849
- }
816
+ };
817
+ tryPostgres(['postgres -V', 'pg_config --version', 'psql -V']);
850
818
  }
851
819
  }
852
820
  if ({}.hasOwnProperty.call(appsObj.versions, 'perl')) {
package/lib/processes.js CHANGED
@@ -261,12 +261,20 @@ function services(srv, callback) {
261
261
  });
262
262
  if (_linux) {
263
263
  // calc process_cpu - ps is not accurate in linux!
264
+ // ps pcpu is a lifetime average, the /proc values below are an interval share -
265
+ // drop the ps seed instead of adding both (#1007)
266
+ result.forEach((item) => {
267
+ item.cpu = 0;
268
+ });
264
269
  let cmd = 'cat /proc/stat | grep "cpu "';
265
270
  for (let i in result) {
266
271
  for (let j in result[i].pids) {
267
272
  cmd += ';cat /proc/' + result[i].pids[j] + '/stat';
268
273
  }
269
274
  }
275
+ // freeze the baseline before the async call - a concurrent call overwrites _services_cpu
276
+ // and would leave this one dividing by a few jiffies (#1007)
277
+ const cpuBaseline = Object.assign({}, _services_cpu);
270
278
  exec(cmd, { maxBuffer: 1024 * 102400 }, function (error, stdout) {
271
279
  let curr_processes = stdout.toString().split('\n');
272
280
 
@@ -277,7 +285,7 @@ function services(srv, callback) {
277
285
  let list_new = {};
278
286
  let resultProcess = {};
279
287
  curr_processes.forEach((element) => {
280
- resultProcess = calcProcStatLinux(element, all, _services_cpu);
288
+ resultProcess = calcProcStatLinux(element, all, cpuBaseline);
281
289
 
282
290
  if (resultProcess.pid) {
283
291
  let listPos = -1;
@@ -297,9 +305,7 @@ function services(srv, callback) {
297
305
  cpuu: resultProcess.cpuu,
298
306
  cpus: resultProcess.cpus,
299
307
  utime: resultProcess.utime,
300
- stime: resultProcess.stime,
301
- cutime: resultProcess.cutime,
302
- cstime: resultProcess.cstime
308
+ stime: resultProcess.stime
303
309
  };
304
310
  }
305
311
  });
@@ -474,6 +480,19 @@ function parseProcStat(line) {
474
480
  return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
475
481
  }
476
482
 
483
+ // drops NaN/Infinity/negative values and scales cpuu + cpus down proportionally
484
+ // if their sum exceeds 100 (normalized against all cores)
485
+ function clampCpuPair(cpuu, cpus) {
486
+ if (!isFinite(cpuu) || cpuu < 0) { cpuu = 0; }
487
+ if (!isFinite(cpus) || cpus < 0) { cpus = 0; }
488
+ const total = cpuu + cpus;
489
+ if (total > 100) {
490
+ cpuu = (cpuu / total) * 100;
491
+ cpus = (cpus / total) * 100;
492
+ }
493
+ return { cpuu: cpuu, cpus: cpus };
494
+ }
495
+
477
496
  function calcProcStatLinux(line, all, _cpu_old) {
478
497
  let statparts = line.replace(/ +/g, ' ').split(')');
479
498
  if (statparts.length >= 2) {
@@ -482,35 +501,34 @@ function calcProcStatLinux(line, all, _cpu_old) {
482
501
  let pid = parseInt(statparts[0].split(' ')[0]);
483
502
  let utime = parseInt(parts[12]);
484
503
  let stime = parseInt(parts[13]);
485
- let cutime = parseInt(parts[14]);
486
- let cstime = parseInt(parts[15]);
487
504
 
488
- // calc
505
+ // calc - child times (cutime/cstime) are deliberately left out: reaping a child adds its
506
+ // whole lifetime in one interval, which is what produced the >100% spikes in #1007.
507
+ // top, htop and Task Manager exclude them too.
489
508
  let cpuu = 0;
490
509
  let cpus = 0;
491
510
  if (_cpu_old.all > 0 && _cpu_old.list[pid]) {
492
- cpuu = ((utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all)) * 100; // user
493
- cpus = ((stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.all)) * 100; // system
511
+ const delta = all - _cpu_old.all;
512
+ cpuu = delta > 0 ? ((utime - _cpu_old.list[pid].utime) / delta) * 100 : 0; // user
513
+ cpus = delta > 0 ? ((stime - _cpu_old.list[pid].stime) / delta) * 100 : 0; // system
494
514
  } else {
495
- cpuu = ((utime + cutime) / all) * 100; // user
496
- cpus = ((stime + cstime) / all) * 100; // system
515
+ cpuu = all > 0 ? (utime / all) * 100 : 0; // user
516
+ cpus = all > 0 ? (stime / all) * 100 : 0; // system
497
517
  }
518
+ // normalized against all cores, so 100 is the ceiling for cpuu + cpus
519
+ const clamped = clampCpuPair(cpuu, cpus);
498
520
  return {
499
521
  pid: pid,
500
522
  utime: utime,
501
523
  stime: stime,
502
- cutime: cutime,
503
- cstime: cstime,
504
- cpuu: cpuu,
505
- cpus: cpus
524
+ cpuu: clamped.cpuu,
525
+ cpus: clamped.cpus
506
526
  };
507
527
  } else {
508
528
  return {
509
529
  pid: 0,
510
530
  utime: 0,
511
531
  stime: 0,
512
- cutime: 0,
513
- cstime: 0,
514
532
  cpuu: 0,
515
533
  cpus: 0
516
534
  };
@@ -520,8 +538,6 @@ function calcProcStatLinux(line, all, _cpu_old) {
520
538
  pid: 0,
521
539
  utime: 0,
522
540
  stime: 0,
523
- cutime: 0,
524
- cstime: 0,
525
541
  cpuu: 0,
526
542
  cpus: 0
527
543
  };
@@ -533,18 +549,21 @@ function calcProcStatWin(procStat, all, _cpu_old) {
533
549
  let cpuu = 0;
534
550
  let cpus = 0;
535
551
  if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) {
536
- cpuu = ((procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all)) * 100; // user
537
- cpus = ((procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all)) * 100; // system
552
+ const delta = all - _cpu_old.all;
553
+ cpuu = delta > 0 ? ((procStat.utime - _cpu_old.list[procStat.pid].utime) / delta) * 100 : 0; // user
554
+ cpus = delta > 0 ? ((procStat.stime - _cpu_old.list[procStat.pid].stime) / delta) * 100 : 0; // system
538
555
  } else {
539
- cpuu = (procStat.utime / all) * 100; // user
540
- cpus = (procStat.stime / all) * 100; // system
556
+ cpuu = all > 0 ? (procStat.utime / all) * 100 : 0; // user
557
+ cpus = all > 0 ? (procStat.stime / all) * 100 : 0; // system
541
558
  }
559
+ // same ceiling as the linux path - cpuu + cpus stays inside [0, 100] (#1007)
560
+ const clamped = clampCpuPair(cpuu, cpus);
542
561
  return {
543
562
  pid: procStat.pid,
544
563
  utime: procStat.utime,
545
564
  stime: procStat.stime,
546
- cpuu: cpuu > 0 ? cpuu : 0,
547
- cpus: cpus > 0 ? cpus : 0
565
+ cpuu: clamped.cpuu,
566
+ cpus: clamped.cpus
548
567
  };
549
568
  }
550
569
 
@@ -637,6 +656,11 @@ function processes(callback) {
637
656
  let command = '';
638
657
  let params = '';
639
658
  let fullcommand = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim();
659
+ // zombies are printed as "[name] <defunct>" - drop the marker so the bracket handling below
660
+ // sees a plain "[name]" and does not leak "] <defunct>" into command and name
661
+ if (fullcommand.endsWith(' <defunct>')) {
662
+ fullcommand = fullcommand.slice(0, -10).trim();
663
+ }
640
664
  if (fullcommand.substr(fullcommand.length - 1) === ']') {
641
665
  fullcommand = fullcommand.slice(0, -1);
642
666
  }
@@ -855,6 +879,9 @@ function processes(callback) {
855
879
  result.list.forEach((element) => {
856
880
  cmd += ';cat /proc/' + element.pid + '/stat';
857
881
  });
882
+ // freeze the baseline before the async call - a concurrent call overwrites _processes_cpu
883
+ // and would leave this one dividing by a few jiffies (#1007)
884
+ const cpuBaseline = Object.assign({}, _processes_cpu);
858
885
  exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
859
886
  let curr_processes = stdout.toString().split('\n');
860
887
 
@@ -865,7 +892,7 @@ function processes(callback) {
865
892
  let list_new = {};
866
893
  let resultProcess = {};
867
894
  curr_processes.forEach((element) => {
868
- resultProcess = calcProcStatLinux(element, all, _processes_cpu);
895
+ resultProcess = calcProcStatLinux(element, all, cpuBaseline);
869
896
 
870
897
  if (resultProcess.pid) {
871
898
  // store pcpu in outer array
@@ -885,9 +912,7 @@ function processes(callback) {
885
912
  cpuu: resultProcess.cpuu,
886
913
  cpus: resultProcess.cpus,
887
914
  utime: resultProcess.utime,
888
- stime: resultProcess.stime,
889
- cutime: resultProcess.cutime,
890
- cstime: resultProcess.cstime
915
+ stime: resultProcess.stime
891
916
  };
892
917
  }
893
918
  });
@@ -950,6 +975,9 @@ function processes(callback) {
950
975
  }
951
976
  } else if (_windows) {
952
977
  try {
978
+ // freeze the baseline before the async call - a concurrent call overwrites _processes_cpu
979
+ // and would leave this one with a non positive delta (#1007)
980
+ const cpuBaseline = Object.assign({}, _processes_cpu);
953
981
  util
954
982
  .powerShell(
955
983
  `Get-CimInstance Win32_Process | select-Object ProcessId,ParentProcessId,ExecutionState,Caption,CommandLine,ExecutablePath,UserModeTime,KernelModeTime,WorkingSetSize,Priority,PageFileUsage,
@@ -960,8 +988,10 @@ function processes(callback) {
960
988
  const procs = [];
961
989
  const procStats = [];
962
990
  const list_new = {};
963
- let allcpuu = 0;
964
- let allcpus = 0;
991
+ // accumulate from the previous totals and add deltas only - a process that exited
992
+ // must not lower the total, otherwise the denominator turns negative (#559)
993
+ let allcpuu = cpuBaseline.all_utime;
994
+ let allcpus = cpuBaseline.all_stime;
965
995
  let processArray = [];
966
996
  try {
967
997
  stdout = stdout.trim().replace(/^\uFEFF/, '');
@@ -981,8 +1011,9 @@ function processes(callback) {
981
1011
  const utime = element.UserModeTime;
982
1012
  const stime = element.KernelModeTime;
983
1013
  const memw = element.WorkingSetSize;
984
- allcpuu = allcpuu + utime;
985
- allcpus = allcpus + stime;
1014
+ const cpuOld = cpuBaseline.list[pid];
1015
+ allcpuu += utime - (cpuOld ? cpuOld.utime : 0);
1016
+ allcpus += stime - (cpuOld ? cpuOld.stime : 0);
986
1017
  result.all++;
987
1018
  if (!statusValue) {
988
1019
  result.unknown++;
@@ -1027,7 +1058,7 @@ function processes(callback) {
1027
1058
  result.sleeping = result.all - result.running - result.blocked - result.unknown;
1028
1059
  result.list = procs;
1029
1060
  procStats.forEach((element) => {
1030
- let resultProcess = calcProcStatWin(element, allcpuu + allcpus, _processes_cpu);
1061
+ let resultProcess = calcProcStatWin(element, allcpuu + allcpus, cpuBaseline);
1031
1062
 
1032
1063
  // store pcpu in outer array
1033
1064
  let listPos = result.list.map((e) => e.pid).indexOf(resultProcess.pid);
@@ -1150,12 +1181,16 @@ function processLoad(proc, callback) {
1150
1181
  if (procSanitized && processes.length && processes[0] !== '------') {
1151
1182
  if (_windows) {
1152
1183
  try {
1184
+ // freeze the baseline before the async call - a concurrent call overwrites _process_cpu
1185
+ // and would leave this one with a non positive delta (#1007)
1186
+ const cpuBaseline = Object.assign({}, _process_cpu);
1153
1187
  util.powerShell('Get-CimInstance Win32_Process | select ProcessId,Caption,UserModeTime,KernelModeTime,WorkingSetSize | ConvertTo-Json -compress').then((stdout, error) => {
1154
1188
  if (!error) {
1155
1189
  const procStats = [];
1156
1190
  const list_new = {};
1157
- let allcpuu = 0;
1158
- let allcpus = 0;
1191
+ // see processes() - never lower the total when a process exits (#559)
1192
+ let allcpuu = cpuBaseline.all_utime;
1193
+ let allcpus = cpuBaseline.all_stime;
1159
1194
  let processArray = [];
1160
1195
  try {
1161
1196
  stdout = stdout.trim().replace(/^\uFEFF/, '');
@@ -1172,8 +1207,9 @@ function processLoad(proc, callback) {
1172
1207
  const utime = element.UserModeTime;
1173
1208
  const stime = element.KernelModeTime;
1174
1209
  const mem = element.WorkingSetSize;
1175
- allcpuu = allcpuu + utime;
1176
- allcpus = allcpus + stime;
1210
+ const cpuOld = cpuBaseline.list[pid];
1211
+ allcpuu += utime - (cpuOld ? cpuOld.utime : 0);
1212
+ allcpus += stime - (cpuOld ? cpuOld.stime : 0);
1177
1213
 
1178
1214
  procStats.push({
1179
1215
  pid: pid,
@@ -1231,7 +1267,7 @@ function processLoad(proc, callback) {
1231
1267
 
1232
1268
  // calculate proc stats for each proc
1233
1269
  procStats.forEach((element) => {
1234
- let resultProcess = calcProcStatWin(element, allcpuu + allcpus, _process_cpu);
1270
+ let resultProcess = calcProcStatWin(element, allcpuu + allcpus, cpuBaseline);
1235
1271
 
1236
1272
  let listPos = -1;
1237
1273
  for (let j = 0; j < result.length; j++) {
@@ -1377,6 +1413,9 @@ function processLoad(proc, callback) {
1377
1413
  cmd += ';cat /proc/' + result[i].pids[j] + '/stat';
1378
1414
  }
1379
1415
  }
1416
+ // freeze the baseline before the async call - a concurrent call overwrites _process_cpu
1417
+ // and would leave this one dividing by a few jiffies (#1007)
1418
+ const cpuBaseline = Object.assign({}, _process_cpu);
1380
1419
  exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
1381
1420
  let curr_processes = stdout.toString().split('\n');
1382
1421
 
@@ -1387,7 +1426,7 @@ function processLoad(proc, callback) {
1387
1426
  let list_new = {};
1388
1427
  let resultProcess = {};
1389
1428
  curr_processes.forEach((element) => {
1390
- resultProcess = calcProcStatLinux(element, all, _process_cpu);
1429
+ resultProcess = calcProcStatLinux(element, all, cpuBaseline);
1391
1430
 
1392
1431
  if (resultProcess.pid) {
1393
1432
  // find result item
@@ -1407,9 +1446,7 @@ function processLoad(proc, callback) {
1407
1446
  cpuu: resultProcess.cpuu,
1408
1447
  cpus: resultProcess.cpus,
1409
1448
  utime: resultProcess.utime,
1410
- stime: resultProcess.stime,
1411
- cutime: resultProcess.cutime,
1412
- cstime: resultProcess.cstime
1449
+ stime: resultProcess.stime
1413
1450
  };
1414
1451
  }
1415
1452
  });
package/lib/wifi.js CHANGED
@@ -193,7 +193,7 @@ function ifaceListLinux() {
193
193
  }
194
194
 
195
195
  function nmiDeviceLinux(iface) {
196
- const cmd = `nmcli -t -f general,wifi-properties,capabilities,ip4,ip6 device show ${iface} 2> /dev/null`;
196
+ const cmd = `nmcli -t -f general,wifi-properties,capabilities,ip4,ip6 device show ${util.sanitizeString(iface, true)} 2> /dev/null`;
197
197
  try {
198
198
  const lines = execSync(cmd, util.execOptsLinux).toString().split('\n');
199
199
  const ssid = util.getValue(lines, 'GENERAL.CONNECTION');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/systeminformation",
3
- "version": "5.33.6-depup.0",
3
+ "version": "5.33.10-depup.0",
4
4
  "description": "Advanced, lightweight system and OS information library (with updated dependencies)",
5
5
  "license": "MIT",
6
6
  "author": "Sebastian Hildebrandt <hildebrandt@plus-innovations.com> (https://plus-innovations.com)",
@@ -111,8 +111,8 @@
111
111
  "changes": {},
112
112
  "depsUpdated": 0,
113
113
  "originalPackage": "systeminformation",
114
- "originalVersion": "5.33.6",
115
- "processedAt": "2026-08-30T00:59:35.725Z",
114
+ "originalVersion": "5.33.10",
115
+ "processedAt": "2026-09-13T01:00:18.796Z",
116
116
  "smokeTest": "passed"
117
117
  }
118
118
  }