MFC r351413,351459,351467: unbreak last(1) for 8-bit locales

Ouput format of last's broken for non UTF-8 locales
since it got libxo(3) support. It uses strftime(3) that produces
non UTF-8 strings passed to xo_emit(3) with wrong %s format -
it should be %hs in this case, so xo_emit(3) produces empty output.

This change is basically no-op when locale is of UTF-8 type,
f.e. en_GB.UTF-8 or ru_RU.UTF-8 or sr_RS.UTF-8@latin.
Also it is no-op for C/POSIX locale that's a subset of UTF-8.

It fixes output for other locales.
This commit is contained in:
Eugene Grosbein 2019-09-06 05:34:31 +00:00
parent 29d369e234
commit 5050094db7

View File

@ -88,6 +88,7 @@ static const char *crmsg; /* cause of last reboot */
static time_t currentout; /* current logout value */
static long maxrec; /* records to display */
static const char *file = NULL; /* utx.log file */
static int noctfix = 0; /* locale is C or UTF-8 */
static int sflag = 0; /* show delta in seconds */
static int width = 5; /* show seconds in delta */
static int yflag; /* show year */
@ -99,6 +100,7 @@ static time_t snaptime; /* if != 0, we will only
*/
static void addarg(int, char *);
static const char *ctf(const char *);
static time_t dateconv(char *);
static void doentry(struct utmpx *);
static void hostconv(char *);
@ -108,6 +110,31 @@ static int want(struct utmpx *);
static void usage(void);
static void wtmp(void);
static const char*
ctf(const char *fmt) {
static char buf[31];
const char *src, *end;
char *dst;
if (noctfix)
return (fmt);
end = buf + sizeof(buf);
for (src = fmt, dst = buf; dst < end; *dst++ = *src++) {
if (*src == '\0') {
*dst = '\0';
break;
} else if (*src == '%' && *(src+1) == 's') {
*dst++ = '%';
*dst++ = 'h';
*dst++ = 's';
strlcpy(dst, src+2, end - dst);
return (buf);
}
}
return (buf);
}
static void
usage(void)
{
@ -126,6 +153,11 @@ main(int argc, char *argv[])
(void) setlocale(LC_TIME, "");
d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
(void) setlocale(LC_CTYPE, "");
p = nl_langinfo(CODESET);
if (strcmp(p, "UTF-8") == 0 || strcmp(p, "US-ASCII") == 0)
noctfix = 1;
argc = xo_parse_args(argc, argv);
if (argc < 0)
exit(1);
@ -247,7 +279,7 @@ wtmp(void)
(void) strftime(ct, sizeof(ct), "%+", tm);
xo_emit("\n{:utxdb/%s}", (file == NULL) ? "utx.log" : file);
xo_attr("seconds", "%lu", (unsigned long) t);
xo_emit(" begins {:begins/%s}\n", ct);
xo_emit(ctf(" begins {:begins/%s}\n"), ct);
xo_close_container("last-information");
}
@ -364,7 +396,7 @@ printentry(struct utmpx *bp, struct idtab *tt)
break;
}
xo_attr("seconds", "%lu", (unsigned long)t);
xo_emit(" {:login-time/%s%c/%s}", ct, tt == NULL ? '\n' : ' ');
xo_emit(ctf(" {:login-time/%s%c/%s}"), ct, tt == NULL ? '\n' : ' ');
if (tt == NULL)
goto end;
if (!tt->logout) {
@ -378,7 +410,7 @@ printentry(struct utmpx *bp, struct idtab *tt)
tm = localtime(&tt->logout);
(void) strftime(ct, sizeof(ct), "%R", tm);
xo_attr("seconds", "%lu", (unsigned long)tt->logout);
xo_emit("- {:logout-time/%s}", ct);
xo_emit(ctf("- {:logout-time/%s}"), ct);
}
delta = tt->logout - bp->ut_tv.tv_sec;
xo_attr("seconds", "%ld", (long)delta);
@ -388,9 +420,9 @@ printentry(struct utmpx *bp, struct idtab *tt)
tm = gmtime(&delta);
(void) strftime(ct, sizeof(ct), width >= 8 ? "%T" : "%R", tm);
if (delta < 86400)
xo_emit(" ({:session-length/%s})\n", ct);
xo_emit(ctf(" ({:session-length/%s})\n"), ct);
else
xo_emit(" ({:session-length/%ld+%s})\n",
xo_emit(ctf(" ({:session-length/%ld+%s})\n"),
(long)delta / 86400, ct);
}