diff --git a/nohang/nohang b/nohang/nohang
index d69d333..892363a 100755
--- a/nohang/nohang
+++ b/nohang/nohang
@@ -11,6 +11,7 @@ from sre_constants import error as invalid_re
from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
+
###############################################################################
# define functions
@@ -19,25 +20,27 @@ from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
def exe(cmd):
""" execute cmd in subprocess.Popen()
"""
+ cmd_list = shlex.split(cmd)
cmd_num_dict['cmd_num'] += 1
cmd_num = cmd_num_dict['cmd_num']
- log('Execute the command({}) in {}: {}'.format(
+
+ log('Execute the command ({}) in {}: {}'.format(
cmd_num,
threading.current_thread().getName(),
- cmd))
+ cmd_list))
t3 = monotonic()
- with Popen(cmd, shell=True) as proc:
+ with Popen(cmd_list) as proc:
try:
proc.wait(timeout=exe_timeout)
exit_status = proc.poll()
t4 = monotonic()
- log('Command({}) execution completed in {} sec; exit status' \
+ log('Command ({}) execution completed in {} sec; exit status' \
': {}'.format(cmd_num, round(t4 - t3, 3), exit_status))
except TimeoutExpired:
proc.kill()
t4 = monotonic()
- log('TimeoutExpired for the command({}) in {} sec'.format(
+ log('TimeoutExpired for the command ({}) in {} sec'.format(
cmd_num, round(t4 - t3, 3)))
@@ -61,9 +64,9 @@ def start_thread(func, *a, **k):
t2 = monotonic()
if debug_threading:
- log('{} has started in {} ms, {} threads currently alive'.format(
- th_name, round((t2 - t1) * 1000, 1), threading.active_count()
- ))
+ log('{} has started in {} ms, {} threads are ' \
+ 'currently alive'.format(th_name, round((
+ t2 - t1) * 1000, 1), threading.active_count()))
except RuntimeError:
@@ -153,6 +156,17 @@ def pop(cmd, username):
""" run cmd in subprocess.Popen()
"""
+
+ cmd_num_dict['cmd_num'] += 1
+ cmd_num = cmd_num_dict['cmd_num']
+
+ log('Execute the Command-{} {} in {}'.format(
+ cmd_num,
+ cmd,
+ threading.current_thread().getName()
+ ))
+
+
if swap_total == 0:
wait_time = 2
else:
@@ -164,18 +178,15 @@ def pop(cmd, username):
try:
proc.wait(timeout=wait_time)
err = proc.poll()
+ t4 = monotonic()
except TimeoutExpired:
proc.kill()
+ t4 = monotonic()
+
if debug_gui_notifications:
log('TimeoutExpired: notify user: {}'.format(username))
- t4 = monotonic()
-
- err = 0
-
if debug_gui_notifications:
- pass
- #log('Popen time: {} sec; exit status: {}; cmd: {}'.format(round(t4 - t3, 3), err, cmd))
log('Popen time: {} sec; exit status: {}; cmd: {}'.format(round(t4 - t3, 3), err, cmd))
@@ -279,15 +290,18 @@ def send_notify(threshold, name, pid):
"""
title = 'Freeze prevention'
- body = '{} [{}] {}'.format(
- notify_sig_dict[threshold],
- pid,
- name.replace(
- # symbol '&' can break notifications in some themes,
- # therefore it is replaced by '*'
- '&', '*'
- )
- )
+
+ if hide_corrective_action_type:
+ body = 'Corrective action applied'
+ else:
+ body = '{} [{}] {}'.format(
+ notify_sig_dict[threshold],
+ pid,
+ name.replace(
+ # symbol '&' can break notifications in some themes,
+ # therefore it is replaced by '*'
+ '&', '*'
+ ))
start_thread(send_notification, title, body)
@@ -301,9 +315,12 @@ def send_notify_etc(pid, name, command):
pid: str process pid
"""
title = 'Freeze prevention'
- body = 'Victim is [{}] {}\nExecute the co' \
- 'mmand:\n{}'.format(
- pid, name.replace('&', '*'), command.replace('&', '*'))
+ if hide_corrective_action_type:
+ body = 'Corrective action applied'
+ else:
+ body = 'Victim is [{}] {}\nExecute the command:\n' \
+ '{}'.format(pid, name.replace(
+ '&', '*'), command.replace('&', '*'))
start_thread(send_notification, title, body)
@@ -3016,9 +3033,24 @@ print_victim_cmdline = conf_parse_bool('print_victim_cmdline')
print_config_at_startup = conf_parse_bool('print_config_at_startup')
print_mem_check_results = conf_parse_bool('print_mem_check_results')
debug_sleep = conf_parse_bool('debug_sleep')
+
+hide_corrective_action_type = conf_parse_bool('hide_corrective_action_type')
+
+
+
+
low_memory_warnings_enabled = conf_parse_bool('low_memory_warnings_enabled')
+
+
+
+
+
+
+
+
+
post_action_gui_notifications = conf_parse_bool(
'post_action_gui_notifications')
@@ -3369,33 +3401,35 @@ if separate_log:
import logging
log_dir = '/var/log/nohang'
-
- try:
- os.mkdir(log_dir)
- except PermissionError:
- print('ERROR: can not create log dir')
- except FileExistsError:
- pass
-
logfile = log_dir + '/nohang.log'
try:
- with open(logfile, 'a') as f:
- pass
- except FileNotFoundError:
- print('ERROR: log FileNotFoundError')
+ os.mkdir(log_dir)
+ except FileExistsError:
+ pass
except PermissionError:
- print('ERROR: log PermissionError')
+ errprint('ERROR: cannot create {}'.format(log_dir))
+
+ try:
+ os.chmod(log_dir, mode=0o750)
+ except FileNotFoundError:
+ errprint('ERROR: file not found: {}'.format(log_dir))
+ except PermissionError:
+ errprint('ERROR: permission denied: {}'.format(log_dir))
try:
logging.basicConfig(
filename=logfile,
level=logging.INFO,
format="%(asctime)s: %(message)s")
- except PermissionError:
- errprint('ERROR: Permission denied: {}'.format(logfile))
except FileNotFoundError:
- errprint('ERROR: FileNotFoundError: {}'.format(logfile))
+ errprint('ERROR: file not found: {}'.format(logfile))
+ except PermissionError:
+ errprint('ERROR: permission denied: {}'.format(logfile))
+
+
+
+
if 'min_mem_report_interval' in config_dict:
@@ -3511,11 +3545,13 @@ if (low_memory_warnings_enabled or \
post_kill_exe != ''):
import threading
+ import shlex
from subprocess import Popen, TimeoutExpired
+
psi_support = os.path.exists(psi_path)
diff --git a/nohang/nohang-desktop.conf b/nohang/nohang-desktop.conf
index de31d99..ea08288 100644
--- a/nohang/nohang-desktop.conf
+++ b/nohang/nohang-desktop.conf
@@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications
+ 4.1. GUI notifications after corrective actions
+
Description:
Type: boolean
Valid values: True and False
@@ -122,6 +124,14 @@ post_action_gui_notifications = True
Type: boolean
Valid values: True and False
+hide_corrective_action_type = True
+
+ 4.2. Low memory warnings
+
+ Description:
+ Type: boolean
+ Valid values: True and False
+
low_memory_warnings_enabled = True
Description:
diff --git a/nohang/nohang.conf b/nohang/nohang.conf
index 10ba4a1..141257d 100644
--- a/nohang/nohang.conf
+++ b/nohang/nohang.conf
@@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications
+ 4.1. GUI notifications after corrective actions
+
Description:
Type: boolean
Valid values: True and False
@@ -122,6 +124,14 @@ post_action_gui_notifications = False
Type: boolean
Valid values: True and False
+hide_corrective_action_type = True
+
+ 4.2. Low memory warnings
+
+ Description:
+ Type: boolean
+ Valid values: True and False
+
low_memory_warnings_enabled = False
Description:
diff --git a/nohang/nohang.service.in b/nohang/nohang.service.in
index c7bb616..d7d34d7 100644
--- a/nohang/nohang.service.in
+++ b/nohang/nohang.service.in
@@ -8,18 +8,20 @@ ExecStart=:TARGET_BIN:/nohang --config :TARGET_CONF:/nohang/nohang.conf
Restart=always
RestartSec=0
KillMode=mixed
+TasksMax=100
Nice=-15
CPUSchedulingResetOnFork=true
OOMScoreAdjust=-10
+UMask=0027
+PrivateTmp=true
RestrictRealtime=yes
MemoryDenyWriteExecute=yes
ProtectKernelModules=true
SystemCallArchitectures=native
ReadOnlyPaths=/
ReadWritePaths=/tmp /var /run /dev/shm
-PrivateTmp=true
-CapabilityBoundingSet=CAP_KILL CAP_AUDIT_WRITE CAP_DAC_READ_SEARCH CAP_IPC_LOCK CAP_SETGID CAP_SETUID CAP_SYS_PTRACE CAP_CHOWN
-AmbientCapabilities=CAP_KILL CAP_AUDIT_WRITE CAP_DAC_READ_SEARCH CAP_IPC_LOCK CAP_SETGID CAP_SETUID CAP_SYS_PTRACE
+CapabilityBoundingSet=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID
+AmbientCapabilities=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID
[Install]
WantedBy=multi-user.target
diff --git a/nohang/test.conf b/nohang/test.conf
index 4afe728..d7a7ae2 100644
--- a/nohang/test.conf
+++ b/nohang/test.conf
@@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications
+ 4.1. GUI notifications after corrective actions
+
Description:
Type: boolean
Valid values: True and False
@@ -122,6 +124,14 @@ post_action_gui_notifications = True
Type: boolean
Valid values: True and False
+hide_corrective_action_type = False
+
+ 4.2. Low memory warnings
+
+ Description:
+ Type: boolean
+ Valid values: True and False
+
low_memory_warnings_enabled = True
Description: