[PATCH] Notify when finished
Harkaitz Agirre
harkaitz.aguirre at gmail.com
Mon Aug 26 14:19:21 UTC 2024
On Mon, 26 Aug 2024 14:00:29 +0000
Yao Zi <ziyao at disroot.org> wrote:
> On Mon, Aug 26, 2024 at 02:46:48PM +0200, Harkaitz Agirre wrote:
> > This patch introduces the "notify me when finished" feature in
> > Busybox Shell.
> >
> > When executing long-running commands (such as compiling code or
> > performing backups), it can be useful to receive notifications when
> > these tasks finish.
> >
> > This allows the user to step away from the terminal, perhaps to
> > grab a coffee.
> >
> > The need for a notification is usually an afterthought, so it is not
> > practical to add a prefix to the commands in order to being
> > notified when finished. Instead, it is more convenient to have a
> > mechanism that automatically alerts the user when a command takes
> > longer than expected.
> >
> > This change makes ash read two variables, TIMED_ALERT and
> > TIMED_ALERT_SECS.
> >
> > If a command execution exceeds the time specified in
> > $TIMED_ALERT_SECS (by default 60 seconds) executes the command in
> > $TIMED_ALERT (if set).
> >
> > The command in $TIMED_ALERT can consult
> > $TIMED_COMMAND,$TIMED_COMMAND_DURATION and $? to prepare the
> > message to send.
> >
> > One example:
> >
> > $ export TIMED_ALERT='notify-send "Command finished" "Command
> > $TIMED_COMMAND finished in $TIMED_COMMAND_DURATION seconds with
> > exit status $?"' $ export TIMED_ALERT_SECS=10
> >
> > Services like ntfy.sh etc can be used to notify the phone.
> > ---
> > shell/ash.c | 83
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file
> > changed, 82 insertions(+), 1 deletion(-)
> >
> > diff --git a/shell/ash.c b/shell/ash.c
> > index bbd730770..a764f6131 100644
> > --- a/shell/ash.c
> > +++ b/shell/ash.c
> > @@ -119,6 +119,18 @@
> > //config: are checked for mtime changes, and "you have mail"
> > //config: message is printed if change is detected.
> > //config:
> > +//config:config ASH_TIMED_ALERT
> > +//config: bool "Enable notify when finished feature"
> > +//config: default y
> > +//config: depends on SHELL_ASH
> > +//config: help
> > +//config: Enable "notify when finished" function:
> > +//config: if set, if $TIMED_ALERT is set and a command lasts
> > +//config: longer that $TIMED_ALERT_SECS (by default 60) then
> > +//config: the command in $TIMED_ALERT is executed. The
> > command +//config: and it's duration can be fetched
> > consulting $TIMED_COMMAND +//config: ,
> > $TIMED_COMMAND_DURATION and $?. +//config:
> > //config:config ASH_ECHO
> > //config: bool "echo builtin"
> > //config: default y
> > @@ -2134,6 +2146,10 @@ change_lc_ctype(const char *value)
> > static void changemail(const char *var_value) FAST_FUNC;
> > #endif
> > static void changepath(const char *) FAST_FUNC;
> > +#if ENABLE_ASH_TIMED_ALERT
> > +static void change_timed_alert(const char *) FAST_FUNC;
> > +static void change_timed_alert_secs(const char *) FAST_FUNC;
> > +#endif
> > #if ENABLE_ASH_RANDOM_SUPPORT
> > static void change_random(const char *) FAST_FUNC;
> > #endif
> > @@ -2155,6 +2171,10 @@ static const struct {
> > #if ENABLE_ASH_MAIL
> > { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail
> > }, { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
> > +#endif
> > +#if ENABLE_ASH_TIMED_ALERT
> > + { VSTRFIXED|VTEXTFIXED|VUNSET, "TIMED_ALERT" ,
> > change_timed_alert },
> > + { VSTRFIXED|VTEXTFIXED|VUNSET, "TIMED_ALERT_SECS",
> > change_timed_alert_secs}, #endif
> > { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path,
> > changepath }, { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL
> > }, @@ -2214,7 +2234,7 @@ extern struct globals_var
> > *BB_GLOBAL_CONST ash_ptr_to_globals_var; # define vmail
> > varinit[1] # define vmpath varinit[2]
> > #endif
> > -#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
> > +#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2+ENABLE_ASH_TIMED_ALERT*2)
> > #define vpath varinit[VAR_OFFSET1 + 1]
> > #define vps1 varinit[VAR_OFFSET1 + 2]
> > #define vps2 varinit[VAR_OFFSET1 + 3]
> > @@ -9464,6 +9484,63 @@ evaltree(union node *n, int flags)
> > return exitstatus;
> > }
> >
> > +#if ENABLE_ASH_TIMED_ALERT
> > +
> > +static const char *timed_alert = NULL;
> > +static long timed_alert_secs = 60;
> > +
> > +static void FAST_FUNC
> > +change_timed_alert(const char *val)
> > +{
> > + timed_alert = val;
> > +}
> > +
> > +static void FAST_FUNC
> > +change_timed_alert_secs(const char *val)
> > +{
> > + long l = atol(val);
> > + if (l > 0)
> > + timed_alert_secs = l;
> > +}
>
> It may be better to disable the alert if an invalid timeout duration
> is given, instead of keeping the original value.
>
> > +
> > +/*
> > + * Evaluate a parse tree. The value is left in the global variable
> > + * exitstatus.
> > + */
> > +static int
> > +evaltree_with_timed_alert(union node *n, int flags)
> > +{
> > + time_t command_start_time, command_end_time,
> > command_duration;
> > + int result;
> > +
>
> There are some trailing spaces. Is it an editor issue? You should
> remove them.
>
> > + if (!iflag || !timed_alert || !timed_alert[0]) {
> > + return evaltree(n, flags);
> > + }
> > +
> > + command_start_time = time(NULL);
> > + result = evaltree(n, flags);
> > + command_end_time = time(NULL);
> > +
> > + command_duration = command_end_time - command_start_time;
> > +
> > + if (command_duration >= timed_alert_secs) {
> > + if (g_parsefile->next_to_pgetc > g_parsefile->buf
> > && g_parsefile->next_to_pgetc[-1] == '\n') {
> > + g_parsefile->next_to_pgetc[-1] = '\0';
> > + } else {
> > + *g_parsefile->next_to_pgetc = '\0';
> > + }
> > + setvar("TIMED_COMMAND", g_parsefile->buf, VEXPORT);
> > + setvar("TIMED_COMMAND_DURATION",
> > utoa(command_duration), VEXPORT);
> > + evalstring(timed_alert, 0);
> > + unsetvar("TIMED_COMMAND");
> > + unsetvar("TIMED_COMMAND_DURATION");
> > + }
> > +
> > + return result;
> > +}
> > +
> > +#endif
> > +
> > static int
> > skiploop(void)
> > {
> > @@ -13641,7 +13718,11 @@ cmdloop(int top)
> > /* job_warning can only be 2,1,0. Here
> > 2->1, 1/0->0 */ job_warning >>= 1;
> > numeof = 0;
> > +#if ENABLE_ASH_TIMED_ALERT
> > + i = evaltree_with_timed_alert(n, 0);
> > +#else
> > i = evaltree(n, 0);
> > +#endif
> > if (n)
> > status = i;
> > }
> > --
> > 2.39.2
> >
>
> I doubt whether this function is valuable enough to be implemented in
> shell. Users could simply use a script to notify themselves when
> running a long script/command.
>
> afaik, even bash doesn't have similar functions by default and I don't
> think busybox ash is the correct place to implement rich interactive
> functions. Things should be done in another way here.
>
> Best regards,
> Yao Zi
Thank you for your suggestions and time,
I agree with the changes you propose to the code.
As I explained to Laurent the point here is that the need for
the notification is usually an afterthought, nearly always I
realize the need for the notification after I the command is
already running.
I already sent a patch to the Bash developers, I implemented this
for both bash and busybox long time ago.
Harkaitz
More information about the busybox
mailing list