Compare commits
	
		
			14 Commits
		
	
	
		
			v2.6.0
			...
			87005e72f1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 87005e72f1 | |||
| f799c2ee66 | |||
| 1a029ba493 | |||
| 5b756dd223 | |||
| 4cac599a58 | |||
| be6a7314c3 | |||
| 83ba9c2611 | |||
| 22ab472e58 | |||
| 9a77030377 | |||
| ceff285ff5 | |||
| d8bfbf0be3 | |||
| 3e6b883b38 | |||
| 47ef918128 | |||
| 5951638967 | 
							
								
								
									
										50
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,55 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.7 - fix(setup.sh)
 | 
				
			||||||
 | 
					Clarify net-snmp dependency installation message in setup.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Updated echo statement to indicate installation of net-snmp along with 2 subdependencies
 | 
				
			||||||
 | 
					- Improves clarity on dependency installation during setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.6 - fix(setup.sh)
 | 
				
			||||||
 | 
					Improve setup script to detect and execute npm-cli.js directly using the Node.js binary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Replace use of the npm binary with direct execution of npm-cli.js
 | 
				
			||||||
 | 
					- Add fallback logic to locate npm-cli.js when not found at the expected path
 | 
				
			||||||
 | 
					- Simplify cleanup by removing unnecessary PATH modifications
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.5 - fix(daemon, setup)
 | 
				
			||||||
 | 
					Improve shutdown command detection and fallback logic; update setup script to use absolute Node/npm paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Use execFileAsync to execute shutdown commands reliably
 | 
				
			||||||
 | 
					- Add multiple fallback alternatives for shutdown and emergency shutdown handling
 | 
				
			||||||
 | 
					- Update setup.sh to log the Node and NPM versions using absolute paths without modifying PATH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.4 - fix(setup)
 | 
				
			||||||
 | 
					Improve installation process in setup script by cleaning up package files and ensuring a minimal net-snmp dependency installation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Remove existing package-lock.json along with node_modules to prevent stale artifacts.
 | 
				
			||||||
 | 
					- Back up the original package.json before modifying it.
 | 
				
			||||||
 | 
					- Create a minimal package.json with only the net-snmp dependency based on the backed-up version.
 | 
				
			||||||
 | 
					- Use a clean install to guarantee that only net-snmp is installed.
 | 
				
			||||||
 | 
					- Restore the original package.json if the installation fails.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.3 - fix(setup)
 | 
				
			||||||
 | 
					Update setup script to install only net-snmp dependency and create a minimal package-lock.json for better dependency control.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Removed full production dependency install in favor of installing only net-snmp@3.20.0
 | 
				
			||||||
 | 
					- Added verification step to confirm net-snmp installation
 | 
				
			||||||
 | 
					- Generate a minimal package-lock.json if one does not exist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.2 - fix(setup/readme)
 | 
				
			||||||
 | 
					Improve force update instructions and dependency installation process in setup.sh and readme.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Clarify force update commands with explicit paths in readme.md
 | 
				
			||||||
 | 
					- Remove existing node_modules before installing dependencies in setup.sh
 | 
				
			||||||
 | 
					- Switch from 'npm ci --only=production' to 'npm install --omit=dev' with updated error instructions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-03-26 - 2.6.1 - fix(setup)
 | 
				
			||||||
 | 
					Update setup.sh to temporarily add vendor Node.js binary to PATH for dependency installation, log Node and npm versions, and restore the original PATH afterwards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Temporarily prepend vendor Node.js binary directory to PATH to ensure proper npm execution.
 | 
				
			||||||
 | 
					- Log Node.js and npm versions for debugging purposes.
 | 
				
			||||||
 | 
					- Restore the original PATH after installing dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 2025-03-26 - 2.6.0 - feat(setup)
 | 
					## 2025-03-26 - 2.6.0 - feat(setup)
 | 
				
			||||||
Add --force update flag to setup script and update installation instructions
 | 
					Add --force update flag to setup script and update installation instructions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@serve.zone/nupst",
 | 
					  "name": "@serve.zone/nupst",
 | 
				
			||||||
  "version": "2.6.0",
 | 
					  "version": "2.6.7",
 | 
				
			||||||
  "description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
 | 
					  "description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
 | 
				
			||||||
  "main": "dist/index.js",
 | 
					  "main": "dist/index.js",
 | 
				
			||||||
  "bin": {
 | 
					  "bin": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -234,7 +234,11 @@ This will:
 | 
				
			|||||||
You can also manually run the setup script with the force flag to update Node.js and dependencies without updating the application code:
 | 
					You can also manually run the setup script with the force flag to update Node.js and dependencies without updating the application code:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
bash setup.sh --force
 | 
					# If you're in the nupst directory:
 | 
				
			||||||
 | 
					bash ./setup.sh --force
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If you're in another directory, specify the full path:
 | 
				
			||||||
 | 
					bash /opt/nupst/setup.sh --force
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Security
 | 
					## Security
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										91
									
								
								setup.sh
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								setup.sh
									
									
									
									
									
								
							@@ -239,25 +239,90 @@ echo "dist_ts directory successfully downloaded from npm registry."
 | 
				
			|||||||
# Make launcher script executable
 | 
					# Make launcher script executable
 | 
				
			||||||
chmod +x "$SCRIPT_DIR/bin/nupst"
 | 
					chmod +x "$SCRIPT_DIR/bin/nupst"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install production dependencies
 | 
					# Set up Node.js binary path
 | 
				
			||||||
echo "Installing production dependencies..."
 | 
					NODE_BIN_DIR="$SCRIPT_DIR/vendor/$NODE_DIR/bin"
 | 
				
			||||||
"$SCRIPT_DIR/vendor/$NODE_DIR/bin/npm" --prefix "$SCRIPT_DIR" ci --only=production --no-audit --no-fund
 | 
					NODE_BIN="$NODE_BIN_DIR/node"
 | 
				
			||||||
 | 
					NPM_CLI_JS="$NODE_BIN_DIR/../lib/node_modules/npm/bin/npm-cli.js"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ $? -ne 0 ]; then
 | 
					# Ensure we have executable permissions
 | 
				
			||||||
  echo "Warning: Failed to install dependencies with 'npm ci'. Trying 'npm install'..."
 | 
					chmod +x "$NODE_BIN"
 | 
				
			||||||
  "$SCRIPT_DIR/vendor/$NODE_DIR/bin/npm" --prefix "$SCRIPT_DIR" install --only=production --no-audit --no-fund
 | 
					
 | 
				
			||||||
 | 
					# Make sure the npm-cli.js exists
 | 
				
			||||||
 | 
					if [ ! -f "$NPM_CLI_JS" ]; then
 | 
				
			||||||
 | 
					  # Try to find npm-cli.js
 | 
				
			||||||
 | 
					  NPM_CLI_JS=$(find "$NODE_BIN_DIR/.." -name "npm-cli.js" | head -1)
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  if [ $? -ne 0 ]; then
 | 
					  if [ -z "$NPM_CLI_JS" ]; then
 | 
				
			||||||
    echo "Error: Failed to install dependencies. NUPST may not function correctly."
 | 
					    echo "Warning: Could not find npm-cli.js, npm commands may fail"
 | 
				
			||||||
    echo "You can try to install dependencies manually by running:"
 | 
					    # Set to a fallback value so code can continue
 | 
				
			||||||
    echo "cd $SCRIPT_DIR && npm install --only=production"
 | 
					    NPM_CLI_JS="$NODE_BIN_DIR/npm"
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    echo "Dependencies installed successfully with 'npm install'."
 | 
					    echo "Found npm-cli.js at: $NPM_CLI_JS"
 | 
				
			||||||
  fi
 | 
					  fi
 | 
				
			||||||
else
 | 
					 | 
				
			||||||
  echo "Dependencies installed successfully with 'npm ci'."
 | 
					 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Display which binaries we're using
 | 
				
			||||||
 | 
					echo "Using Node binary: $NODE_BIN"
 | 
				
			||||||
 | 
					echo "Using NPM CLI JS: $NPM_CLI_JS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Remove existing node_modules directory and package files
 | 
				
			||||||
 | 
					echo "Cleaning up existing installation..."
 | 
				
			||||||
 | 
					rm -rf "$SCRIPT_DIR/node_modules"
 | 
				
			||||||
 | 
					rm -f "$SCRIPT_DIR/package-lock.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Back up existing package.json if it exists
 | 
				
			||||||
 | 
					if [ -f "$SCRIPT_DIR/package.json" ]; then
 | 
				
			||||||
 | 
					  echo "Backing up existing package.json..."
 | 
				
			||||||
 | 
					  cp "$SCRIPT_DIR/package.json" "$SCRIPT_DIR/package.json.bak"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create a clean minimal package.json with ONLY net-snmp dependency
 | 
				
			||||||
 | 
					echo "Creating minimal package.json with only net-snmp dependency..."
 | 
				
			||||||
 | 
					VERSION=$(grep -o '"version": "[^"]*"' "$SCRIPT_DIR/package.json.bak" | head -1 | cut -d'"' -f4 || echo "2.6.3")
 | 
				
			||||||
 | 
					echo '{
 | 
				
			||||||
 | 
					  "name": "@serve.zone/nupst",
 | 
				
			||||||
 | 
					  "version": "'$VERSION'",
 | 
				
			||||||
 | 
					  "description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
 | 
				
			||||||
 | 
					  "main": "dist_ts/index.js",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "bin": {
 | 
				
			||||||
 | 
					    "nupst": "bin/nupst"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "net-snmp": "3.20.0"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "engines": {
 | 
				
			||||||
 | 
					    "node": ">=16.0.0"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "private": true
 | 
				
			||||||
 | 
					}' > "$SCRIPT_DIR/package.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Install ONLY net-snmp
 | 
				
			||||||
 | 
					echo "Installing ONLY net-snmp dependency (+ 2 subdependencies)..."
 | 
				
			||||||
 | 
					echo "Node version: $("$NODE_BIN" --version)"
 | 
				
			||||||
 | 
					echo "Executing NPM directly with Node.js"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Execute npm-cli.js directly with our Node.js binary
 | 
				
			||||||
 | 
					"$NODE_BIN" "$NPM_CLI_JS" --prefix "$SCRIPT_DIR" install --no-audit --no-fund
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSTALL_STATUS=$?
 | 
				
			||||||
 | 
					if [ $INSTALL_STATUS -ne 0 ]; then
 | 
				
			||||||
 | 
					  echo "Error: Failed to install net-snmp dependency. NUPST may not function correctly."
 | 
				
			||||||
 | 
					  echo "Restoring original package.json..."
 | 
				
			||||||
 | 
					  mv "$SCRIPT_DIR/package.json.bak" "$SCRIPT_DIR/package.json"
 | 
				
			||||||
 | 
					  exit 1
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					  echo "net-snmp dependency installed successfully."
 | 
				
			||||||
 | 
					  # Show what's actually installed
 | 
				
			||||||
 | 
					  echo "Installed modules:"
 | 
				
			||||||
 | 
					  find "$SCRIPT_DIR/node_modules" -maxdepth 1 -type d | grep -v "^$SCRIPT_DIR/node_modules$" | sort
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  # Remove backup if successful
 | 
				
			||||||
 | 
					  rm -f "$SCRIPT_DIR/package.json.bak"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# No temporary files to clean up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "NUPST setup completed successfully."
 | 
					echo "NUPST setup completed successfully."
 | 
				
			||||||
echo "You can now run NUPST using: $SCRIPT_DIR/bin/nupst"
 | 
					echo "You can now run NUPST using: $SCRIPT_DIR/bin/nupst"
 | 
				
			||||||
echo "To install NUPST globally, run: sudo ln -s $SCRIPT_DIR/bin/nupst /usr/local/bin/nupst"
 | 
					echo "To install NUPST globally, run: sudo ln -s $SCRIPT_DIR/bin/nupst /usr/local/bin/nupst"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,6 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export const commitinfo = {
 | 
					export const commitinfo = {
 | 
				
			||||||
  name: '@serve.zone/nupst',
 | 
					  name: '@serve.zone/nupst',
 | 
				
			||||||
  version: '2.6.0',
 | 
					  version: '2.6.7',
 | 
				
			||||||
  description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
 | 
					  description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										176
									
								
								ts/daemon.ts
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								ts/daemon.ts
									
									
									
									
									
								
							@@ -1,11 +1,12 @@
 | 
				
			|||||||
import * as fs from 'fs';
 | 
					import * as fs from 'fs';
 | 
				
			||||||
import * as path from 'path';
 | 
					import * as path from 'path';
 | 
				
			||||||
import { exec } from 'child_process';
 | 
					import { exec, execFile } from 'child_process';
 | 
				
			||||||
import { promisify } from 'util';
 | 
					import { promisify } from 'util';
 | 
				
			||||||
import { NupstSnmp } from './snmp/manager.js';
 | 
					import { NupstSnmp } from './snmp/manager.js';
 | 
				
			||||||
import type { ISnmpConfig } from './snmp/types.js';
 | 
					import type { ISnmpConfig } from './snmp/types.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const execAsync = promisify(exec);
 | 
					const execAsync = promisify(exec);
 | 
				
			||||||
 | 
					const execFileAsync = promisify(execFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configuration interface for the daemon
 | 
					 * Configuration interface for the daemon
 | 
				
			||||||
@@ -298,23 +299,101 @@ export class NupstDaemon {
 | 
				
			|||||||
    const shutdownDelayMinutes = 5;
 | 
					    const shutdownDelayMinutes = 5;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      // Execute shutdown command with delay to allow for VM graceful shutdown
 | 
					      // Find shutdown command in common system paths
 | 
				
			||||||
      const { stdout } = await execAsync(`shutdown -h +${shutdownDelayMinutes} "UPS battery critical, shutting down in ${shutdownDelayMinutes} minutes"`);
 | 
					      const shutdownPaths = [
 | 
				
			||||||
      console.log('Shutdown initiated:', stdout);
 | 
					        '/sbin/shutdown',
 | 
				
			||||||
      console.log(`Allowing ${shutdownDelayMinutes} minutes for VMs to shut down safely`);
 | 
					        '/usr/sbin/shutdown',
 | 
				
			||||||
 | 
					        '/bin/shutdown',
 | 
				
			||||||
 | 
					        '/usr/bin/shutdown'
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      let shutdownCmd = '';
 | 
				
			||||||
 | 
					      for (const path of shutdownPaths) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          if (fs.existsSync(path)) {
 | 
				
			||||||
 | 
					            shutdownCmd = path;
 | 
				
			||||||
 | 
					            console.log(`Found shutdown command at: ${shutdownCmd}`);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					          // Continue checking other paths
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (shutdownCmd) {
 | 
				
			||||||
 | 
					        // Execute shutdown command with delay to allow for VM graceful shutdown
 | 
				
			||||||
 | 
					        console.log(`Executing: ${shutdownCmd} -h +${shutdownDelayMinutes} "UPS battery critical..."`);
 | 
				
			||||||
 | 
					        const { stdout } = await execFileAsync(shutdownCmd, [
 | 
				
			||||||
 | 
					          '-h', 
 | 
				
			||||||
 | 
					          `+${shutdownDelayMinutes}`, 
 | 
				
			||||||
 | 
					          `UPS battery critical, shutting down in ${shutdownDelayMinutes} minutes`
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        console.log('Shutdown initiated:', stdout);
 | 
				
			||||||
 | 
					        console.log(`Allowing ${shutdownDelayMinutes} minutes for VMs to shut down safely`);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // Try using the PATH to find shutdown
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          console.log('Shutdown command not found in common paths, trying via PATH...');
 | 
				
			||||||
 | 
					          const { stdout } = await execAsync(`shutdown -h +${shutdownDelayMinutes} "UPS battery critical, shutting down in ${shutdownDelayMinutes} minutes"`, {
 | 
				
			||||||
 | 
					            env: process.env // Pass the current environment
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          console.log('Shutdown initiated:', stdout);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					          throw new Error(`Shutdown command not found: ${e.message}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      // Monitor UPS during shutdown and force immediate shutdown if battery gets too low
 | 
					      // Monitor UPS during shutdown and force immediate shutdown if battery gets too low
 | 
				
			||||||
      console.log('Monitoring UPS during shutdown process...');
 | 
					      console.log('Monitoring UPS during shutdown process...');
 | 
				
			||||||
      await this.monitorDuringShutdown();
 | 
					      await this.monitorDuringShutdown();
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      console.error('Failed to initiate shutdown:', error);
 | 
					      console.error('Failed to initiate shutdown:', error);
 | 
				
			||||||
      // Try a different method if first one fails
 | 
					      
 | 
				
			||||||
      try {
 | 
					      // Try alternative shutdown methods
 | 
				
			||||||
        console.log('Trying alternative shutdown method...');
 | 
					      const alternatives = [
 | 
				
			||||||
        await execAsync('poweroff --force');
 | 
					        { cmd: 'poweroff', args: ['--force'] },
 | 
				
			||||||
      } catch (innerError) {
 | 
					        { cmd: 'halt', args: ['-p'] },
 | 
				
			||||||
        console.error('All shutdown methods failed:', innerError);
 | 
					        { cmd: 'systemctl', args: ['poweroff'] },
 | 
				
			||||||
 | 
					        { cmd: 'reboot', args: ['-p'] } // Some systems allow reboot -p for power off
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      for (const alt of alternatives) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          // First check if command exists in common system paths
 | 
				
			||||||
 | 
					          const paths = [
 | 
				
			||||||
 | 
					            `/sbin/${alt.cmd}`,
 | 
				
			||||||
 | 
					            `/usr/sbin/${alt.cmd}`,
 | 
				
			||||||
 | 
					            `/bin/${alt.cmd}`,
 | 
				
			||||||
 | 
					            `/usr/bin/${alt.cmd}`
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          let cmdPath = '';
 | 
				
			||||||
 | 
					          for (const path of paths) {
 | 
				
			||||||
 | 
					            if (fs.existsSync(path)) {
 | 
				
			||||||
 | 
					              cmdPath = path;
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          if (cmdPath) {
 | 
				
			||||||
 | 
					            console.log(`Trying alternative shutdown method: ${cmdPath} ${alt.args.join(' ')}`);
 | 
				
			||||||
 | 
					            await execFileAsync(cmdPath, alt.args);
 | 
				
			||||||
 | 
					            return; // Exit if successful
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            // Try using PATH environment
 | 
				
			||||||
 | 
					            console.log(`Trying alternative via PATH: ${alt.cmd} ${alt.args.join(' ')}`);
 | 
				
			||||||
 | 
					            await execAsync(`${alt.cmd} ${alt.args.join(' ')}`, {
 | 
				
			||||||
 | 
					              env: process.env // Pass the current environment
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return; // Exit if successful
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } catch (altError) {
 | 
				
			||||||
 | 
					          console.error(`Alternative method ${alt.cmd} failed:`, altError);
 | 
				
			||||||
 | 
					          // Continue to next method
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      console.error('All shutdown methods failed');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@@ -346,10 +425,79 @@ export class NupstDaemon {
 | 
				
			|||||||
          console.log('└──────────────────────────────────────────┘');
 | 
					          console.log('└──────────────────────────────────────────┘');
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
          try {
 | 
					          try {
 | 
				
			||||||
            await execAsync('shutdown -h now "EMERGENCY: UPS battery critically low, shutting down NOW"');
 | 
					            // Find shutdown command in common system paths
 | 
				
			||||||
 | 
					            const shutdownPaths = [
 | 
				
			||||||
 | 
					              '/sbin/shutdown',
 | 
				
			||||||
 | 
					              '/usr/sbin/shutdown',
 | 
				
			||||||
 | 
					              '/bin/shutdown',
 | 
				
			||||||
 | 
					              '/usr/bin/shutdown'
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            let shutdownCmd = '';
 | 
				
			||||||
 | 
					            for (const path of shutdownPaths) {
 | 
				
			||||||
 | 
					              if (fs.existsSync(path)) {
 | 
				
			||||||
 | 
					                shutdownCmd = path;
 | 
				
			||||||
 | 
					                console.log(`Found shutdown command at: ${shutdownCmd}`);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (shutdownCmd) {
 | 
				
			||||||
 | 
					              console.log(`Executing emergency shutdown: ${shutdownCmd} -h now`);
 | 
				
			||||||
 | 
					              await execFileAsync(shutdownCmd, ['-h', 'now', 'EMERGENCY: UPS battery critically low, shutting down NOW']);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              // Try using the PATH to find shutdown
 | 
				
			||||||
 | 
					              console.log('Shutdown command not found in common paths, trying via PATH...');
 | 
				
			||||||
 | 
					              await execAsync('shutdown -h now "EMERGENCY: UPS battery critically low, shutting down NOW"', {
 | 
				
			||||||
 | 
					                env: process.env // Pass the current environment
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          } catch (error) {
 | 
					          } catch (error) {
 | 
				
			||||||
            console.error('Emergency shutdown failed, trying alternative method...');
 | 
					            console.error('Emergency shutdown failed, trying alternative methods...');
 | 
				
			||||||
            await execAsync('poweroff --force');
 | 
					            
 | 
				
			||||||
 | 
					            // Try alternative shutdown methods in sequence
 | 
				
			||||||
 | 
					            const alternatives = [
 | 
				
			||||||
 | 
					              { cmd: 'poweroff', args: ['--force'] },
 | 
				
			||||||
 | 
					              { cmd: 'halt', args: ['-p'] },
 | 
				
			||||||
 | 
					              { cmd: 'systemctl', args: ['poweroff'] }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            for (const alt of alternatives) {
 | 
				
			||||||
 | 
					              try {
 | 
				
			||||||
 | 
					                // Check common paths
 | 
				
			||||||
 | 
					                const paths = [
 | 
				
			||||||
 | 
					                  `/sbin/${alt.cmd}`,
 | 
				
			||||||
 | 
					                  `/usr/sbin/${alt.cmd}`,
 | 
				
			||||||
 | 
					                  `/bin/${alt.cmd}`,
 | 
				
			||||||
 | 
					                  `/usr/bin/${alt.cmd}`
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                let cmdPath = '';
 | 
				
			||||||
 | 
					                for (const path of paths) {
 | 
				
			||||||
 | 
					                  if (fs.existsSync(path)) {
 | 
				
			||||||
 | 
					                    cmdPath = path;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if (cmdPath) {
 | 
				
			||||||
 | 
					                  console.log(`Emergency: using ${cmdPath} ${alt.args.join(' ')}`);
 | 
				
			||||||
 | 
					                  await execFileAsync(cmdPath, alt.args);
 | 
				
			||||||
 | 
					                  return; // Exit if successful
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                  // Try using PATH
 | 
				
			||||||
 | 
					                  console.log(`Emergency: trying ${alt.cmd} via PATH`);
 | 
				
			||||||
 | 
					                  await execAsync(`${alt.cmd} ${alt.args.join(' ')}`, {
 | 
				
			||||||
 | 
					                    env: process.env
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                  return; // Exit if successful
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              } catch (altError) {
 | 
				
			||||||
 | 
					                // Continue to next method
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            console.error('All emergency shutdown methods failed');
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
          // Stop monitoring after initiating emergency shutdown
 | 
					          // Stop monitoring after initiating emergency shutdown
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user