Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Aug 2019 01:25:39 +0000 (UTC)
From:      Eugene Grosbein <eugen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r351413 - head/usr.bin/last
Message-ID:  <201908230125.x7N1PdTN070890@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: eugen
Date: Fri Aug 23 01:25:38 2019
New Revision: 351413
URL: https://svnweb.freebsd.org/changeset/base/351413

Log:
  last(1): unbreak for 8-bit locales
  
  Ouput format of last(1) is 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.
  It fixes output for other locales.
  
  MFC after:	2 weeks

Modified:
  head/usr.bin/last/last.c

Modified: head/usr.bin/last/last.c
==============================================================================
--- head/usr.bin/last/last.c	Fri Aug 23 01:16:12 2019	(r351412)
+++ head/usr.bin/last/last.c	Fri Aug 23 01:25:38 2019	(r351413)
@@ -93,6 +93,7 @@ static time_t	currentout;			/* current logout value */
 static long	maxrec;				/* records to display */
 static const	char *file = NULL;		/* utx.log file */
 static int	sflag = 0;			/* show delta in seconds */
+static int	utf8flag;			/* current locale is UTF-8 */
 static int	width = 5;			/* show seconds in delta */
 static int	yflag;				/* show year */
 static int      d_first;
@@ -103,6 +104,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 *);
@@ -112,6 +114,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 (utf8flag)
+		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)
 {
@@ -130,6 +157,9 @@ main(int argc, char *argv[])
 	(void) setlocale(LC_TIME, "");
 	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
 
+	(void) setlocale(LC_CTYPE, "");
+	utf8flag = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0);
+
 	argc = xo_parse_args(argc, argv);
 	if (argc < 0)
 		exit(1);
@@ -262,7 +292,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");
 }
 
@@ -379,7 +409,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) {
@@ -393,7 +423,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);
@@ -403,9 +433,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);
 	}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201908230125.x7N1PdTN070890>