* [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
@ 2014-07-07 7:31 Stef Walter
2014-07-14 13:37 ` Karel Zak
2014-07-15 7:47 ` Karel Zak
0 siblings, 2 replies; 10+ messages in thread
From: Stef Walter @ 2014-07-07 7:31 UTC (permalink / raw)
To: util-linux; +Cc: Stef Walter
Several of the /etc/issue escape codes such as \4 and \S depend on
variable data which can change after the agetty prompt is displayed.
This can cause stale data to be displayed when a user looks at a VT,
especially in cases of DHCP racing with system start up.
This commit allows agetty to react a SIGUSR1 signal by reprinting
its prompt including the reprocessing of /etc/issue.
We never want this to occur once the user has started typing a
user name. So we detect when the user starts typing, after which
no further reprompting occurs even if SIGUSR1 is received.
Signed-off-by: Stef Walter <stefw@redhat.com>
---
term-utils/agetty.8 | 9 +++++-
term-utils/agetty.c | 86 +++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 81 insertions(+), 14 deletions(-)
diff --git a/term-utils/agetty.8 b/term-utils/agetty.8
index 27a0d1b..b11dd4b 100644
--- a/term-utils/agetty.8
+++ b/term-utils/agetty.8
@@ -385,7 +385,14 @@ displays as:
This is thingol.orcan.dk (Linux i386 1.1.9) 18:29:30
.fi
.RE
-
+.SH SIGNALS
+Upon receiving
+.BR SIGUSR1
+.BR agetty
+will reprint the
+.B /etc/issue
+(if so configured) and login prompt. It will do this unless the
+user has started typing a login name.
.SH FILES
.na
.TP
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index 2b5932d..3e38107 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -270,6 +270,7 @@ static char *get_logname(struct options *op,
struct termios *tp, struct chardata *cp);
static void termio_final(struct options *op,
struct termios *tp, struct chardata *cp);
+static void sig_usr1_handler(int sig);
static int caps_lock(char *s);
static speed_t bcode(char *s);
static void usage(FILE * out) __attribute__((__noreturn__));
@@ -285,6 +286,9 @@ static int plymouth_command(const char* arg);
/* Fake hostname for ut_host specified on command line. */
static char *fakehost;
+/* Indicates whether we've been asked (via a signal) to reprompt */
+static int reprompt_flag;
+
#ifdef DEBUGGING
# include "closestream.h"
# ifndef DEBUG_OUTPUT
@@ -309,7 +313,7 @@ int main(int argc, char **argv)
};
char *login_argv[LOGIN_ARGV_MAX + 1];
int login_argc = 0;
- struct sigaction sa, sa_hup, sa_quit, sa_int;
+ struct sigaction sa, sa_hup, sa_quit, sa_int, sa_usr1;
sigset_t set;
setlocale(LC_ALL, "");
@@ -324,6 +328,12 @@ int main(int argc, char **argv)
sigaction(SIGQUIT, &sa, &sa_quit);
sigaction(SIGINT, &sa, &sa_int);
+ /* Signal to restart prompting */
+ memset(&sa_usr1, 0, sizeof (sa_usr1));
+ sa_usr1.sa_handler = sig_usr1_handler;
+ sigemptyset (&sa_usr1.sa_mask);
+ sigaction(SIGUSR1, &sa_usr1, NULL);
+
#ifdef DEBUGGING
dbf = fopen(DEBUG_OUTPUT, "w");
for (int i = 1; i < argc; i++) {
@@ -824,6 +834,11 @@ static void parse_args(int argc, char **argv, struct options *op)
debug("exiting parseargs\n");
}
+static void sig_usr1_handler(int sig)
+{
+ reprompt_flag = sig;
+}
+
/* Parse alternate baud rates. */
static void parse_speeds(struct options *op, char *arg)
{
@@ -1114,6 +1129,21 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
}
/* Initialize termios settings. */
+static void termio_clear(int fd)
+{
+ /*
+ * Do not write a full reset (ESC c) because this destroys
+ * the unicode mode again if the terminal was in unicode
+ * mode. Also it clears the CONSOLE_MAGIC features which
+ * are required for some languages/console-fonts.
+ * Just put the cursor to the home position (ESC [ H),
+ * erase everything below the cursor (ESC [ J), and set the
+ * scrolling region to the full window (ESC [ r)
+ */
+ write_all(fd, "\033[r\033[H\033[J", 9);
+}
+
+/* Initialize termios settings. */
static void termio_init(struct options *op, struct termios *tp)
{
speed_t ispeed, ospeed;
@@ -1166,18 +1196,8 @@ static void termio_init(struct options *op, struct termios *tp)
if ((tp->c_cflag & (CS8|PARODD|PARENB)) == CS8)
op->flags |= F_EIGHTBITS;
- if ((op->flags & F_NOCLEAR) == 0) {
- /*
- * Do not write a full reset (ESC c) because this destroys
- * the unicode mode again if the terminal was in unicode
- * mode. Also it clears the CONSOLE_MAGIC features which
- * are required for some languages/console-fonts.
- * Just put the cursor to the home position (ESC [ H),
- * erase everything below the cursor (ESC [ J), and set the
- * scrolling region to the full window (ESC [ r)
- */
- write_all(STDOUT_FILENO, "\033[r\033[H\033[J", 9);
- }
+ if ((op->flags & F_NOCLEAR) == 0)
+ termio_clear(STDOUT_FILENO);
return;
}
@@ -1593,6 +1613,37 @@ static void next_speed(struct options *op, struct termios *tp)
tcsetattr(STDIN_FILENO, TCSANOW, tp);
}
+static int wait_for_term_input(int fd)
+{
+ struct termios orig, nonc;
+ char input[32];
+ int count;
+ int i;
+
+ /* Our aim here is to fall through if something fails
+ * and not be stuck waiting. On failure assume we have input */
+
+ if (tcgetattr(fd, &orig) != 0)
+ return 1;
+
+ memcpy(&nonc, &orig, sizeof (nonc));
+ nonc.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHOKE);
+ nonc.c_cc[VMIN] = 1;
+ nonc.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSANOW, &nonc) != 0)
+ return 1;
+
+ count = read(fd, input, sizeof (input));
+ tcsetattr(fd, TCSANOW, &orig);
+
+ /* Reinject the bytes we read back into the buffer */
+ for (i = 0; i < count; i++)
+ ioctl(fd, TIOCSTI, input + i);
+
+ return count > 0;
+}
+
/* Get user name, establish parity, speed, erase, kill & eol. */
static char *get_logname(struct options *op, struct termios *tp, struct chardata *cp)
{
@@ -1625,9 +1676,18 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
while (*logname == '\0') {
+ reprompt_flag = 0;
+
/* Write issue file and prompt */
do_prompt(op, tp);
+ /* If asked to reprompt *before* terminal input arrives, then do so */
+ if (!wait_for_term_input(STDIN_FILENO) && reprompt_flag != 0) {
+ if (op->flags & F_VCONSOLE)
+ termio_clear(STDOUT_FILENO);
+ continue;
+ }
+
cp->eol = '\0';
/* Read name, watch for break and end-of-line. */
--
1.9.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-07 7:31 [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1 Stef Walter
@ 2014-07-14 13:37 ` Karel Zak
2014-07-15 7:35 ` Stef Walter
2014-07-15 7:47 ` Karel Zak
1 sibling, 1 reply; 10+ messages in thread
From: Karel Zak @ 2014-07-14 13:37 UTC (permalink / raw)
To: Stef Walter; +Cc: util-linux
On Mon, Jul 07, 2014 at 09:31:24AM +0200, Stef Walter wrote:
> Several of the /etc/issue escape codes such as \4 and \S depend on
> variable data which can change after the agetty prompt is displayed.
> This can cause stale data to be displayed when a user looks at a VT,
> especially in cases of DHCP racing with system start up.
>
> This commit allows agetty to react a SIGUSR1 signal by reprinting
> its prompt including the reprocessing of /etc/issue.
>
> We never want this to occur once the user has started typing a
> user name. So we detect when the user starts typing, after which
> no further reprompting occurs even if SIGUSR1 is received.
Good idea, interesting implementation, but it's too late for v2.25.
I'm going to apply the patch to the git tree after v2.25 release.
Thanks.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-14 13:37 ` Karel Zak
@ 2014-07-15 7:35 ` Stef Walter
2014-07-15 7:51 ` Karel Zak
0 siblings, 1 reply; 10+ messages in thread
From: Stef Walter @ 2014-07-15 7:35 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux
On 14.07.2014 15:37, Karel Zak wrote:
> On Mon, Jul 07, 2014 at 09:31:24AM +0200, Stef Walter wrote:
>> Several of the /etc/issue escape codes such as \4 and \S depend on
>> variable data which can change after the agetty prompt is displayed.
>> This can cause stale data to be displayed when a user looks at a VT,
>> especially in cases of DHCP racing with system start up.
>>
>> This commit allows agetty to react a SIGUSR1 signal by reprinting
>> its prompt including the reprocessing of /etc/issue.
>>
>> We never want this to occur once the user has started typing a
>> user name. So we detect when the user starts typing, after which
>> no further reprompting occurs even if SIGUSR1 is received.
>
> Good idea, interesting implementation, but it's too late for v2.25.
> I'm going to apply the patch to the git tree after v2.25 release.
Nice. Thanks.
Lennart discovered an issue with this ...
That the exec'ing the login process might race with the SIGUSR1 signal.
The fix here would be to signal(SIGUSR1, SIG_IGN) before exec'ing, does
that sound appropriate? I can post a new patch.
By the way, more information about this use case here:
https://bugzilla.redhat.com/show_bug.cgi?id=1110763
Also, on the use of SIGUSR1 ... often linux daemons like to use SIGHUP
as a 'reload' signal. But obviously this signal already has specific
meaning in the agetty case, hence the choice of SIGUSR1.
Cheers,
Stef
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-07 7:31 [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1 Stef Walter
2014-07-14 13:37 ` Karel Zak
@ 2014-07-15 7:47 ` Karel Zak
2014-07-15 7:57 ` Stef Walter
1 sibling, 1 reply; 10+ messages in thread
From: Karel Zak @ 2014-07-15 7:47 UTC (permalink / raw)
To: Stef Walter; +Cc: util-linux
On Mon, Jul 07, 2014 at 09:31:24AM +0200, Stef Walter wrote:
> /* Get user name, establish parity, speed, erase, kill & eol. */
> static char *get_logname(struct options *op, struct termios *tp, struct chardata *cp)
> {
> @@ -1625,9 +1676,18 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
>
> while (*logname == '\0') {
>
> + reprompt_flag = 0;
> +
> /* Write issue file and prompt */
> do_prompt(op, tp);
>
> + /* If asked to reprompt *before* terminal input arrives, then do so */
> + if (!wait_for_term_input(STDIN_FILENO) && reprompt_flag != 0) {
> + if (op->flags & F_VCONSOLE)
> + termio_clear(STDOUT_FILENO);
> + continue;
> + }
Now when I think about it.. would be better to have this feature
optional? I think it's overkill to have it enabled on all machines.
The another story is the signal usage (and possible race with login(1) as
discussed at https://bugzilla.redhat.com/show_bug.cgi?id=1110763).
What about for example:
agetty --reload-trigger <file>
and use inotify for the <file>. I guess this way also allows to avoid
the ioctl() tty voodoo and you can use select() for the inotify and
tty file descriptors.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 7:35 ` Stef Walter
@ 2014-07-15 7:51 ` Karel Zak
0 siblings, 0 replies; 10+ messages in thread
From: Karel Zak @ 2014-07-15 7:51 UTC (permalink / raw)
To: Stef Walter; +Cc: util-linux
On Tue, Jul 15, 2014 at 09:35:55AM +0200, Stef Walter wrote:
> On 14.07.2014 15:37, Karel Zak wrote:
> > On Mon, Jul 07, 2014 at 09:31:24AM +0200, Stef Walter wrote:
> >> Several of the /etc/issue escape codes such as \4 and \S depend on
> >> variable data which can change after the agetty prompt is displayed.
> >> This can cause stale data to be displayed when a user looks at a VT,
> >> especially in cases of DHCP racing with system start up.
> >>
> >> This commit allows agetty to react a SIGUSR1 signal by reprinting
> >> its prompt including the reprocessing of /etc/issue.
> >>
> >> We never want this to occur once the user has started typing a
> >> user name. So we detect when the user starts typing, after which
> >> no further reprompting occurs even if SIGUSR1 is received.
> >
> > Good idea, interesting implementation, but it's too late for v2.25.
> > I'm going to apply the patch to the git tree after v2.25 release.
>
> Nice. Thanks.
I have never seen the idea with VMIN and TIOCSTI ioctl, that's
interesting thing.
> Lennart discovered an issue with this ...
>
> That the exec'ing the login process might race with the SIGUSR1 signal.
> The fix here would be to signal(SIGUSR1, SIG_IGN) before exec'ing, does
> that sound appropriate? I can post a new patch.
>
> By the way, more information about this use case here:
> https://bugzilla.redhat.com/show_bug.cgi?id=1110763
Yes, I read it yesterday evening. Lennart is right about the race.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 7:47 ` Karel Zak
@ 2014-07-15 7:57 ` Stef Walter
2014-07-15 9:19 ` Karel Zak
0 siblings, 1 reply; 10+ messages in thread
From: Stef Walter @ 2014-07-15 7:57 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux
On 15.07.2014 09:47, Karel Zak wrote:
> On Mon, Jul 07, 2014 at 09:31:24AM +0200, Stef Walter wrote:
>> /* Get user name, establish parity, speed, erase, kill & eol. */
>> static char *get_logname(struct options *op, struct termios *tp, struct chardata *cp)
>> {
>> @@ -1625,9 +1676,18 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
>>
>> while (*logname == '\0') {
>>
>> + reprompt_flag = 0;
>> +
>> /* Write issue file and prompt */
>> do_prompt(op, tp);
>>
>> + /* If asked to reprompt *before* terminal input arrives, then do so */
>> + if (!wait_for_term_input(STDIN_FILENO) && reprompt_flag != 0) {
>> + if (op->flags & F_VCONSOLE)
>> + termio_clear(STDOUT_FILENO);
>> + continue;
>> + }
>
> Now when I think about it.. would be better to have this feature
> optional? I think it's overkill to have it enabled on all machines.
Sure.
> The another story is the signal usage (and possible race with login(1) as
> discussed at https://bugzilla.redhat.com/show_bug.cgi?id=1110763).
>
> What about for example:
>
> agetty --reload-trigger <file>
As I said in the above bugzilla bug, I don't mind doing this ... but in
my opinion unix signals are meant exactly for this use case, and are
used by many (most?) other linx processes as a reload trigger.
> and use inotify for the <file>. I guess this way also allows to avoid
> the ioctl() tty voodoo and you can use select() for the inotify and
> tty file descriptors.
Unfortunately that's not how it works. When in canonical mode, the tty
file descriptor only becomes readable once a complete line has been
entered. I've verified that select() does not return until <enter> is
pressed.
Hence the switch to non-canonical mode, until the first character is
pressed, and then back to canonical.
Cheers,
Stef
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 7:57 ` Stef Walter
@ 2014-07-15 9:19 ` Karel Zak
2014-07-15 12:40 ` Stef Walter
0 siblings, 1 reply; 10+ messages in thread
From: Karel Zak @ 2014-07-15 9:19 UTC (permalink / raw)
To: Stef Walter; +Cc: util-linux
On Tue, Jul 15, 2014 at 09:57:12AM +0200, Stef Walter wrote:
> On 15.07.2014 09:47, Karel Zak wrote:
> > Now when I think about it.. would be better to have this feature
> > optional? I think it's overkill to have it enabled on all machines.
>
> Sure.
>
> > The another story is the signal usage (and possible race with login(1) as
> > discussed at https://bugzilla.redhat.com/show_bug.cgi?id=1110763).
> >
> > What about for example:
> >
> > agetty --reload-trigger <file>
>
> As I said in the above bugzilla bug, I don't mind doing this ... but in
> my opinion unix signals are meant exactly for this use case, and are
> used by many (most?) other linx processes as a reload trigger.
Yes, it's pretty common classic solution, but I think that in this
case it is not too robust solution.
> > and use inotify for the <file>. I guess this way also allows to avoid
> > the ioctl() tty voodoo and you can use select() for the inotify and
> > tty file descriptors.
>
> Unfortunately that's not how it works. When in canonical mode, the tty
> file descriptor only becomes readable once a complete line has been
> entered. I've verified that select() does not return until <enter> is
> pressed.
Ah.. good point, but with non-canonical mode it works as expected,
right? So, we can use fd with VMIN=1 and inotify fd for the select().
Maybe the best would be to implement all within agetty, I mean add
a special command
agetty --reload [<tty>]
to reload another already running agetty process(es). So rather than
"killall agetty" you have to use "agetty --reload".
Then all the implementation will be a private thing and only the "--reload"
command line option will be a public API.
Note that we does not control code of all login(1) implementations
and we have --login-program <path> to start arbitrary random thing
from agetty, so our solution have to be generic rather than rely
on any login(1) change.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 9:19 ` Karel Zak
@ 2014-07-15 12:40 ` Stef Walter
2014-07-15 16:12 ` Stef Walter
2014-07-16 10:02 ` Karel Zak
0 siblings, 2 replies; 10+ messages in thread
From: Stef Walter @ 2014-07-15 12:40 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux
On 15.07.2014 11:19, Karel Zak wrote:
> On Tue, Jul 15, 2014 at 09:57:12AM +0200, Stef Walter wrote:
>> On 15.07.2014 09:47, Karel Zak wrote:
>>> Now when I think about it.. would be better to have this feature
>>> optional? I think it's overkill to have it enabled on all machines.
>>
>> Sure.
>>
>>> The another story is the signal usage (and possible race with login(1) as
>>> discussed at https://bugzilla.redhat.com/show_bug.cgi?id=1110763).
>>>
>>> What about for example:
>>>
>>> agetty --reload-trigger <file>
>>
>> As I said in the above bugzilla bug, I don't mind doing this ... but in
>> my opinion unix signals are meant exactly for this use case, and are
>> used by many (most?) other linx processes as a reload trigger.
>
> Yes, it's pretty common classic solution, but I think that in this
> case it is not too robust solution.
>
>>> and use inotify for the <file>. I guess this way also allows to avoid
>>> the ioctl() tty voodoo and you can use select() for the inotify and
>>> tty file descriptors.
>>
>> Unfortunately that's not how it works. When in canonical mode, the tty
>> file descriptor only becomes readable once a complete line has been
>> entered. I've verified that select() does not return until <enter> is
>> pressed.
>
> Ah.. good point, but with non-canonical mode it works as expected,
> right? So, we can use fd with VMIN=1 and inotify fd for the select().
Yup.
> Maybe the best would be to implement all within agetty, I mean add
> a special command
>
> agetty --reload [<tty>]
>
> to reload another already running agetty process(es). So rather than
> "killall agetty" you have to use "agetty --reload".
>
> Then all the implementation will be a private thing and only the "--reload"
> command line option will be a public API.
Okay. I'll work on this and keep you posted.
> Note that we does not control code of all login(1) implementations
> and we have --login-program <path> to start arbitrary random thing
> from agetty, so our solution have to be generic rather than rely
> on any login(1) change.
Well you don't need to modify login(1) (or other --login-program's) at
all. SIG_IGN is kept across an exec.
Stef
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 12:40 ` Stef Walter
@ 2014-07-15 16:12 ` Stef Walter
2014-07-16 10:02 ` Karel Zak
1 sibling, 0 replies; 10+ messages in thread
From: Stef Walter @ 2014-07-15 16:12 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux
[-- Attachment #1: Type: text/plain, Size: 916 bytes --]
On 15.07.2014 14:40, Stef Walter wrote:
> On 15.07.2014 11:19, Karel Zak wrote:
>> Maybe the best would be to implement all within agetty, I mean add
>> a special command
>>
>> agetty --reload [<tty>]
>>
>> to reload another already running agetty process(es). So rather than
>> "killall agetty" you have to use "agetty --reload".
>>
>> Then all the implementation will be a private thing and only the "--reload"
>> command line option will be a public API.
>
> Okay. I'll work on this and keep you posted.
Attached is the updated patch.
The current patch implements --reload. We use inotify on a path in /run
to signal the process. We don't create the file initially until does a
--reload.
Note that I didn't implement the [<tty>] option. It seems like it would
need inotify track multiple files, and as such be prone to races, when
trying to signal all agetty processes.
What do you think?
Stef
[-- Attachment #2: 0001-agetty-Reprompt-and-reprint-etc-issue-when-asked.patch --]
[-- Type: text/x-patch, Size: 8279 bytes --]
>From 33583bff1b4dfb3dcff582d1dec9f4005e8bdafd Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@redhat.com>
Date: Thu, 3 Jul 2014 17:44:41 +0200
Subject: [PATCH] agetty: Reprompt and reprint /etc/issue when asked
Add an 'agetty --reload' command which asks all running agetty
commands to display their prompts again.
Several of the /etc/issue escape codes such as \4 and \S depend on
variable data which can change after the agetty prompt is displayed.
This can cause stale data to be displayed when a user looks at a VT,
especially in cases of DHCP racing with system start up.
We never want this to occur once the user has started typing a
user name. So we detect when the user starts typing, after which
no further reprompting occurs after that point.
Signed-off-by: Stef Walter <stefw@redhat.com>
---
term-utils/agetty.8 | 5 +++
term-utils/agetty.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 119 insertions(+), 12 deletions(-)
diff --git a/term-utils/agetty.8 b/term-utils/agetty.8
index 27a0d1b..c997129 100644
--- a/term-utils/agetty.8
+++ b/term-utils/agetty.8
@@ -252,6 +252,11 @@ Sleep seconds before open tty.
\-\-nice \fInumber\fP
Run login with this priority.
.TP
+\-\-reload
+Ask all running agetty instances to reload and update their displayed prompts,
+if the user has not yet commenced logging in. After doing so the command will
+exit.
+.TP
\-\-version
Display version information and exit.
.TP
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index 2b5932d..d92da80 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -18,6 +18,7 @@
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
+#include <sys/inotify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -112,6 +113,9 @@
#define LOGIN "login: "
#define LOGIN_ARGV_MAX 16 /* Numbers of args for login */
+/* Reload trigger file */
+#define GETTY_RELOAD_TRIGGER "/run/agetty.reload"
+
/*
* When multiple baud rates are specified on the command line, the first one
* we will try is the first one specified.
@@ -281,10 +285,14 @@ static ssize_t append(char *dest, size_t len, const char *sep, const char *src)
static void check_username (const char* nm);
static void login_options_to_argv(char *argv[], int *argc, char *str, char *username);
static int plymouth_command(const char* arg);
+static void reload_agettys(void);
/* Fake hostname for ut_host specified on command line. */
static char *fakehost;
+/* Indicates whether we've been asked (via a signal) to reprompt */
+static int inotify_fd = -1;
+
#ifdef DEBUGGING
# include "closestream.h"
# ifndef DEBUG_OUTPUT
@@ -334,6 +342,10 @@ int main(int argc, char **argv)
debug("\n");
#endif /* DEBUGGING */
+ inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (inotify_fd > 0)
+ inotify_add_watch (inotify_fd, GETTY_RELOAD_TRIGGER, IN_ATTRIB | IN_MODIFY);
+
/* Parse command-line arguments. */
parse_args(argc, argv, &options);
@@ -587,6 +599,7 @@ static void parse_args(int argc, char **argv, struct options *op)
HELP_OPTION,
ERASE_CHARS_OPTION,
KILL_CHARS_OPTION,
+ RELOAD_OPTION,
};
const struct option longopts[] = {
{ "8bits", no_argument, 0, '8' },
@@ -618,6 +631,7 @@ static void parse_args(int argc, char **argv, struct options *op)
{ "nohints", no_argument, 0, NOHINTS_OPTION },
{ "nohostname", no_argument, 0, NOHOSTNAME_OPTION },
{ "long-hostname", no_argument, 0, LONGHOSTNAME_OPTION },
+ { "reload", no_argument, 0, RELOAD_OPTION },
{ "version", no_argument, 0, VERSION_OPTION },
{ "help", no_argument, 0, HELP_OPTION },
{ "erase-chars", required_argument, 0, ERASE_CHARS_OPTION },
@@ -736,6 +750,9 @@ static void parse_args(int argc, char **argv, struct options *op)
case KILL_CHARS_OPTION:
op->killchars = optarg;
break;
+ case RELOAD_OPTION:
+ reload_agettys();
+ exit(EXIT_SUCCESS);
case VERSION_OPTION:
printf(_("%s from %s\n"), program_invocation_short_name,
PACKAGE_STRING);
@@ -1114,6 +1131,21 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
}
/* Initialize termios settings. */
+static void termio_clear(int fd)
+{
+ /*
+ * Do not write a full reset (ESC c) because this destroys
+ * the unicode mode again if the terminal was in unicode
+ * mode. Also it clears the CONSOLE_MAGIC features which
+ * are required for some languages/console-fonts.
+ * Just put the cursor to the home position (ESC [ H),
+ * erase everything below the cursor (ESC [ J), and set the
+ * scrolling region to the full window (ESC [ r)
+ */
+ write_all(fd, "\033[r\033[H\033[J", 9);
+}
+
+/* Initialize termios settings. */
static void termio_init(struct options *op, struct termios *tp)
{
speed_t ispeed, ospeed;
@@ -1166,18 +1198,8 @@ static void termio_init(struct options *op, struct termios *tp)
if ((tp->c_cflag & (CS8|PARODD|PARENB)) == CS8)
op->flags |= F_EIGHTBITS;
- if ((op->flags & F_NOCLEAR) == 0) {
- /*
- * Do not write a full reset (ESC c) because this destroys
- * the unicode mode again if the terminal was in unicode
- * mode. Also it clears the CONSOLE_MAGIC features which
- * are required for some languages/console-fonts.
- * Just put the cursor to the home position (ESC [ H),
- * erase everything below the cursor (ESC [ J), and set the
- * scrolling region to the full window (ESC [ r)
- */
- write_all(STDOUT_FILENO, "\033[r\033[H\033[J", 9);
- }
+ if ((op->flags & F_NOCLEAR) == 0)
+ termio_clear(STDOUT_FILENO);
return;
}
@@ -1593,6 +1615,60 @@ static void next_speed(struct options *op, struct termios *tp)
tcsetattr(STDIN_FILENO, TCSANOW, tp);
}
+static int wait_for_term_input(int fd)
+{
+ char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
+ struct termios orig, nonc;
+ fd_set rfds;
+ int count;
+ int i;
+
+ /* Our aim here is to fall through if something fails
+ * and not be stuck waiting. On failure assume we have input */
+
+ if (tcgetattr(fd, &orig) != 0)
+ return 1;
+
+ memcpy(&nonc, &orig, sizeof (nonc));
+ nonc.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHOKE);
+ nonc.c_cc[VMIN] = 1;
+ nonc.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSANOW, &nonc) != 0)
+ return 1;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ if (inotify_fd >= 0)
+ FD_SET(inotify_fd, &rfds);
+
+ /* If waiting fails, just fall through, presumably reading input will fail */
+ if (select (MAX(fd, inotify_fd) + 1, &rfds, NULL, NULL, NULL) < 0)
+ return 1;
+
+ if (FD_ISSET(fd, &rfds)) {
+ count = read(fd, buffer, sizeof (buffer));
+
+ tcsetattr(fd, TCSANOW, &orig);
+
+ /* Reinject the bytes we read back into the buffer, usually just one byte */
+ for (i = 0; i < count; i++)
+ ioctl(fd, TIOCSTI, buffer + i);
+
+ /* Have terminal input */
+ return 1;
+
+ } else {
+ tcsetattr(fd, TCSANOW, &orig);
+
+ /* Just drain the inotify buffer */
+ while (read(inotify_fd, buffer, sizeof (buffer)) > 0);
+
+ /* Need to reprompt */
+ return 0;
+ }
+}
+
/* Get user name, establish parity, speed, erase, kill & eol. */
static char *get_logname(struct options *op, struct termios *tp, struct chardata *cp)
{
@@ -1628,6 +1704,13 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
/* Write issue file and prompt */
do_prompt(op, tp);
+ /* If asked to reprompt *before* terminal input arrives, then do so */
+ if (!wait_for_term_input(STDIN_FILENO)) {
+ if (op->flags & F_VCONSOLE)
+ termio_clear(STDOUT_FILENO);
+ continue;
+ }
+
cp->eol = '\0';
/* Read name, watch for break and end-of-line. */
@@ -2364,3 +2447,22 @@ static int plymouth_command(const char* arg)
}
return 1;
}
+
+static void reload_agettys(void)
+{
+ struct timeval tv[2];
+ int fd;
+
+ if (gettimeofday (tv, NULL) < 0)
+ err (1, "couldn't get current time");
+ memcpy (tv, tv + 1, sizeof (struct timeval));
+
+ fd = open(GETTY_RELOAD_TRIGGER, O_CREAT|O_CLOEXEC|O_WRONLY, 0700);
+ if (fd < 0)
+ err (1, "couldn't open: %s", GETTY_RELOAD_TRIGGER);
+
+ if (futimes (fd, tv) < 0 || close (fd) < 0)
+ err (1, "couldn't touch file: %s", GETTY_RELOAD_TRIGGER);
+
+ close (fd);
+}
--
1.9.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1
2014-07-15 12:40 ` Stef Walter
2014-07-15 16:12 ` Stef Walter
@ 2014-07-16 10:02 ` Karel Zak
1 sibling, 0 replies; 10+ messages in thread
From: Karel Zak @ 2014-07-16 10:02 UTC (permalink / raw)
To: Stef Walter; +Cc: util-linux
On Tue, Jul 15, 2014 at 02:40:41PM +0200, Stef Walter wrote:
> On 15.07.2014 11:19, Karel Zak wrote:
> > Note that we does not control code of all login(1) implementations
> > and we have --login-program <path> to start arbitrary random thing
> > from agetty, so our solution have to be generic rather than rely
> > on any login(1) change.
>
> Well you don't need to modify login(1) (or other --login-program's) at
> all. SIG_IGN is kept across an exec.
Sure, but it's little bit fragile way.
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2014-07-16 10:02 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-07 7:31 [PATCH] agetty: Reprompt and reprint /etc/issue if we receive SIGUSR1 Stef Walter
2014-07-14 13:37 ` Karel Zak
2014-07-15 7:35 ` Stef Walter
2014-07-15 7:51 ` Karel Zak
2014-07-15 7:47 ` Karel Zak
2014-07-15 7:57 ` Stef Walter
2014-07-15 9:19 ` Karel Zak
2014-07-15 12:40 ` Stef Walter
2014-07-15 16:12 ` Stef Walter
2014-07-16 10:02 ` Karel Zak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).