]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
agetty: add \S to output /etc/os-release data
authorKarel Zak <kzak@redhat.com>
Thu, 12 Sep 2013 10:44:09 +0000 (12:44 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 12 Sep 2013 10:44:09 +0000 (12:44 +0200)
This patch allows to use a new \S or \S{VARNAME} sequence in the
/etc/issue file. The sequence prints data from /etc/os-release.  The
reason is to keep /etc/issue file distribution and release
independent.

The \S{ANSI_COLOR} is converted to the real terminal escape seq.

For example:

   \S
   Kernel \r on an \m (\l)

or more complex example:

   Welcome to \S{ANSI_COLOR}\S{NAME}\e0m \S{VERSION}
   Report bugs at \S{BUG_REPORT_URL}.

See http://www.freedesktop.org/software/systemd/man/os-release.html
fr more details about /etc/issue.

Based on patch from Bill Nottingham <notting@redhat.com>.

Signed-off-by: Karel Zak <kzak@redhat.com>
include/pathnames.h
term-utils/agetty.8
term-utils/agetty.c

index cc8a20b16e0d89dd8c1ddef9e3b61ad80e16762c..e25234c45a477b172eb5b349b445db7c7f4de49a 100644 (file)
@@ -63,6 +63,7 @@
 
 /* used in term-utils/agetty.c */
 #define _PATH_ISSUE            "/etc/issue"
+#define _PATH_OS_RELEASE       "/etc/os-release"
 #define _PATH_NUMLOCK_ON       _PATH_LOCALSTATEDIR "/numlock-on"
 
 #define _PATH_LOGINDEFS                "/etc/login.defs"
index 7a0df78045c42f0b71cc9f9a5254272ff38e8d7c..d77955573fd52fae155a16ee5e602bf1db8b5c97 100644 (file)
@@ -320,6 +320,14 @@ Insert the current date.
 .TP
 s
 Insert the system name, the name of the operating system. Same as `uname \-s'.
+See also \\S escape code.
+.TP
+S or S{VARIABLE}
+Insert the VARIABLE data from \fI/etc/os-release\fP.  If the VARIABLE argument
+is not specified then use PRETTY_NAME from the file or the system name (see \\s).
+This escape code allows to keep \fI/etc/issue\fP distribution and release
+independent.  Note that \\S{ANSI_COLOR} is converted to the real terminal
+escape sequence.
 .TP
 l
 Insert the name of the current tty line.
@@ -378,11 +386,14 @@ the system status file.
 .B /etc/issue
 printed before the login prompt.
 .TP
+.B /etc/os-release
+operating system identification data.
+.TP
 .B /dev/console
 problem reports (if syslog(3) is not used).
 .TP
 .B /etc/inittab
-\fIinit\fP(8) configuration file.
+\fIinit\fP(8) configuration file for SysV-style init daemon.
 .SH BUGS
 .ad
 .fi
index 29301a61c85d5f8ad4c10c7eefd46160d1ff39c3..3033558bd47a9ceb2637633f617d41e658373bcb 100644 (file)
@@ -129,6 +129,7 @@ struct options {
        char *issue;                    /* alternative issue file */
        char *erasechars;               /* string with erase chars */
        char *killchars;                /* string with kill chars */
+       char *osrelease;                /* /etc/os-release data */
        int delay;                      /* Sleep seconds before prompt */
        int nice;                       /* Run login with this priority */
        int numspeed;                   /* number of baud rates to try */
@@ -465,7 +466,8 @@ int main(int argc, char **argv)
                        log_warn(_("%s: can't change process priority: %m"),
                                options.tty);
        }
-
+       if (options.osrelease)
+               free(options.osrelease);
 #ifdef DEBUGGING
        fprintf(dbf, "read %c\n", ch);
        if (close_stream(dbf) != 0)
@@ -1317,6 +1319,84 @@ static char *xgetdomainname(void)
        return NULL;
 }
 
+static char *read_os_release(struct options *op, const char *varname)
+{
+       int fd = -1;
+       struct stat st;
+       size_t varsz = strlen(varname);
+       char *p, *buf = NULL, *ret = NULL;
+
+       /* read the file only once */
+       if (!op->osrelease) {
+               fd = open(_PATH_OS_RELEASE, O_RDONLY);
+               if (fd == -1) {
+                       log_warn(_("cannot open: %s: %m"), _PATH_OS_RELEASE);
+                       return NULL;
+               }
+
+               if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024)
+                       goto done;
+
+               op->osrelease = malloc(st.st_size + 1);
+               if (!op->osrelease)
+                       log_err(_("failed to allocate memory: %m"));
+               if (read_all(fd, op->osrelease, st.st_size) != (ssize_t) st.st_size) {
+                       free(op->osrelease);
+                       op->osrelease = NULL;
+                       goto done;
+               }
+               op->osrelease[st.st_size] = 0;
+       }
+       buf = strdup(op->osrelease);
+       if (!buf)
+               log_err(_("failed to allocate memory: %m"));
+       p = buf;
+
+       for (;;) {
+               char *eol, *eon;
+
+               p += strspn(p, "\n\r");
+               p += strspn(p, " \t\n\r");
+               if (!*p)
+                       break;
+               if (strspn(p, "#;\n") != 0) {
+                       p += strcspn(p, "\n\r");
+                       continue;
+               }
+               if (strncmp(p, varname, varsz) != 0) {
+                       p += strcspn(p, "\n\r");
+                       continue;
+               }
+               p += varsz;
+               p += strspn(p, " \t\n\r=\"");
+               eol = p + strcspn(p, "\n\r");
+               *eol = '\0';
+               eon = eol-1;
+               while (eon > p) {
+                       if (*eon == '\t' || *eon == ' ') {
+                               eon--;
+                               continue;
+                       }
+                       if (*eon == '"') {
+                               *eon = '\0';
+                               break;
+                       }
+                       break;
+               }
+               if (ret)
+                       free(ret);
+               ret = strdup(p);
+               if (!ret)
+                       log_err(_("failed to allocate memory: %m"));
+               p = eol + 1;
+       }
+done:
+       free(buf);
+       if (fd >= 0)
+               close(fd);
+       return ret;
+}
+
 /* Show login prompt, optionally preceded by /etc/issue contents. */
 static void do_prompt(struct options *op, struct termios *tp)
 {
@@ -2006,6 +2086,24 @@ static void output_special_char(unsigned char c, struct options *op,
                }
                break;
        }
+       case 'S':
+       {
+               char *var = NULL, varname[64];
+
+               if (get_escape_argument(fp, varname, sizeof(varname)))
+                       var = read_os_release(op, varname);
+               else if (!(var = read_os_release(op, "PRETTY_NAME")))
+                       var = uts.sysname;
+               if (var) {
+                       if (strcmp(varname, "ANSI_COLOR") == 0)
+                               printf("\033[%sm", var);
+                       else
+                               printf("%s", var);
+                       if (var != uts.sysname)
+                               free(var);
+               }
+               break;
+       }
        case 'u':
        case 'U':
        {