From: Tobias Stoeckmann Date: Thu, 9 Apr 2026 19:23:05 +0000 (+0200) Subject: last: Use int for string precision modifier X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=a401c223ab5a2affcfdae44f25ebb2a56a5f263b;p=thirdparty%2Futil-linux.git last: Use int for string precision modifier The %.*s modifier requires an int as precision argument, not an unsigned int. Instead of just turning the domain_len and name_len fields into int, this refactoring makes it easier to verify that only two fixed values are ever used and avoids many int/size_t casts: Since fullnames_mode field already specifies which values domain_len and name_len will take, these fields can be turned into local variables. No special checks required when parsing 'w' argument. Setting domain_len and name_len as close as possible to their usages as %.*s modifier arguments shows that the relevant if-else-blocks are always evaluated and only allow two values. This leads to smaller binary size because less instructions are needed (e.g. these variables do not need pointer dereferences anymore). In total, around 160 bytes on x86_64 are saved. Signed-off-by: Tobias Stoeckmann --- diff --git a/login-utils/last.c b/login-utils/last.c index 0afdf9dd4..51743e5b4 100644 --- a/login-utils/last.c +++ b/login-utils/last.c @@ -83,8 +83,6 @@ struct last_control { usedns, /* Use DNS to lookup the hostname */ useip; /* Print IP address in number format */ - unsigned int name_len; /* Number of login name characters to print */ - unsigned int domain_len; /* Number of domain name characters to print */ unsigned int maxrecs; /* Maximum number of records to list */ char **show; /* Match search list */ @@ -401,6 +399,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t int mins, hours, days; int r, len; struct last_timefmt *fmt; + int name_len; /* * uucp and ftp have special-type entries @@ -526,32 +525,43 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t * set last displayed character to an asterisk when * user/domain/ip fields are to be truncated in non-fullnames mode */ - if (!ctl->fullnames_mode && (strnlen(p->ut_user, sizeof(p->ut_user)) > ctl->name_len)) - p->ut_user[ctl->name_len-1] = '*'; + if (ctl->fullnames_mode) + name_len = (int)sizeof_member(struct utmpx, ut_user); + else { + name_len = LAST_LOGIN_LEN; + if (strnlen(p->ut_user, sizeof(p->ut_user)) > LAST_LOGIN_LEN) + p->ut_user[LAST_LOGIN_LEN - 1] = '*'; + } if (ctl->showhost) { if (!ctl->altlist) { - - if (!ctl->fullnames_mode && (strnlen(domain, sizeof(domain)) > ctl->domain_len)) - domain[ctl->domain_len-1] = '*'; + int domain_len; + + if (ctl->fullnames_mode) + domain_len = (int)sizeof_member(struct utmpx, ut_host); + else { + domain_len = LAST_DOMAIN_LEN; + if (strnlen(domain, sizeof(domain)) > LAST_DOMAIN_LEN) + domain[LAST_DOMAIN_LEN - 1] = '*'; + } len = snprintf(final, sizeof(final), "%-8.*s%c%-12.12s%c%-16.*s%c%-*.*s%c%-*.*s%c%s\n", - ctl->name_len, p->ut_user, ctl->separator, utline, ctl->separator, - ctl->domain_len, domain, ctl->separator, + name_len, p->ut_user, ctl->separator, utline, ctl->separator, + domain_len, domain, ctl->separator, fmt->in_len, fmt->in_len, logintime, ctl->separator, fmt->out_len, fmt->out_len, logouttime, ctl->separator, length); } else { len = snprintf(final, sizeof(final), "%-8.*s%c%-12.12s%c%-*.*s%c%-*.*s%c%-12.12s%c%s\n", - ctl->name_len, p->ut_user, ctl->separator, utline, ctl->separator, + name_len, p->ut_user, ctl->separator, utline, ctl->separator, fmt->in_len, fmt->in_len, logintime, ctl->separator, fmt->out_len, fmt->out_len, logouttime, ctl->separator, length, ctl->separator, domain); } } else len = snprintf(final, sizeof(final), "%-8.*s%c%-12.12s%c%-*.*s%c%-*.*s%c%s\n", - ctl->name_len, p->ut_user, ctl->separator, utline, ctl->separator, + name_len, p->ut_user, ctl->separator, utline, ctl->separator, fmt->in_len, fmt->in_len, logintime, ctl->separator, fmt->out_len, fmt->out_len, logouttime, ctl->separator, length); @@ -940,9 +950,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct last_control ctl = { .showhost = TRUE, - .name_len = LAST_LOGIN_LEN, .time_fmt = LAST_TIMEFTM_SHORT, - .domain_len = LAST_DOMAIN_LEN, .boot_time = { .tv_sec = 1595978419, .tv_usec = 816074 @@ -989,9 +997,7 @@ int main(int argc, char **argv) { struct last_control ctl = { .showhost = TRUE, - .name_len = LAST_LOGIN_LEN, .time_fmt = LAST_TIMEFTM_SHORT, - .domain_len = LAST_DOMAIN_LEN, .fullnames_mode = false, }; char **files = NULL; @@ -1096,10 +1102,6 @@ int main(int argc, char **argv) break; case 'w': ctl.fullnames_mode = true; - if (ctl.name_len < sizeof_member(struct utmpx, ut_user)) - ctl.name_len = sizeof_member(struct utmpx, ut_user); - if (ctl.domain_len < sizeof_member(struct utmpx, ut_host)) - ctl.domain_len = sizeof_member(struct utmpx, ut_host); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':