add CLI options using sys.argv

This commit is contained in:
Alexey Avramov 2019-02-13 02:09:51 +09:00
parent 5f211d765b
commit c0cffa7e7a
3 changed files with 164 additions and 69 deletions

View File

@ -107,6 +107,19 @@ $ sudo systemctl start nohang
$ sudo systemctl enable nohang $ sudo systemctl enable nohang
``` ```
## Command line options
```
./nohang -h
usage: nohang [-h] [-c CONFIG]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf
```
## How to configure nohang ## How to configure nohang
The program can be configured by editing the [config file](https://github.com/hakavlad/nohang/blob/master/nohang.conf). The configuration includes the following sections: The program can be configured by editing the [config file](https://github.com/hakavlad/nohang/blob/master/nohang.conf). The configuration includes the following sections:
@ -205,13 +218,13 @@ Please create [issues](https://github.com/hakavlad/nohang/issues). Use cases, fe
- [x] Handle all timeouts when notify-send starts - [x] Handle all timeouts when notify-send starts
- [x] Fix conf parsing: use of `line.partition('=')` instead of `line.split('=')` - [x] Fix conf parsing: use of `line.partition('=')` instead of `line.split('=')`
- [x] Add `oom-sort` - [x] Add `oom-sort`
- [x] Reduce memory usage (remove `import argparse`) - [x] Reduce memory usage and startup time (using `sys.argv` instead of `argparse`)
- [x] Remove CLI options (need to add it again via `sys.argv`) - [x] Remove CLI options (need to add it again via `sys.argv`)
- [x] Remove self-defense options from config, use systemd unit scheduling instead - [x] Remove self-defense options from config, use systemd unit scheduling instead
- [x] Add the ability to send any signal instead of SIGTERM for processes with certain names - [x] Add the ability to send any signal instead of SIGTERM for processes with certain names
- [x] Handle `UnicodeDecodeError` if victim name consists of many unicode characters - [x] Handle `UnicodeDecodeError` if victim name consists of many unicode characters
- [x] Fix `mlockall()` using `MCL_ONFAULT` and lock all memory by default - [x] Fix `mlockall()` using `MCL_ONFAULT` and lock all memory by default
- [ ] Add `PSI` support (using `/proc/pressure/memory`, need Linux 4.20+) - [x] Add initial support for `PSI` (using `/proc/pressure/memory`, need Linux 4.20+)
- [ ] Redesign of the config - [ ] Redesign of the config
- [ ] Decrease CPU usage: ignore `zram` by default - [ ] Decrease CPU usage: ignore `zram` by default
- [ ] Improve user input validation - [ ] Improve user input validation
@ -221,5 +234,4 @@ Please create [issues](https://github.com/hakavlad/nohang/issues). Use cases, fe
- [x] Fix: replace `re.fullmatch()` by `re.search()` - [x] Fix: replace `re.fullmatch()` by `re.search()`
- [ ] Validation RE patterns at startup - [ ] Validation RE patterns at startup
- [v0.1](https://github.com/hakavlad/nohang/releases/tag/v0.1), 2018-11-23 - [v0.1](https://github.com/hakavlad/nohang/releases/tag/v0.1), 2018-11-23: Initial release
- 1st release

211
nohang
View File

@ -4,9 +4,48 @@ import os
from ctypes import CDLL from ctypes import CDLL
from time import sleep, time from time import sleep, time
from operator import itemgetter from operator import itemgetter
from sys import stdout from sys import stdout, stderr, argv, exit
from signal import SIGKILL, SIGTERM from signal import SIGKILL, SIGTERM
help_mess = """usage: nohang [-h] [-c CONFIG]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf"""
if len(argv) == 1:
if os.path.exists('./nohang.conf'):
config = cd = os.getcwd() + '/nohang.conf'
else:
config = '/etc/nohang/nohang.conf'
elif len(argv) == 2:
if argv[1] == '--help' or argv[1] == '-h':
print(help_mess)
exit(1)
else:
print('Invalid CLI input')
exit(1)
elif len(argv) > 3:
print('Invalid CLI input')
exit(1)
else:
if argv[1] == '--config' or argv[1] == '-c':
config = argv[2]
else:
print('Invalid option: {}'.format(argv[1]))
exit(1)
conf_err_mess = 'Invalid config. Exit.'
start_time = time() start_time = time()
sig_dict = {SIGKILL: 'SIGKILL', sig_dict = {SIGKILL: 'SIGKILL',
@ -40,6 +79,7 @@ HR = '~' * 79
# todo: make config option # todo: make config option
print_total_stat = True print_total_stat = True
########################################################################## ##########################################################################
# define functions # define functions
@ -194,7 +234,7 @@ def conf_parse_string(param):
else: else:
print('All the necessary parameters must be in the config') print('All the necessary parameters must be in the config')
print('There is no "{}" parameter in the config'.format(param)) print('There is no "{}" parameter in the config'.format(param))
exit() exit(1)
def conf_parse_bool(param): def conf_parse_bool(param):
@ -211,14 +251,14 @@ def conf_parse_bool(param):
elif param_str == 'False': elif param_str == 'False':
return False return False
else: else:
print('Invalid value of the "{}" parameter.'.format(param_str)) print('Invalid value of the "{}" parameter.'.format(param))
print('Valid values are True and False.') print('Valid values are True and False.')
print('Exit') print('Exit')
exit() exit(1)
else: else:
print('All the necessary parameters must be in the config') print('All the necessary parameters must be in the config')
print('There is no "{}" parameter in the config'.format(param_str)) print('There is no "{}" parameter in the config'.format(param))
exit() exit(1)
def rline1(path): def rline1(path):
@ -325,6 +365,9 @@ def pid_to_uid(pid):
return f_list[uid_index].split('\t')[2] return f_list[uid_index].split('\t')[2]
def notify_send_wait(title, body): def notify_send_wait(title, body):
'''GUI notifications with UID != 0''' '''GUI notifications with UID != 0'''
with Popen(['notify-send', '--icon=dialog-warning', title, body]) as proc: with Popen(['notify-send', '--icon=dialog-warning', title, body]) as proc:
@ -338,8 +381,6 @@ def notify_send_wait(title, body):
def notify_helper(title, body): def notify_helper(title, body):
'''GUI notification with UID = 0''' '''GUI notification with UID = 0'''
# os.system(notify_helper_path + ' foo bar &')
with Popen([notify_helper_path, title, body]) as proc: with Popen([notify_helper_path, title, body]) as proc:
try: try:
proc.wait(timeout=wait_time) proc.wait(timeout=wait_time)
@ -350,12 +391,16 @@ def notify_helper(title, body):
title, body)) title, body))
def send_notify_warn(): def send_notify_warn():
""" """
Look for process with maximum 'badness' and warn user with notification. Look for process with maximum 'badness' and warn user with notification.
(implement Low memory warnings) (implement Low memory warnings)
""" """
'''
# find process with max badness # find process with max badness
fat_tuple = fattest() fat_tuple = fattest()
pid = fat_tuple[0] pid = fat_tuple[0]
@ -376,7 +421,14 @@ def send_notify_warn():
# title = 'Low memory: {}'.format(low_mem_percent) # title = 'Low memory: {}'.format(low_mem_percent)
title = 'Low memory' title = 'Low memory'
'''
'''
body = 'Next victim: {}[{}]'.format( body = 'Next victim: {}[{}]'.format(
name.replace( name.replace(
# symbol '&' can break notifications in some themes, # symbol '&' can break notifications in some themes,
@ -384,6 +436,13 @@ def send_notify_warn():
'&', '*'), '&', '*'),
pid pid
) )
'''
'''
body = 'MemAvail: {}%\nSwapFree: {}%'.format(
round(mem_available / mem_total * 100),
round(swap_free / (swap_total + 0.1) * 100))
if root: # If nohang was started by root if root: # If nohang was started by root
# send notification to all active users with special script # send notification to all active users with special script
@ -391,6 +450,22 @@ def send_notify_warn():
else: # Or by regular user else: # Or by regular user
# send notification to user that runs this nohang # send notification to user that runs this nohang
notify_send_wait(title, body) notify_send_wait(title, body)
'''
b = """{} 'Low memory' 'MemAvail: {}%\nSwapFree: {}%' &""".format(
notify_helper_path,
round(mem_available / mem_total * 100),
round(swap_free / (swap_total + 0.1) * 100)
)
t0 = time()
os.system(b)
t1 = time()
print('t:', t1 - t0)
def send_notify(signal, name, pid): def send_notify(signal, name, pid):
@ -402,13 +477,14 @@ def send_notify(signal, name, pid):
pid: str process pid pid: str process pid
""" """
title = 'Freeze prevention' title = 'Freeze prevention'
body = '{} {}[{}]'.format( body = '<b>{}</b> [{}] <b>{}</b>'.format(
notify_sig_dict[signal], notify_sig_dict[signal],
pid,
name.replace( name.replace(
# symbol '&' can break notifications in some themes, # symbol '&' can break notifications in some themes,
# therefore it is replaced by '*' # therefore it is replaced by '*'
'&', '*'), '&', '*'
pid )
) )
if root: if root:
# send notification to all active users with notify-send # send notification to all active users with notify-send
@ -899,7 +975,7 @@ def sleep_after_check_mem():
stdout.flush() stdout.flush()
sleep(t) sleep(t)
except KeyboardInterrupt: except KeyboardInterrupt:
exit() exit(1)
def calculate_percent(arg_key): def calculate_percent(arg_key):
@ -922,12 +998,12 @@ def calculate_percent(arg_key):
mem_min_percent = string_to_float_convert_test(mem_min_percent) mem_min_percent = string_to_float_convert_test(mem_min_percent)
if mem_min_percent is None: if mem_min_percent is None:
print('Invalid {} value, not float\nExit'.format(arg_key)) print('Invalid {} value, not float\nExit'.format(arg_key))
exit() exit(1)
# Final validations... # Final validations...
if mem_min_percent < 0 or mem_min_percent > 100: if mem_min_percent < 0 or mem_min_percent > 100:
print( print(
'{}, as percents value, out of range [0; 100]\nExit'.format(arg_key)) '{}, as percents value, out of range [0; 100]\nExit'.format(arg_key))
exit() exit(1)
# mem_min_sigterm_percent is clean and valid float percentage. Can # mem_min_sigterm_percent is clean and valid float percentage. Can
# translate into Kb # translate into Kb
@ -938,14 +1014,14 @@ def calculate_percent(arg_key):
mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip()) mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip())
if mem_min_mb is None: if mem_min_mb is None:
print('Invalid {} value, not float\nExit'.format(arg_key)) print('Invalid {} value, not float\nExit'.format(arg_key))
exit() exit(1)
mem_min_kb = mem_min_mb * 1024 mem_min_kb = mem_min_mb * 1024
if mem_min_kb > mem_total: if mem_min_kb > mem_total:
print( print(
'{} value can not be greater then MemTotal ({} MiB)\nExit'.format( '{} value can not be greater then MemTotal ({} MiB)\nExit'.format(
arg_key, round( arg_key, round(
mem_total / 1024))) mem_total / 1024)))
exit() exit(1)
mem_min_percent = mem_min_kb / mem_total * 100 mem_min_percent = mem_min_kb / mem_total * 100
else: else:
@ -982,7 +1058,7 @@ for s in mem_list:
if mem_list_names[2] != 'MemAvailable': if mem_list_names[2] != 'MemAvailable':
print('Your Linux kernel is too old, Linux 3.14+ requied\nExit') print('Your Linux kernel is too old, Linux 3.14+ requied\nExit')
exit() exit(1)
swap_total_index = mem_list_names.index('SwapTotal') swap_total_index = mem_list_names.index('SwapTotal')
swap_free_index = swap_total_index + 1 swap_free_index = swap_total_index + 1
@ -1003,6 +1079,8 @@ vm_size_index = status_names.index('VmSize')
vm_rss_index = status_names.index('VmRSS') vm_rss_index = status_names.index('VmRSS')
vm_swap_index = status_names.index('VmSwap') vm_swap_index = status_names.index('VmSwap')
uid_index = status_names.index('Uid') uid_index = status_names.index('Uid')
state_index = status_names.index('State')
try: try:
anon_index = status_names.index('RssAnon') anon_index = status_names.index('RssAnon')
@ -1023,7 +1101,7 @@ cd = os.getcwd()
''' '''
config = '/etc/nohang/nohang.conf' #config = '/etc/nohang/nohang.conf'
# config = 'nohang.conf' # config = 'nohang.conf'
@ -1075,7 +1153,7 @@ try:
if len(etc_name) > 15: if len(etc_name) > 15:
print('Invalid config, the length of the process ' print('Invalid config, the length of the process '
'name must not exceed 15 characters\nExit') 'name must not exceed 15 characters\nExit')
exit() exit(1)
etc_dict[etc_name] = etc_command etc_dict[etc_name] = etc_command
# NEED VALIDATION! # NEED VALIDATION!
@ -1095,16 +1173,21 @@ try:
except PermissionError: except PermissionError:
print('PermissionError', conf_err_mess) print('PermissionError', conf_err_mess)
exit() exit(1)
except UnicodeDecodeError: except UnicodeDecodeError:
print('UnicodeDecodeError', conf_err_mess) print('UnicodeDecodeError', conf_err_mess)
exit() exit(1)
except IsADirectoryError: except IsADirectoryError:
print('IsADirectoryError', conf_err_mess) print('IsADirectoryError', conf_err_mess)
exit() exit(1)
except IndexError: except IndexError:
print('IndexError', conf_err_mess) print('IndexError', conf_err_mess)
exit() exit(1)
except FileNotFoundError:
print('FileNotFoundError', conf_err_mess)
exit(1)
# print(processname_re_list) # print(processname_re_list)
# print(cmdline_re_list) # print(cmdline_re_list)
@ -1158,53 +1241,53 @@ if 'rate_mem' in config_dict:
rate_mem = string_to_float_convert_test(config_dict['rate_mem']) rate_mem = string_to_float_convert_test(config_dict['rate_mem'])
if rate_mem is None: if rate_mem is None:
print('Invalid rate_mem value, not float\nExit') print('Invalid rate_mem value, not float\nExit')
exit() exit(1)
if rate_mem <= 0: if rate_mem <= 0:
print('rate_mem MUST be > 0\nExit') print('rate_mem MUST be > 0\nExit')
exit() exit(1)
else: else:
print('rate_mem not in config\nExit') print('rate_mem not in config\nExit')
exit() exit(1)
if 'rate_swap' in config_dict: if 'rate_swap' in config_dict:
rate_swap = string_to_float_convert_test(config_dict['rate_swap']) rate_swap = string_to_float_convert_test(config_dict['rate_swap'])
if rate_swap is None: if rate_swap is None:
print('Invalid rate_swap value, not float\nExit') print('Invalid rate_swap value, not float\nExit')
exit() exit(1)
if rate_swap <= 0: if rate_swap <= 0:
print('rate_swap MUST be > 0\nExit') print('rate_swap MUST be > 0\nExit')
exit() exit(1)
else: else:
print('rate_swap not in config\nExit') print('rate_swap not in config\nExit')
exit() exit(1)
if 'rate_zram' in config_dict: if 'rate_zram' in config_dict:
rate_zram = string_to_float_convert_test(config_dict['rate_zram']) rate_zram = string_to_float_convert_test(config_dict['rate_zram'])
if rate_zram is None: if rate_zram is None:
print('Invalid rate_zram value, not float\nExit') print('Invalid rate_zram value, not float\nExit')
exit() exit(1)
if rate_zram <= 0: if rate_zram <= 0:
print('rate_zram MUST be > 0\nExit') print('rate_zram MUST be > 0\nExit')
exit() exit(1)
else: else:
print('rate_zram not in config\nExit') print('rate_zram not in config\nExit')
exit() exit(1)
if 'swap_min_sigterm' in config_dict: if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm'] swap_min_sigterm = config_dict['swap_min_sigterm']
else: else:
print('swap_min_sigterm not in config\nExit') print('swap_min_sigterm not in config\nExit')
exit() exit(1)
if 'swap_min_sigkill' in config_dict: if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill'] swap_min_sigkill = config_dict['swap_min_sigkill']
else: else:
print('swap_min_sigkill not in config\nExit') print('swap_min_sigkill not in config\nExit')
exit() exit(1)
if 'min_delay_after_sigterm' in config_dict: if 'min_delay_after_sigterm' in config_dict:
@ -1212,13 +1295,13 @@ if 'min_delay_after_sigterm' in config_dict:
config_dict['min_delay_after_sigterm']) config_dict['min_delay_after_sigterm'])
if min_delay_after_sigterm is None: if min_delay_after_sigterm is None:
print('Invalid min_delay_after_sigterm value, not float\nExit') print('Invalid min_delay_after_sigterm value, not float\nExit')
exit() exit(1)
if min_delay_after_sigterm < 0: if min_delay_after_sigterm < 0:
print('min_delay_after_sigterm must be positiv\nExit') print('min_delay_after_sigterm must be positiv\nExit')
exit() exit(1)
else: else:
print('min_delay_after_sigterm not in config\nExit') print('min_delay_after_sigterm not in config\nExit')
exit() exit(1)
if 'min_delay_after_sigkill' in config_dict: if 'min_delay_after_sigkill' in config_dict:
@ -1226,13 +1309,13 @@ if 'min_delay_after_sigkill' in config_dict:
config_dict['min_delay_after_sigkill']) config_dict['min_delay_after_sigkill'])
if min_delay_after_sigkill is None: if min_delay_after_sigkill is None:
print('Invalid min_delay_after_sigkill value, not float\nExit') print('Invalid min_delay_after_sigkill value, not float\nExit')
exit() exit(1)
if min_delay_after_sigkill < 0: if min_delay_after_sigkill < 0:
print('min_delay_after_sigkill must be positive\nExit') print('min_delay_after_sigkill must be positive\nExit')
exit() exit(1)
else: else:
print('min_delay_after_sigkill not in config\nExit') print('min_delay_after_sigkill not in config\nExit')
exit() exit(1)
if 'psi_avg10_sleep_time' in config_dict: if 'psi_avg10_sleep_time' in config_dict:
@ -1240,13 +1323,13 @@ if 'psi_avg10_sleep_time' in config_dict:
config_dict['psi_avg10_sleep_time']) config_dict['psi_avg10_sleep_time'])
if psi_avg10_sleep_time is None: if psi_avg10_sleep_time is None:
print('Invalid psi_avg10_sleep_time value, not float\nExit') print('Invalid psi_avg10_sleep_time value, not float\nExit')
exit() exit(1)
if psi_avg10_sleep_time < 0: if psi_avg10_sleep_time < 0:
print('psi_avg10_sleep_time must be positive\nExit') print('psi_avg10_sleep_time must be positive\nExit')
exit() exit(1)
else: else:
print('psi_avg10_sleep_time not in config\nExit') print('psi_avg10_sleep_time not in config\nExit')
exit() exit(1)
if 'sigkill_psi_avg10' in config_dict: if 'sigkill_psi_avg10' in config_dict:
@ -1254,13 +1337,13 @@ if 'sigkill_psi_avg10' in config_dict:
config_dict['sigkill_psi_avg10']) config_dict['sigkill_psi_avg10'])
if sigkill_psi_avg10 is None: if sigkill_psi_avg10 is None:
print('Invalid sigkill_psi_avg10 value, not float\nExit') print('Invalid sigkill_psi_avg10 value, not float\nExit')
exit() exit(1)
if sigkill_psi_avg10 < 0 or sigkill_psi_avg10 > 100: if sigkill_psi_avg10 < 0 or sigkill_psi_avg10 > 100:
print('sigkill_psi_avg10 must be in the range [0; 100]\nExit') print('sigkill_psi_avg10 must be in the range [0; 100]\nExit')
exit() exit(1)
else: else:
print('sigkill_psi_avg10 not in config\nExit') print('sigkill_psi_avg10 not in config\nExit')
exit() exit(1)
if 'sigterm_psi_avg10' in config_dict: if 'sigterm_psi_avg10' in config_dict:
@ -1268,13 +1351,13 @@ if 'sigterm_psi_avg10' in config_dict:
config_dict['sigterm_psi_avg10']) config_dict['sigterm_psi_avg10'])
if sigterm_psi_avg10 is None: if sigterm_psi_avg10 is None:
print('Invalid sigterm_psi_avg10 value, not float\nExit') print('Invalid sigterm_psi_avg10 value, not float\nExit')
exit() exit(1)
if sigterm_psi_avg10 < 0 or sigterm_psi_avg10 > 100: if sigterm_psi_avg10 < 0 or sigterm_psi_avg10 > 100:
print('sigterm_psi_avg10 must be in the range [0; 100]\nExit') print('sigterm_psi_avg10 must be in the range [0; 100]\nExit')
exit() exit(1)
else: else:
print('sigterm_psi_avg10 not in config\nExit') print('sigterm_psi_avg10 not in config\nExit')
exit() exit(1)
if 'min_badness' in config_dict: if 'min_badness' in config_dict:
@ -1282,13 +1365,13 @@ if 'min_badness' in config_dict:
config_dict['min_badness']) config_dict['min_badness'])
if min_badness is None: if min_badness is None:
print('Invalid min_badness value, not integer\nExit') print('Invalid min_badness value, not integer\nExit')
exit() exit(1)
if min_badness < 0 or min_badness > 1000: if min_badness < 0 or min_badness > 1000:
print('Invalud min_badness value\nExit') print('Invalud min_badness value\nExit')
exit() exit(1)
else: else:
print('min_badness not in config\nExit') print('min_badness not in config\nExit')
exit() exit(1)
if 'oom_score_adj_max' in config_dict: if 'oom_score_adj_max' in config_dict:
@ -1296,13 +1379,13 @@ if 'oom_score_adj_max' in config_dict:
config_dict['oom_score_adj_max']) config_dict['oom_score_adj_max'])
if oom_score_adj_max is None: if oom_score_adj_max is None:
print('Invalid oom_score_adj_max value, not integer\nExit') print('Invalid oom_score_adj_max value, not integer\nExit')
exit() exit(1)
if oom_score_adj_max < 0 or oom_score_adj_max > 1000: if oom_score_adj_max < 0 or oom_score_adj_max > 1000:
print('Invalid oom_score_adj_max value\nExit') print('Invalid oom_score_adj_max value\nExit')
exit() exit(1)
else: else:
print('oom_score_adj_max not in config\nExit') print('oom_score_adj_max not in config\nExit')
exit() exit(1)
if 'min_time_between_warnings' in config_dict: if 'min_time_between_warnings' in config_dict:
@ -1310,20 +1393,20 @@ if 'min_time_between_warnings' in config_dict:
config_dict['min_time_between_warnings']) config_dict['min_time_between_warnings'])
if min_time_between_warnings is None: if min_time_between_warnings is None:
print('Invalid min_time_between_warnings value, not float\nExit') print('Invalid min_time_between_warnings value, not float\nExit')
exit() exit(1)
if min_time_between_warnings < 1 or min_time_between_warnings > 300: if min_time_between_warnings < 1 or min_time_between_warnings > 300:
print('min_time_between_warnings value out of range [1; 300]\nExit') print('min_time_between_warnings value out of range [1; 300]\nExit')
exit() exit(1)
else: else:
print('min_time_between_warnings not in config\nExit') print('min_time_between_warnings not in config\nExit')
exit() exit(1)
if 'swap_min_warnings' in config_dict: if 'swap_min_warnings' in config_dict:
swap_min_warnings = config_dict['swap_min_warnings'] swap_min_warnings = config_dict['swap_min_warnings']
else: else:
print('swap_min_warnings not in config\nExit') print('swap_min_warnings not in config\nExit')
exit() exit(1)
########################################################################## ##########################################################################
@ -1344,12 +1427,12 @@ def get_swap_threshold_tuple(string):
valid = string_to_float_convert_test(string[:-1]) valid = string_to_float_convert_test(string[:-1])
if valid is None: if valid is None:
print('somewhere swap unit is not float_%') print('somewhere swap unit is not float_%')
exit() exit(1)
value = float(string[:-1].strip()) value = float(string[:-1].strip())
if value < 0 or value > 100: if value < 0 or value > 100:
print('invalid value, must be from the range[0; 100] %') print('invalid value, must be from the range[0; 100] %')
exit() exit(1)
return value, True return value, True
@ -1357,18 +1440,18 @@ def get_swap_threshold_tuple(string):
valid = string_to_float_convert_test(string[:-1]) valid = string_to_float_convert_test(string[:-1])
if valid is None: if valid is None:
print('somewhere swap unit is not float_M') print('somewhere swap unit is not float_M')
exit() exit(1)
value = float(string[:-1].strip()) * 1024 value = float(string[:-1].strip()) * 1024
if value < 0: if value < 0:
print('invalid unit in config (negative value)') print('invalid unit in config (negative value)')
exit() exit(1)
return value, False return value, False
else: else:
print('Invalid config file. There are invalid units somewhere\nExit') print('Invalid config file. There are invalid units somewhere\nExit')
exit() exit(1)
swap_min_sigterm_tuple = get_swap_threshold_tuple(swap_min_sigterm) swap_min_sigterm_tuple = get_swap_threshold_tuple(swap_min_sigterm)

View File

@ -4,7 +4,7 @@ After=sysinit.target
Documentation=man:nohang(1) https://github.com/hakavlad/nohang Documentation=man:nohang(1) https://github.com/hakavlad/nohang
[Service] [Service]
ExecStart=/usr/sbin/nohang ExecStart=/usr/sbin/nohang --config /etc/nohang/nohang.conf
Slice=nohang.slice Slice=nohang.slice
Restart=always Restart=always
ProtectSystem=strict ProtectSystem=strict