Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance ways that upsd/upsmon can send signals to their running siblings #1300

Merged
merged 15 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 54 additions & 6 deletions clients/upsmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@ static int parse_conf_arg(size_t numargs, char **arg)
}

/* RUN_AS_USER <userid> */
if (!strcmp(arg[0], "RUN_AS_USER")) {
if (!strcmp(arg[0], "RUN_AS_USER")) {
free(run_as_user);
run_as_user = xstrdup(arg[1]);
return 1;
Expand Down Expand Up @@ -1393,6 +1393,13 @@ static void loadconfig(void)
fatalx(EXIT_FAILURE, "%s", ctx.errmsg);
}

if (reload_flag == 1) {
/* if upsmon.conf added or changed
* (or commented away) the debug_min
* setting, detect that */
nut_debug_level_global = -1;
}

while (pconf_file_next(&ctx)) {
if (pconf_parse_error(&ctx)) {
upslogx(LOG_ERR, "Parse error: %s:%d: %s",
Expand All @@ -1419,6 +1426,15 @@ static void loadconfig(void)
}
}

if (reload_flag == 1) {
if (nut_debug_level_global > -1) {
upslogx(LOG_INFO,
"Applying debug_min=%d from upsmon.conf",
nut_debug_level_global);
nut_debug_level = nut_debug_level_global;
}
}

pconf_finish(&ctx);
}

Expand Down Expand Up @@ -1809,6 +1825,7 @@ static void help(const char *arg_progname)
printf(" - fsd: shutdown all primary-mode UPSes (use with caution)\n");
printf(" - reload: reread configuration\n");
printf(" - stop: stop monitoring and exit\n");
printf(" -P <pid> send the signal above to specified PID (bypassing PID file)\n");
printf(" -D raise debugging level (and stay foreground by default)\n");
printf(" -F stay foregrounded even if no debugging is enabled\n");
printf(" -B stay backgrounded even if debugging is bumped\n");
Expand Down Expand Up @@ -2042,7 +2059,8 @@ static void check_parent(void)
int main(int argc, char *argv[])
{
const char *prog = xbasename(argv[0]);
int i, cmd = 0, checking_flag = 0, foreground = -1;
int i, cmd = 0, cmdret = -1, checking_flag = 0, foreground = -1;
pid_t oldpid = -1;

printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);

Expand All @@ -2053,7 +2071,7 @@ int main(int argc, char *argv[])

run_as_user = xstrdup(RUN_AS_USER);

while ((i = getopt(argc, argv, "+DFBhic:f:pu:VK46")) != -1) {
while ((i = getopt(argc, argv, "+DFBhic:P:f:pu:VK46")) != -1) {
switch (i) {
case 'c':
if (!strncmp(optarg, "fsd", strlen(optarg)))
Expand All @@ -2067,6 +2085,12 @@ int main(int argc, char *argv[])
if (cmd == 0)
help(argv[0]);
break;

case 'P':
if ((oldpid = parsepid(optarg)) < 0)
help(argv[0]);
break;

case 'D':
nut_debug_level++;
break;
Expand Down Expand Up @@ -2121,17 +2145,41 @@ int main(int argc, char *argv[])
}

if (cmd) {
sendsignal(prog, cmd);
exit(EXIT_SUCCESS);
if (oldpid < 0) {
cmdret = sendsignal(prog, cmd);
} else {
cmdret = sendsignalpid(oldpid, cmd);
}
/* exit(EXIT_SUCCESS); */
exit((cmdret == 0)?EXIT_SUCCESS:EXIT_FAILURE);
}

/* otherwise, we are being asked to start.
* so check if a previous instance is running by sending signal '0'
* (Ie 'kill <pid> 0') */
if (sendsignal(prog, 0) == 0) {
if (oldpid < 0) {
cmdret = sendsignal(prog, 0);
} else {
cmdret = sendsignalpid(oldpid, 0);
}
switch (cmdret) {
case 0:
printf("Fatal error: A previous upsmon instance is already running!\n");
printf("Either stop the previous instance first, or use the 'reload' command.\n");
exit(EXIT_FAILURE);

case -3:
case -2:
upslogx(LOG_WARNING, "Could not %s PID file "
"to see if previous upsmon instance is "
"already running!\n",
(cmdret == -3 ? "find" : "parse"));
break;

case -1:
default:
/* Just failed to send signal, no competitor running */
break;
}

argc -= optind;
Expand Down
106 changes: 72 additions & 34 deletions common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ void writepid(const char *name)
pidf = fopen(fn, "w");

if (pidf) {
fprintf(pidf, "%d\n", (int) getpid());
intmax_t pid = (intmax_t)getpid();
upsdebugx(1, "Saving PID %jd into %s", pid, fn);
fprintf(pidf, "%jd\n", pid);
fclose(pidf);
} else {
upslog_with_errno(LOG_NOTICE, "writepid: fopen %s", fn);
Expand All @@ -302,61 +304,97 @@ void writepid(const char *name)
umask(mask);
}

/* open pidfn, get the pid, then send it sig */
int sendsignalfn(const char *pidfn, int sig)
/* send sig to pid, returns -1 for error, or
* zero for a successfully sent signal
*/
int sendsignalpid(pid_t pid, int sig)
{
char buf[SMALLBUF];
FILE *pidf;
pid_t pid = -1;
int ret;

pidf = fopen(pidfn, "r");
if (!pidf) {
upslog_with_errno(LOG_NOTICE, "fopen %s", pidfn);
if (pid < 2 || pid > get_max_pid_t()) {
upslogx(LOG_NOTICE,
"Ignoring invalid pid number %" PRIdMAX,
(intmax_t) pid);
return -1;
}

if (fgets(buf, sizeof(buf), pidf) == NULL) {
upslogx(LOG_NOTICE, "Failed to read pid from %s", pidfn);
fclose(pidf);
/* see if this is going to work first */
ret = kill(pid, 0);

if (ret < 0) {
perror("kill");
return -1;
}

{ /* scoping */
intmax_t _pid = strtol(buf, (char **)NULL, 10); /* assuming 10 digits for a long */
if (_pid <= get_max_pid_t()) {
pid = (pid_t)_pid;
} else {
upslogx(LOG_NOTICE, "Received a pid number too big for a pid_t: %" PRIdMAX, _pid);
if (sig != 0) {
/* now actually send it */
ret = kill(pid, sig);

if (ret < 0) {
perror("kill");
return -1;
}
}

if (pid < 2) {
upslogx(LOG_NOTICE, "Ignoring invalid pid number %" PRIdMAX, (intmax_t) pid);
fclose(pidf);
return -1;
return 0;
}

/* parses string buffer into a pid_t if it passes
* a few sanity checks; returns -1 on error
*/
pid_t parsepid(const char *buf)
{
pid_t pid = -1;

/* assuming 10 digits for a long */
intmax_t _pid = strtol(buf, (char **)NULL, 10);
if (_pid <= get_max_pid_t()) {
pid = (pid_t)_pid;
} else {
upslogx(LOG_NOTICE, "Received a pid number too big for a pid_t: %" PRIdMAX, _pid);
}

/* see if this is going to work first */
ret = kill(pid, 0);
return pid;
}

if (ret < 0) {
perror("kill");
/* open pidfn, get the pid, then send it sig
* returns negative codes for errors, or
* zero for a successfully sent signal
*/
int sendsignalfn(const char *pidfn, int sig)
{
char buf[SMALLBUF];
FILE *pidf;
pid_t pid = -1;
int ret = -1;

pidf = fopen(pidfn, "r");
if (!pidf) {
upslog_with_errno(LOG_NOTICE, "fopen %s", pidfn);
return -3;
}

if (fgets(buf, sizeof(buf), pidf) == NULL) {
upslogx(LOG_NOTICE, "Failed to read pid from %s", pidfn);
fclose(pidf);
return -1;
return -2;
}
/* TOTHINK: Original code only closed pidf before
* exiting the method, on error or "normally".
* Why not here? Do we want an (exclusive?) hold
* on it while being active in the method?
*/

/* now actually send it */
ret = kill(pid, sig);
/* this method actively reports errors, if any */
pid = parsepid(buf);

if (ret < 0) {
perror("kill");
fclose(pidf);
return -1;
if (pid >= 0) {
/* this method actively reports errors, if any */
ret = sendsignalpid(pid, sig);
}

fclose(pidf);
return 0;
return ret;
}

int snprintfcat(char *dst, size_t size, const char *fmt, ...)
Expand Down
11 changes: 11 additions & 0 deletions conf/upsd.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,14 @@
# running mode directly, and without need to edit init-scripts or service
# unit definitions. Note that command-line option `-D` can only increase
# this verbosity level.
#
# NOTE: if the running daemon receives a `reload` command, presence of the
# `DEBUG_MIN NUMBER` value in the configuration file can be used to tune
# debugging verbosity in the running service daemon (it is recommended to
# comment it away or set the minimum to explicit zero when done, to avoid
# huge journals and I/O system abuse). Keep in mind that for this run-time
# tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
# is applied instantly and overrides any previously set value, from file
# or CLI options, regardless of older logging level being higher or lower
# than the newly found number; a missing (or commented away) value however
# does not change the previously active logging verbosity.
11 changes: 11 additions & 0 deletions conf/upsmon.conf.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,14 @@ FINALDELAY 5
# running mode directly, and without need to edit init-scripts or service
# unit definitions. Note that command-line option `-D` can only increase
# this verbosity level.
#
# NOTE: if the running daemon receives a `reload` command, presence of the
# `DEBUG_MIN NUMBER` value in the configuration file can be used to tune
# debugging verbosity in the running service daemon (it is recommended to
# comment it away or set the minimum to explicit zero when done, to avoid
# huge journals and I/O system abuse). Keep in mind that for this run-time
# tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
# is applied instantly and overrides any previously set value, from file
# or CLI options, regardless of older logging level being higher or lower
# than the newly found number; a missing (or commented away) value however
# does not change the previously active logging verbosity.
11 changes: 11 additions & 0 deletions docs/man/upsd.conf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ Optionally specify a minimum debug level for `upsd` data daemon, e.g. for
troubleshooting a deployment, without impacting foreground or background
running mode directly. Command-line option `-D` can only increase this
verbosity level.
+
NOTE: if the running daemon receives a `reload` command, presence of the
`DEBUG_MIN NUMBER` value in the configuration file can be used to tune
debugging verbosity in the running service daemon (it is recommended to
comment it away or set the minimum to explicit zero when done, to avoid
huge journals and I/O system abuse). Keep in mind that for this run-time
tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
is applied instantly and overrides any previously set value, from file
or CLI options, regardless of older logging level being higher or lower
than the newly found number; a missing (or commented away) value however
does not change the previously active logging verbosity.

SEE ALSO
--------
Expand Down
7 changes: 7 additions & 0 deletions docs/man/upsd.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,20 @@ are:
*reload*;; reread configuration files
*stop*;; stop process and exit

*-P* 'pid'::
Send the command signal above using specified PID number, rather than
consulting the PID file. This can help define service units which
start `upsd` as a foreground process so it does not create a PID file.
See also `-FF` option as an alternative.

*-D*::
Raise the debugging level. upsd will run in the foreground by default,
and will print information on stdout about the monitoring process.
Use this option multiple times for more details.

*-F*::
upsd will run in the foreground, regardless of debugging settings.
Specify twice (`-FF` or `-F -F`) to save the PID file even in this mode.

*-B*::
upsd will run in the background, regardless of debugging settings.
Expand Down
11 changes: 11 additions & 0 deletions docs/man/upsmon.conf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,17 @@ Optionally specify a minimum debug level for `upsmon` daemon, e.g. for
troubleshooting a deployment, without impacting foreground or background
running mode directly. Command-line option `-D` can only increase this
verbosity level.
+
NOTE: if the running daemon receives a `reload` command, presence of the
`DEBUG_MIN NUMBER` value in the configuration file can be used to tune
debugging verbosity in the running service daemon (it is recommended to
comment it away or set the minimum to explicit zero when done, to avoid
huge journals and I/O system abuse). Keep in mind that for this run-time
tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
is applied instantly and overrides any previously set value, from file
or CLI options, regardless of older logging level being higher or lower
than the newly found number; a missing (or commented away) value however
does not change the previously active logging verbosity.

SEE ALSO
--------
Expand Down
8 changes: 7 additions & 1 deletion docs/man/upsmon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ SYNOPSIS

*upsmon* -h

*upsmon* -c 'command'
*upsmon* -c 'command' [-P 'pid']

*upsmon* [-D] [-F | -B] [-K] [-p] [-u 'user']

Expand Down Expand Up @@ -44,6 +44,12 @@ commands are:
*reload*;; reread linkman:upsmon.conf[5] configuration file. See
"reloading nuances" below if this doesn't work.

*-P* 'pid'::
Send the command signal above using specified PID number, rather than
consulting the PID file. This can help define service units which
start main `upsmon` as a foreground process so it does not have to
rely on a PID file.

*-D*::
Raise the debugging level. upsmon will run in the foreground by default,
and will print information on stdout about the monitoring process.
Expand Down