Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package blog for openSUSE:Factory checked in at 2026-06-22 18:05:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/blog (Old) and /work/SRC/openSUSE:Factory/.blog.new.1956 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "blog" Mon Jun 22 18:05:38 2026 rev:26 rq:1361156 version:2.42 Changes: -------- --- /work/SRC/openSUSE:Factory/blog/blog.changes 2026-04-25 21:35:28.977163119 +0200 +++ /work/SRC/openSUSE:Factory/.blog.new.1956/blog.changes 2026-06-22 18:06:08.266702816 +0200 @@ -1,0 +2,45 @@ +Mon Jun 22 13:48:12 UTC 2026 - Dr. Werner Fink <[email protected]> + +- Update to version 2.42 + Fix possible memory leaks, eliminate type punning, and resolve I/O blocking + This update implements a series of systemic improvements to stability, + security, and performance: + 1. Memory Safety & Leak Resolution: + - Implemented lcons_shutdown destructor to automatically purge the console + list and close FDs on exit. + - Fixed password buffer leak by using in closeIO, correctly matching + the mmap allocation in shm_malloc. + - Added cleanup for pwprompt in closeIO. + 2. Elimination of Dangerous Type Punning: + - Replaced the unreliable &cons->node pattern with a type-safe list_t lcons + sentinel across the codebase. + - Added __attribute__((may_alias)) to list_t in listing.h to prevent + compiler strict aliasing optimizations from corrupting list traversals. + 3. I/O Responsiveness & Stability: + - Removed tcdrain() from the high-frequency epoll_console_in path to + eliminate daemon freezes during heavy output. + - Updated consinitIO to ensure CON_SERIAL devices remain in O_NONBLOCK + mode, preventing freezes on slow serial lines. + - Extended the tcdrain skip-list in closeIO to include CON_SERIAL, ensuring + a hang-free shutdown. + 4. Architectural Improvements: + - Redesigned shm_malloc to use a tiered mapping strategy: prefers + file-backed shared memory in /dev/shm with a graceful fallback + to MAP_ANONYMOUS. + - Optimized listing.h with always_inline attributes, __builtin_prefetch + for cache efficiency, and list poisoning for safer debugging. + +------------------------------------------------------------------- +Fri Jun 19 12:45:28 UTC 2026 - Dr. Werner Fink <[email protected]> + +- Update to version 2.41 + * The __attribute__((noreturn)) for error() in libconsole.h added + * The variable err with 0 initialized in thread_poll() + * The variable cp.parity with {0} initialized in readpw() + * feat(blogd): handle pending systemd password requests on coldstart + * Initialize console pointer list as well + * Check peer credentials before reading command + * Make isinteger() string check usable for all architectures + * Add some comments about warnings and translation for S390 + +------------------------------------------------------------------- Old: ---- showconsole-2.40.tar.gz New: ---- showconsole-2.42.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ blog.spec ++++++ --- /var/tmp/diff_new_pack.RRs00r/_old 2026-06-22 18:06:09.790755992 +0200 +++ /var/tmp/diff_new_pack.RRs00r/_new 2026-06-22 18:06:09.794756131 +0200 @@ -17,7 +17,7 @@ Name: blog -Version: 2.40 +Version: 2.42 %define sonum 2 Release: 0 Summary: Boot logging ++++++ showconsole-2.40.tar.gz -> showconsole-2.42.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/Makefile new/showconsole-2.42/Makefile --- old/showconsole-2.40/Makefile 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/Makefile 2026-06-22 15:46:21.000000000 +0200 @@ -15,7 +15,7 @@ DEBUG = DESTDIR = MAJOR := 2 -MINOR := 40 +MINOR := 42 VERSION := $(MAJOR).$(MINOR) DATE = $(shell date +'%d%b%y' | tr '[:lower:]' '[:upper:]') COPTS = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/blogctl.c new/showconsole-2.42/blogctl.c --- old/showconsole-2.40/blogctl.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/blogctl.c 2026-06-22 15:46:21.000000000 +0200 @@ -19,7 +19,7 @@ /* * Cry and exit. */ -void error (const char *fmt, ...) +__attribute__((noreturn)) void error (const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/blogd.c new/showconsole-2.42/blogd.c --- old/showconsole-2.40/blogd.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/blogd.c 2026-06-22 15:46:21.000000000 +0200 @@ -61,7 +61,7 @@ /* * Cry and exit. */ -void error (const char *fmt, ...) +__attribute__((noreturn)) void error (const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -197,7 +197,7 @@ int ret = 0, tflags; int olderr = errno; - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { int newfd; if (!c->tty) continue; @@ -285,7 +285,7 @@ argc -= optind; myname = program_invocation_short_name; - getconsoles(&cons, 1); + getconsoles(1); close(0); close(1); @@ -293,10 +293,12 @@ if ((fd = open_tty(console, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0) error("Can not open system console %s: %m", console); - if (fd > 0) { + if (fd != 0) { (void)ioctl(fd, TIOCNXCL); /* Avoid EBUSY */ dup2(fd, 0); close(fd); + } else { + (void)ioctl(0, TIOCNXCL); } dup2(0, 1); @@ -305,7 +307,7 @@ (void)ioctl(0, TIOCCONS, NULL); /* Undo any current map if any */ - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { speed_t ospeed; speed_t ispeed; int flags; @@ -419,7 +421,7 @@ (void)restart_sig(SIGTERM, 1); (void)restart_sig(SIGSYS, 1); - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { struct termios oldtio; speed_t ospeed; speed_t ispeed; @@ -512,7 +514,7 @@ int ret __attribute__ ((unused)); if ((flags = fcntl(0, F_GETFL)) < 0) - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd < 0) continue; ret = write(c->fd, msg, strlen(msg)); @@ -521,7 +523,7 @@ flags &= ~(O_NONBLOCK); flags |= O_NOCTTY; if (fcntl(0, F_SETFL, flags) < 0) - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd < 0) continue; ret = write(c->fd, msg, strlen(msg)); @@ -540,7 +542,7 @@ close(pipefd[0]); if (pipefd[1] >= 0) close(pipefd[1]); - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { const char *msg = "blogd: can not fork to become daemon: "; const char *err = strerror(errno); int ret __attribute__ ((unused)); @@ -557,7 +559,7 @@ close(ptm); if (pipefd[1] >= 0) close(pipefd[1]); - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd > 0) { close(c->fd); c->fd = -1; @@ -604,7 +606,7 @@ if (show_status == 0 && kill (1, SIGRTMIN+20) < 0) warn("could not tell system to hode its status"); - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd > 0) { if (c->tlock) /* write back old setup */ tcsetattr(c->fd, TCSADRAIN, &c->otio); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/coldstart.c new/showconsole-2.42/libconsole/coldstart.c --- old/showconsole-2.40/libconsole/coldstart.c 1970-01-01 01:00:00.000000000 +0100 +++ new/showconsole-2.42/libconsole/coldstart.c 2026-06-22 15:46:21.000000000 +0200 @@ -0,0 +1,231 @@ +/* + * coldstart.c + * + * Copyright 2026 Werner Fink + * Copyright 2026 SUSE Software Solutions Germany GmbH + * + * This source is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include "listing.h" +#include "libconsole.h" + +extern void parse_ask_file(const char *); + +#define MAX_LINE 1024 +#define ASK_DIR "/run/systemd/ask-password" + +void send_response_to_systemd(const char *socket_path, const char *password) +{ + char *packet; + size_t pwd_len, packet_len; + struct sockaddr_un addr; + + int sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) + return; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); + + /* systemd protocol requires: '+' + password (the \0 is optional) */ + pwd_len = strlen(password); + packet_len = pwd_len + 1; /* +1 for '+' */ + packet = (char*)malloc(packet_len); + + if (!packet) + error("memory allocation: %m"); + + packet[0] = '+'; + memcpy(packet + 1, password, pwd_len); + + /* Now send the packet as one datagramm (SOCK_DGRAM) */ + sendto(sock, packet, packet_len, 0, (struct sockaddr *)&addr, sizeof(addr)); + + free(packet); + close(sock); +} + + + +/* Inintialize head node for systemd password queries */ +list_t pwd_requests = { &(pwd_requests), &(pwd_requests) }; + +/* + * Data structure for single password query, compare + * with https://systemd.io/PASSWORD_AGENTS/ + */ +struct request { + list_t node; + time_t notafter; + pid_t pid; + char *socket_path; + char *message; +}; + +struct request *requests = NULL; + +/* Helper to safely strip newlines and trailing whitespace */ +static void trim_trailing(char *str) +{ + size_t len = strlen(str); + while (len > 0 && (str[len - 1] == '\n' || str[len - 1] == '\r' || str[len - 1] == ' ')) { + str[len - 1] = '\0'; + len--; + } +} + +/* Parses a single ask.<id> file and adds it to the list if valid */ +void parse_ask_file(const char *filepath) +{ + char line[MAX_LINE]; + int in_ask_section; + struct request *req; + list_t *head; + + FILE *fp = fopen(filepath, "r"); + if (!fp) + return; + + in_ask_section = 0; + + /* Allocate memory for our custom wrapper structure */ + if (posix_memalign((void**)&req, sizeof(void*), alignof(struct request)) != 0 || !req) { + fclose(fp); + error("memory allocation: %m"); + } + + while (fgets(line, sizeof(line), fp)) { + char *eq, *key, *value; + + trim_trailing(line); + + /* Skip empty lines or comments */ + if (line[0] == '\0' || line[0] == '#') + continue; + + /* Section header matching */ + if (line[0] == '[' && line[strlen(line) - 1] == ']') { + if (strcmp(line, "[Ask]") == 0) { + in_ask_section = 1; + } else { + in_ask_section = 0; /* Left the [Ask] block */ + } + continue; /* Next line please */ + } + + if (!in_ask_section) + continue; /* Only parse key=value variables if inside the [Ask] section */ + + eq = strchr(line, '='); + if (!eq) + continue; + + *eq = '\0'; + key = line; + value = eq + 1; + + if (strcmp(key, "Message") == 0) + req->message = strdup(value); + else if (strcmp(key, "PID") == 0) + req->pid = (pid_t)atol(value); + else if (strcmp(key, "Socket") == 0) + req->socket_path = strdup(value); + else if (strcmp(key, "NotAfter") == 0) + req->notafter = atoll(value); + } + fclose(fp); + + /* If we successfully found at least a message, commit it to our linked list */ + if (req->message) { + if (!requests) { + head = &(pwd_requests); + requests = (struct request*)head; + } else + head = &requests->node; + insert(&req->node, head); + } else { + /* Clean up allocation if it wasn't a valid systemd ask file */ + if (req->socket_path) + free(req->socket_path); + free(req); + } +} + +/* Scans the target directory for any files prefixed with "ask." */ +void scan_ask_directory(const char *dir_path) +{ + struct dirent *entry; + char full_path[MAX_LINE]; + + DIR *dir = opendir(dir_path); + if (!dir) + error("Failed to open systemd ask-password directory: %m"); + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') + continue; + if (entry->d_name[0] != 'a') + continue; + /* Look specifically for files starting with "ask." */ + if (strncmp(entry->d_name, "ask.", 4) == 0) { + snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); + parse_ask_file(full_path); + } + } + closedir(dir); +} + +/* + * Pops the first systemd password request from the pending list. + * Transfers ownership of the allocated strings for message and socket_path + * to the caller. The caller is responsible for freeing them. + * Returns 1 if a request was popped, 0 if the list is empty. + */ +int coldstart_pop_request(char **message, char **socket_path) +{ + struct request *req; + + if (!requests) + return 0; + + /* Check if the doubly linked list is empty */ + if (pwd_requests.next == &pwd_requests) { + requests = NULL; + return 0; + } + + /* Get the first entry and extract the strings */ + req = list_entry(pwd_requests.next, struct request, node); + + *message = req->message; + *socket_path = req->socket_path; + + /* + * Defensive: clear the pointers from the struct before freeing it + * to clarify that ownership has been transferred to the caller. + */ + req->message = NULL; + req->socket_path = NULL; + + /* Remove from list and free the request container */ + delete(&req->node); + free(req); + + return 1; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/console.c new/showconsole-2.42/libconsole/console.c --- old/showconsole-2.40/libconsole/console.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/console.c 2026-06-22 15:46:21.000000000 +0200 @@ -153,9 +153,28 @@ } /* + * Console list + */ +list_t lcons = { &(lcons), &(lcons) }; + +static __attribute__((destructor)) void lcons_shutdown(void) +{ + struct console *c, *n; + + if (list_empty(&lcons)) + return; + + list_for_each_entry_safe(c, n, &lcons, node) { + delete(&c->node); + if (c->fd >= 0) + close(c->fd); + free(c); + } +} + +/* * The stdio file pointer for our log file */ -struct console *cons; FILE * flog = NULL; static int fdread = -1; static int fdfifo = -1; @@ -493,6 +512,39 @@ static char * ttail = temp; static volatile ssize_t tavail; +static void ask_for_password(void) attribute((noinline)); + +static int coldstart_active = 0; +static char *coldstart_socket_path = NULL; + +static void coldstart_next(void) +{ + char *msg = NULL; + char *sock = NULL; + + if (!coldstart_pop_request(&msg, &sock)) { + coldstart_active = 0; + return; + } + + coldstart_socket_path = sock; + + if (pwprompt) + free(pwprompt); + pwprompt = msg; + + if (!password) { + void *tmp = shm_malloc(MAX_PASSLEN + sizeof(int32_t)); + if (!tmp) + error("can not allocate string for password"); + password = (char *)tmp; + pwsize = (int32_t *)(tmp + MAX_PASSLEN); + } + password[0] = '\0'; + + ask_for_password(); +} + /* * Prepare I/O */ @@ -516,6 +568,9 @@ fdsock = listen; /* We use only ONE socket ... see also safeout() */ fdread = input; + /* Phase 1: Scan for pending systemd password queries */ + scan_ask_directory("/run/systemd/ask-password"); + if (fifo_name && fdfifo < 0) { struct stat st; errno = 0; @@ -540,13 +595,17 @@ if (fdsock >= 0) epoll_addread(fdsock, &epoll_socket_accept); - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd < 0) continue; epoll_addwrite(c->fd, &epoll_write_watchdog); } (void)mlockall(MCL_FUTURE); + + /* Phase 2: Start processing coldstart requests via epoll */ + coldstart_active = 1; + coldstart_next(); } /* @@ -747,10 +806,10 @@ warn("no message logging because /var file system is not accessible"); #endif - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd < 0) continue; - if (c->flags & CON_3215) + if (c->flags & (CON_3215|CON_SERIAL)) continue; (void)tcdrain(c->fd); /* Hold in sync with console */ } @@ -793,13 +852,21 @@ if (epfd >= 0) close(epfd); - if (password) + if (password) { memset(password, 0, MAX_PASSLEN); + munmap(password, MAX_PASSLEN+sizeof(int32_t)); + password = NULL; + } + + if (pwprompt) { + free(pwprompt); + pwprompt = NULL; + } - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->fd < 0) continue; - if (c->flags & CON_3215) + if (c->flags & (CON_3215|CON_SERIAL)) continue; (void)tcdrain(c->fd); } @@ -839,6 +906,9 @@ */ return 1; #endif + if (newc->flags & CON_SERIAL) + return 1; /* Keep serial console devices non-blocking to prevent freezes */ + if ((tflags = fcntl(newc->fd, F_GETFL)) < 0) warn("can not get terminal flags of %s", newc->tty); @@ -852,7 +922,6 @@ } /* Allocate a console */ -static list_t lcons = { &(lcons), &(lcons) }; static int consalloc(struct console **cons, char *name, const int cflags, const dev_t dev, int io) { struct console *newc; @@ -892,7 +961,7 @@ return 1; } -void getconsoles(struct console **cons, int io) +void getconsoles(int io) { static const struct { short flag; @@ -915,10 +984,6 @@ #endif int items; - - if (!cons) - error("error: console pointer empty"); - fc = fopen("/proc/consoles", "re"); if (!fc) { if (errno != ENOENT) @@ -978,7 +1043,6 @@ if (!c) goto err; - *cons = c; return; err: #ifdef TIOCGDEV @@ -995,7 +1059,6 @@ error("/dev/console is not a valid fallback\n"); free(tty); - *cons = c; return; } fallback: @@ -1007,8 +1070,6 @@ if (!consalloc(&c, tty, CON_CONSDEV, makedev(TTYAUX_MAJOR, 1), io)) error("/dev/console is not a valid fallback\n"); free(tty); - - *cons = c; } /* @@ -1026,7 +1087,7 @@ int saveerr = errno; if (fdc < 0) { - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->flags & CON_CONSDEV) { fdc = c->fd; break; @@ -1044,7 +1105,7 @@ parselog(trans, cnt); /* Parse and make copy of the input */ - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { int len; char *mesg; if (c->fd < 0) @@ -1080,7 +1141,7 @@ if (tavail > TRANS_BUFFER_SIZE) len = TRANS_BUFFER_SIZE; - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { size_t ret; if (c->fd < 0) continue; @@ -1088,9 +1149,6 @@ if (ret < 1) goto flush; len = ret; /* First make write out all but Second? */ - if (c->flags & CON_3215) - continue; - (void)tcdrain(c->fd); /* Write copy of input to real tty */ } thead += len; @@ -1107,7 +1165,7 @@ } } - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { size_t ret; if (c->fd < 0) continue; @@ -1119,9 +1177,6 @@ } break; } - if (c->flags & CON_3215) - continue; - (void)tcdrain(c->fd); /* Write copy of input to real tty */ } flush: flushlog(); @@ -1225,18 +1280,29 @@ asking = 0; /* Success! */ /* 1. Deliver the password and close the socket as well */ - if (pwd_client_fd >= 0) { - (void)do_answer_password(pwd_client_fd); - epoll_delete(pwd_client_fd); - close(pwd_client_fd); - pwd_client_fd = -1; + if (coldstart_active) { + if (coldstart_socket_path) { + password = frobnicate(password, *pwsize); + send_response_to_systemd(coldstart_socket_path, password); + password = frobnicate(password, *pwsize); + + free(coldstart_socket_path); + coldstart_socket_path = NULL; + } + } else { + if (pwd_client_fd >= 0) { + (void)do_answer_password(pwd_client_fd); + epoll_delete(pwd_client_fd); + close(pwd_client_fd); + pwd_client_fd = -1; + } } /* 2. Enable Kernel-Logging to the console Konsole */ klogctl(SYSLOG_ACTION_CONSOLE_ON, NULL, 0); /* 3. Close other waiting password processes */ - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->pid > 0 && c->pid != info.si_pid) { kill(c->pid, SIGTERM); } @@ -1244,10 +1310,14 @@ c->pid = -1; /* we are done now */ } } + + /* 4. Advance coldstart */ + if (coldstart_active) + coldstart_next(); } } else { /* Clear Zombies */ - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->pid == info.si_pid) { c->pid = -1; } @@ -1272,7 +1342,7 @@ static void socket_handler(int fd) { struct ucred cred = {}; - unsigned char magic[2]; + unsigned char magic[2] = {0}; const char *enqry; char *arg = NULL; socklen_t clen; @@ -1284,32 +1354,6 @@ goto out; } - ret = safein(fd, &magic[0], sizeof(magic)); - if (ret < 0) { - warn("can not read request magic from UNIX socket"); - goto out; - } - - if (magic[1] == '\002') { - unsigned char alen; - - ret = safein(fd, &alen, sizeof(unsigned char)); - if (ret < 0) { - warn("can not get message len from UNIX socket"); - goto out; - } - - arg = calloc(alen, sizeof(char)); - if (!arg) - error("can not allocate memory for message from socket"); - - ret = safein(fd, arg, alen); - if (ret < 0) { - warn("can not get message len from UNIX socket"); - goto out; - } - } - clen = sizeof(struct ucred); ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &clen); if (ret < 0) { @@ -1341,8 +1385,39 @@ goto out; } + ret = safein(fd, &magic[0], sizeof(magic)); + if (ret < (ssize_t)sizeof(magic)) { + warn("can not read request magic from UNIX socket"); + goto out; + } + + if (magic[1] == '\002') { + unsigned char alen; + + ret = safein(fd, &alen, sizeof(unsigned char)); + if (ret < (ssize_t)sizeof(unsigned char)) { + warn("can not get message len from UNIX socket"); + goto out; + } + + arg = calloc(alen, sizeof(char)); + if (!arg) + error("can not allocate memory for message from socket"); + + ret = safein(fd, arg, alen); + if (ret < (ssize_t)alen) { + warn("can not get message len from UNIX socket"); + goto out; + } + } + switch (magic[0]) { case MAGIC_ASK_PWD: + if (magic[1] != '\002') { + errno = EINVAL; + warn("Got password invalid request for prompt"); + goto out; + } #ifdef DEBUG warn("Got password request for prompt >%s<", arg); #endif @@ -1381,6 +1456,11 @@ break; case MAGIC_CHROOT: + if (magic[1] != '\002') { + errno = EINVAL; + warn("Got password invalid chroot request"); + goto out; + } new_root(arg); @@ -1419,7 +1499,7 @@ if (fdread >= 0) { struct console *c; - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->flags & CON_CONSDEV) { if (c->fd > 0) { epoll_delete(fdread); @@ -1445,7 +1525,7 @@ if (fdread < 0) { struct console *c; - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { if (c->flags & CON_CONSDEV) { if (c->fd > 0) { char ptsname[NAME_MAX+1]; @@ -1565,7 +1645,7 @@ break; } out: /* We are done */ - if (fd > 0) { + if (fd >= 0) { epoll_delete(fd); close(fd); fd = -1; @@ -1593,7 +1673,7 @@ struct console *c; size_t len; - if (!pwprompt && !*pwprompt) + if (!pwprompt || !*pwprompt) return; len = strlen(pwprompt); @@ -1611,7 +1691,7 @@ asking = 1; /* Show only our question about password/passphrase */ /* pwprompt */ - list_for_each_entry(c, &cons->node, node) { + list_for_each_entry(c, &lcons, node) { int pfd; if (c->fd < 0 || !c->tty) continue; @@ -1627,8 +1707,9 @@ char *message; int eightbit; int len, fdc, tflags; +#if defined(__s390__) || defined(__s390x__) int vmcpfd = -1; - +#endif if (fdfifo >= 0) close(fdfifo); if (fdsock >= 0) @@ -1647,7 +1728,7 @@ dup2(c->fd, 1); currenttty = c->tty; /* Used in readpw() in case of an error */ - list_for_each_entry(d, &cons->node, node) + list_for_each_entry(d, &lcons, node) if (d->fd >= 0) { close(d->fd); d->fd = -1; @@ -1839,7 +1920,7 @@ c->pid = -1; /* Terminate all other password asking children for syncronious mode */ - list_for_each_entry(d, &cons->node, node) { + list_for_each_entry(d, &lcons, node) { if (d->pid > 0 && d->pid != c->pid) { kill(d->pid, SIGTERM); /* Just wait to avoid being flooded with zombies */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/libconsole.h new/showconsole-2.42/libconsole/libconsole.h --- old/showconsole-2.40/libconsole/libconsole.h 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/libconsole.h 2026-06-22 15:46:21.000000000 +0200 @@ -63,7 +63,7 @@ #define weak_symbol(name) _weak_pragma(name) _declare(name) __attribute__((weak)) /* external function in program */ -extern void error (const char *fmt, ...); +extern void error (const char *fmt, ...) __attribute__((noreturn)); /* console.c */ @@ -138,13 +138,18 @@ extern void safeIO (void); extern void closeIO(void); -extern struct console *cons; -extern void getconsoles(struct console **cons, int io); +extern list_t lcons; +extern void getconsoles(int io); extern void epoll_write_watchdog(int) attribute((noinline)); /* chroot.c */ extern void new_root(const char *root); +/* coldstart.c */ +extern void scan_ask_directory(const char *dir_path); +extern void send_response_to_systemd(const char *socket_path, const char *password); +extern int coldstart_pop_request(char **message, char **socket_path); + /* devices.c */ extern char *charname(const char *dev); extern char *chardev(const dev_t cons); @@ -212,8 +217,8 @@ extern int request_tty(const char *tty); /* vmcp.c */ -#if defined(__s390__) || defined(__s390x__) extern int isinteger(const char *str); +#if defined(__s390__) || defined(__s390x__) extern int openvmcp(void); extern void clearvmcp(void); extern char* queryterm(int fd); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/log.c new/showconsole-2.42/libconsole/log.c --- old/showconsole-2.40/libconsole/log.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/log.c 2026-06-22 15:46:21.000000000 +0200 @@ -182,7 +182,7 @@ if (gettimeofday(&now, NULL) == 0) { struct timespec abstime; - int err; + int err = 0; now.tv_usec += msec * 1000; while (now.tv_usec >= 1000000) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/proc.c new/showconsole-2.42/libconsole/proc.c --- old/showconsole-2.40/libconsole/proc.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/proc.c 2026-06-22 15:46:21.000000000 +0200 @@ -68,8 +68,10 @@ if (dr->d_name[0] == '.') continue; len = readlinkat(dirfd(dir), dr->d_name, &tmp[0], LINE_MAX); - tmp[len] = '\0'; - fprintf(stderr, "/proc/%d/fd/%s %s\n", (int)pid, dr->d_name, tmp); + if (len >= 0) { + tmp[len] = '\0'; + fprintf(stderr, "/proc/%d/fd/%s %s\n", (int)pid, dr->d_name, tmp); + } } closedir(dir); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/readpw.c new/showconsole-2.42/libconsole/readpw.c --- old/showconsole-2.40/libconsole/readpw.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/readpw.c 2026-06-22 15:46:21.000000000 +0200 @@ -36,7 +36,7 @@ ssize_t readpw(int fd, char *pass, int eightbit) { char *ptr = pass; - struct chardata cp; + struct chardata cp = {0}; int ret; cp.eol = *ptr = '\0'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/shm.c new/showconsole-2.42/libconsole/shm.c --- old/showconsole-2.40/libconsole/shm.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/shm.c 2026-06-22 15:46:21.000000000 +0200 @@ -76,6 +76,7 @@ void *area; char *template; int shmfd = -1; + int flags = MAP_LOCKED|MAP_SHARED; if (devshm) { int ret; @@ -93,7 +94,10 @@ error("can not allocate shared memory object"); } - area = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_LOCKED|MAP_SHARED|MAP_ANONYMOUS, shmfd, 0); + if (shmfd == -1) + flags |= MAP_ANONYMOUS; + + area = mmap(NULL, size, PROT_READ|PROT_WRITE, flags, shmfd, 0); if (area == MAP_FAILED) error("can not map shared memory object into memory"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/socket.c new/showconsole-2.42/libconsole/socket.c --- old/showconsole-2.40/libconsole/socket.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/socket.c 2026-06-22 15:46:21.000000000 +0200 @@ -45,9 +45,10 @@ ret = bind(fd, &su, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1)); if (ret < 0) { + int err = errno; close(fd); fd = -1; - if (errno != EADDRINUSE) + if (err != EADDRINUSE) warn("can not bind a name to UNIX socket"); else fd = -2; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/libconsole/vmcp.c new/showconsole-2.42/libconsole/vmcp.c --- old/showconsole-2.40/libconsole/vmcp.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/libconsole/vmcp.c 2026-06-22 15:46:21.000000000 +0200 @@ -22,13 +22,6 @@ #include <sys/ioctl.h> #include "libconsole.h" -#if defined(__s390__) || defined(__s390x__) - -#define VMCP_DEVICE_NODE "/dev/vmcp" -#define VMCP_GETSIZE _IOR(0x10, 3, int) -#define VMCP_SETBUF _IOW(0x10, 2, int) -#define VMCP_GETCODE _IOR(0x10, 1, int) - int isinteger(const char *str) { int errs = errno, ret = 1; @@ -54,6 +47,13 @@ return ret; } +#if defined(__s390__) || defined(__s390x__) + +#define VMCP_DEVICE_NODE "/dev/vmcp" +#define VMCP_GETSIZE _IOR(0x10, 3, int) +#define VMCP_SETBUF _IOW(0x10, 2, int) +#define VMCP_GETCODE _IOR(0x10, 1, int) + static char *more, *hold; static int spooling; @@ -224,6 +224,13 @@ void warning3215(int fd) { + /* + * Warning: Do not translate this test as it might inlude then so called + * umlauts which in fact can not be encoded for the 3215 console interface. + * The 3215 console driver work in fact with EBCDIC codepage and the + * kernel has to translate such umlauts (multi or single bytes) with the + * correct EBCDIC character table (for german e.g. IBM-1141 or IBM-273). + */ (void) writevmcp(fd, "MESSAGE * WARNING: 3215 mode. Password visible!"); (void) writevmcp(fd, "MESSAGE * Ensure nobody is watching the screen."); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/listing.h new/showconsole-2.42/listing.h --- old/showconsole-2.40/listing.h 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/listing.h 2026-06-22 15:46:21.000000000 +0200 @@ -11,6 +11,9 @@ #ifndef _LISTING_H_ #define _LISTING_H_ +#ifdef DEBUG +# include <assert.h> +#endif #ifndef offsetof # define offsetof(type,memb) __builtin_offsetof(type,memb) @@ -18,13 +21,17 @@ typedef struct list_struct { struct list_struct * next, * prev; -} list_t; +} __attribute__((may_alias)) list_t; /* * Insert new entry as next member. */ -static inline void insert (list_t * new, list_t * here) +static inline __attribute__((always_inline)) void insert (list_t * new, list_t * here) { +#ifdef DEBUG + assert(new != NULL && here != NULL); + assert(here->next != NULL && here->prev != NULL); +#endif list_t * prev = here; list_t * next = here->next; @@ -45,16 +52,26 @@ /* * Remove entries, note that the pointer its self remains. */ -static inline void delete (list_t * entry) +#define LIST_POISON1 ((void *) 0x100) +#define LIST_POISON2 ((void *) 0x200) + +static inline __attribute__((always_inline)) void delete (list_t * entry) { +#ifdef DEBUG + assert(entry != NULL); + assert(entry->next != LIST_POISON1 && entry->prev != LIST_POISON2); +#endif list_t * prev = entry->prev; list_t * next = entry->next; next->prev = prev; prev->next = next; + + entry->next = (list_t *)LIST_POISON1; + entry->prev = (list_t *)LIST_POISON2; } -static inline void join(list_t *list, list_t *head) +static inline __attribute__((always_inline)) void join(list_t *list, list_t *head) { list_t *first = list->next; @@ -70,7 +87,7 @@ } } -static inline int list_empty(list_t *head) +static inline __attribute__((always_inline)) int list_empty(list_t *head) { return head->next == head; } @@ -79,7 +96,7 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ((type *)( (char *)(__mptr) - offsetof(type,member) )); })) #define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) + for (pos = (head)->next; __builtin_prefetch(pos->next, 0, 3), pos != (head); pos = pos->next) #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.40/showconsole.c new/showconsole-2.42/showconsole.c --- old/showconsole-2.40/showconsole.c 2026-04-24 09:28:22.000000000 +0200 +++ new/showconsole-2.42/showconsole.c 2026-06-22 15:46:21.000000000 +0200 @@ -83,6 +83,9 @@ if (opt && *opt++ == '-' && *opt++ == 'r' && *opt == '\0') goto out; + if (!argv[1]) + goto out; + if ((fd = open(argv[1], O_WRONLY|O_NOCTTY)) < 0) error("can not open %s: %m", argv[1]); @@ -103,8 +106,8 @@ } else if (argc > 2) error("Usage: %s [-n]", myname); - getconsoles(&cons, 0); - list_for_each_entry(c, &cons->node, node) { + getconsoles(0); + list_for_each_entry(c, &lcons, node) { if (c->flags & CON_CONSDEV) { if (numeric) printf("%u %u\n", major(c->dev), minor(c->dev));
