agetty: add support for /run/issue and /usr/lib/issue
Addresses: https://github.com/karelzak/util-linux/issues/828 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
c2409b55a0
commit
456bcbca6b
|
@ -68,8 +68,11 @@
|
|||
# define _PATH_BTMP "/var/log/btmp"
|
||||
#endif
|
||||
|
||||
#define _PATH_ISSUE "/etc/issue"
|
||||
#define _PATH_ISSUEDIR _PATH_ISSUE ".d"
|
||||
#define _PATH_ISSUE_FILENAME "issue"
|
||||
#define _PATH_ISSUE_DIRNAME _PATH_ISSUE_FILENAME ".d"
|
||||
|
||||
#define _PATH_ISSUE "/etc/" _PATH_ISSUE_FILENAME
|
||||
#define _PATH_ISSUEDIR "/etc/" _PATH_ISSUE_DIRNAME
|
||||
|
||||
#define _PATH_OS_RELEASE_ETC "/etc/os-release"
|
||||
#define _PATH_OS_RELEASE_USR "/usr/lib/os-release"
|
||||
|
|
|
@ -118,7 +118,7 @@ is added to the \fB/bin/login\fP command line.
|
|||
See \fB\-\-login\-options\fR.
|
||||
.TP
|
||||
\-f, \-\-issue\-file \fIfile|directory\fP
|
||||
Display the contents of \fIfile\fP instead of \fI/etc/issue\fP. If the
|
||||
Display the contents of \fIfile\fP instead of \fI/etc/issue\fP (or other). If the
|
||||
specified path is a \fIdirectory\fP then displays all files with .issue file
|
||||
extension in version-sort order from the directory. This allows custom
|
||||
messages to be displayed on different terminals. The
|
||||
|
@ -340,7 +340,7 @@ for a leading "\-" and makes sure the logname gets passed as one parameter
|
|||
on how the login binary parses the command line that might not be sufficient.
|
||||
Check that the used login program cannot be abused this way.
|
||||
.PP
|
||||
Some programs use "\-\-" to indicate that the rest of the commandline should
|
||||
Some programs use "\-\-" to indicate that the rest of the command line should
|
||||
not be interpreted as options. Use this feature if available by passing "\-\-"
|
||||
before the username gets passed by \\u.
|
||||
|
||||
|
@ -353,9 +353,18 @@ directory is ignored. All files with .issue extension from the directory are
|
|||
printed in version-sort order. The directory allow to maintain 3rd-party
|
||||
messages independently on the primary system \fI/etc/issue\fP file.
|
||||
|
||||
Since version 2.35 additional locations for issue file and directory are
|
||||
supported. If the default \fI/etc/issue\fP does not exist than agetty checks
|
||||
for \fI/run/issue\fP and \fI/run/issue.d\fP, thereafter for
|
||||
\fI/usr/lib/issue\fP and \fI/usr/lib/issue.d\fP. The directory /etc is
|
||||
expected for host specific configuration, /run is expected for generated stuff
|
||||
and /usr/lib for static distribution maintained configuration.
|
||||
|
||||
The default path maybe overridden by \fB\-\-issue\-file\fP option. In this case
|
||||
specified path has to be file or directory and the default \fI/etc/issue\fP as
|
||||
well as \fI/etc/issue.d\fP are ignored.
|
||||
specified path has to be file or directory and all the default issue file and
|
||||
directory locations are ignored.
|
||||
|
||||
The issue file feature is possible to completely disable by \fB\-\-noissue\fP option.
|
||||
|
||||
The issue files may contain certain escape codes to display the system name, date, time
|
||||
etcetera. All escape codes consist of a backslash (\\) immediately
|
||||
|
|
|
@ -1729,26 +1729,53 @@ static int issuedir_filter(const struct dirent *d)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static FILE *issuedir_next_file(int dd, struct dirent **namelist, int nfiles, int *n)
|
||||
|
||||
static int issuefile_read_stream(struct issue *ie, FILE *f, struct options *op, struct termios *tp);
|
||||
|
||||
/* returns: 0 on success, 1 cannot open, <0 on error
|
||||
*/
|
||||
static int issuedir_read(struct issue *ie, const char *dirname,
|
||||
struct options *op, struct termios *tp)
|
||||
{
|
||||
while (*n < nfiles) {
|
||||
struct dirent *d = namelist[*n];
|
||||
struct stat st;
|
||||
int dd, nfiles, i;
|
||||
struct dirent **namelist = NULL;
|
||||
|
||||
dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (dd < 0)
|
||||
return 1;
|
||||
|
||||
nfiles = scandirat(dd, ".", &namelist, issuedir_filter, versionsort);
|
||||
if (nfiles <= 0)
|
||||
goto done;
|
||||
|
||||
ie->do_tcsetattr = 1;
|
||||
|
||||
for (i = 0; i < nfiles; i++) {
|
||||
struct dirent *d = namelist[i];
|
||||
FILE *f;
|
||||
|
||||
(*n)++;
|
||||
|
||||
if (fstatat(dd, d->d_name, &st, 0) ||
|
||||
!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
f = fopen_at(dd, d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR);
|
||||
if (f)
|
||||
return f;
|
||||
if (f) {
|
||||
issuefile_read_stream(ie, f, op, tp);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < nfiles; i++)
|
||||
free(namelist[i]);
|
||||
free(namelist);
|
||||
done:
|
||||
close(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !ISSUEDIR_SUPPORT */
|
||||
static int issuedir_read(struct issue *ie __attribute__((__unused__)),
|
||||
const char *dirname __attribute__((__unused__)),
|
||||
struct options *op __attribute__((__unused__)),
|
||||
struct termios *tp __attribute__((__unused__)))
|
||||
{
|
||||
}
|
||||
#endif /* ISSUEDIR_SUPPORT */
|
||||
|
||||
#ifndef ISSUE_SUPPORT
|
||||
|
@ -1769,6 +1796,44 @@ static void eval_issue_file(struct issue *ie __attribute__((__unused__)),
|
|||
}
|
||||
#else /* ISSUE_SUPPORT */
|
||||
|
||||
static int issuefile_read_stream(
|
||||
struct issue *ie, FILE *f,
|
||||
struct options *op, struct termios *tp)
|
||||
{
|
||||
struct stat st;
|
||||
int c;
|
||||
|
||||
if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode))
|
||||
return 1;
|
||||
|
||||
if (!ie->output)
|
||||
ie->output = open_memstream(&ie->mem, &ie->mem_sz);
|
||||
|
||||
while ((c = getc(f)) != EOF) {
|
||||
if (c == '\\')
|
||||
output_special_char(ie, getc(f), op, tp, f);
|
||||
else
|
||||
putc(c, ie->output);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int issuefile_read(
|
||||
struct issue *ie, const char *filename,
|
||||
struct options *op, struct termios *tp)
|
||||
{
|
||||
FILE *f = fopen(filename, "r" UL_CLOEXECSTR);
|
||||
int rc = 1;
|
||||
|
||||
if (f)
|
||||
rc = issuefile_read_stream(ie, f, op, tp);
|
||||
fclose(f);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#ifdef AGETTY_RELOAD
|
||||
static int issue_is_changed(struct issue *ie)
|
||||
{
|
||||
|
@ -1829,97 +1894,65 @@ static void eval_issue_file(struct issue *ie,
|
|||
struct options *op,
|
||||
struct termios *tp)
|
||||
{
|
||||
const char *filename, *dirname = NULL;
|
||||
FILE *f = NULL;
|
||||
#ifdef ISSUEDIR_SUPPORT
|
||||
int dd = -1, nfiles = 0, i;
|
||||
struct dirent **namelist = NULL;
|
||||
#endif
|
||||
int has_file = 0;
|
||||
|
||||
#ifdef AGETTY_RELOAD
|
||||
netlink_groups = 0;
|
||||
#endif
|
||||
|
||||
if (!(op->flags & F_ISSUE))
|
||||
return;
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* The custom issue file or directory specified by: agetty -f <path>.
|
||||
* Note that nothing is printed if the file/dir does not exist.
|
||||
*/
|
||||
filename = op->issue;
|
||||
if (filename) {
|
||||
if (op->issue) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(filename, &st) < 0)
|
||||
return;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
dirname = filename;
|
||||
filename = NULL;
|
||||
}
|
||||
} else {
|
||||
/* The default /etc/issue and optional /etc/issue.d directory
|
||||
* as extension to the file. The /etc/issue.d directory is
|
||||
* ignored if there is no /etc/issue file. The file may be
|
||||
* empty or symlink.
|
||||
*/
|
||||
if (access(_PATH_ISSUE, F_OK|R_OK) != 0)
|
||||
return;
|
||||
filename = _PATH_ISSUE;
|
||||
dirname = _PATH_ISSUEDIR;
|
||||
if (stat(op->issue, &st) < 0)
|
||||
goto done;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
issuedir_read(ie, op->issue, op, tp);
|
||||
else
|
||||
issuefile_read(ie, op->issue, op, tp);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ie->output = open_memstream(&ie->mem, &ie->mem_sz);
|
||||
#ifdef ISSUEDIR_SUPPORT
|
||||
if (dirname) {
|
||||
dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (dd >= 0)
|
||||
nfiles = scandirat(dd, ".", &namelist, issuedir_filter, versionsort);
|
||||
if (nfiles <= 0)
|
||||
dirname = NULL;
|
||||
}
|
||||
i = 0;
|
||||
#endif
|
||||
if (filename)
|
||||
f = fopen(filename, "r");
|
||||
|
||||
if (f || dirname) {
|
||||
int c;
|
||||
|
||||
ie->do_tcsetattr = 1;
|
||||
|
||||
do {
|
||||
#ifdef ISSUEDIR_SUPPORT
|
||||
if (!f && i < nfiles)
|
||||
f = issuedir_next_file(dd, namelist, nfiles, &i);
|
||||
#endif
|
||||
if (!f)
|
||||
break;
|
||||
while ((c = getc(f)) != EOF) {
|
||||
if (c == '\\')
|
||||
output_special_char(ie, getc(f), op, tp, f);
|
||||
else
|
||||
putc(c, ie->output);
|
||||
}
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
} while (dirname);
|
||||
|
||||
if ((op->flags & F_VCONSOLE) == 0)
|
||||
ie->do_tcrestore = 1;
|
||||
/* The default /etc/issue and optional /etc/issue.d directory as
|
||||
* extension to the file. The /etc/issue.d directory is ignored if
|
||||
* there is no /etc/issue file. The file may be empty or symlink.
|
||||
*/
|
||||
if (access(_PATH_ISSUE, F_OK|R_OK) == 0) {
|
||||
issuefile_read(ie, _PATH_ISSUE, op, tp);
|
||||
issuedir_read(ie, _PATH_ISSUEDIR, op, tp);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef ISSUEDIR_SUPPORT
|
||||
for (i = 0; i < nfiles; i++)
|
||||
free(namelist[i]);
|
||||
free(namelist);
|
||||
if (dd >= 0)
|
||||
close(dd);
|
||||
#endif
|
||||
/* Fallback @runstatedir (usually /run) -- the file is not required to
|
||||
* read the dir.
|
||||
*/
|
||||
if (issuefile_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_FILENAME, op, tp) == 0)
|
||||
has_file++;
|
||||
if (issuedir_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_DIRNAME, op, tp) == 0)
|
||||
has_file++;
|
||||
if (has_file)
|
||||
goto done;
|
||||
|
||||
/* Fallback @sysconfstaticdir (usually /usr/lib) -- the file is not
|
||||
* required to read the dir
|
||||
*/
|
||||
issuefile_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_FILENAME, op, tp);
|
||||
issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp);
|
||||
|
||||
done:
|
||||
|
||||
#ifdef AGETTY_RELOAD
|
||||
if (netlink_groups != 0)
|
||||
open_netlink();
|
||||
#endif
|
||||
fclose(ie->output);
|
||||
if (ie->output)
|
||||
fclose(ie->output);
|
||||
}
|
||||
#endif /* ISSUE_SUPPORT */
|
||||
|
||||
|
|
Loading…
Reference in New Issue