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-04-16 17:25:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/blog (Old) and /work/SRC/openSUSE:Factory/.blog.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "blog" Thu Apr 16 17:25:12 2026 rev:24 rq:1346447 version:2.38 Changes: -------- --- /work/SRC/openSUSE:Factory/blog/blog.changes 2026-03-20 21:19:43.501298343 +0100 +++ /work/SRC/openSUSE:Factory/.blog.new.11940/blog.changes 2026-04-16 17:25:22.639497950 +0200 @@ -1,0 +2,12 @@ +Mon Apr 13 12:47:36 UTC 2026 - Dr. Werner Fink <[email protected]> + +- Update to version 2.38 + * Silent debugging messages in epoll algorithm (boo#1261699) + * Make it work on 3215 console of s390 + means no tcdrain() for 3215, no blocking writes, not more then + 130 characters per line, no \r, finalize lines with \n. + Nevertheless use a blocking read for password requests. + Make automatic CLEAR an kernel command line option with + the parameter blog.timeout=0 (boo#1261697) + +------------------------------------------------------------------- Old: ---- showconsole-2.37.tar.gz New: ---- showconsole-2.38.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ blog.spec ++++++ --- /var/tmp/diff_new_pack.aE9dPV/_old 2026-04-16 17:25:23.263523659 +0200 +++ /var/tmp/diff_new_pack.aE9dPV/_new 2026-04-16 17:25:23.267523824 +0200 @@ -17,7 +17,7 @@ Name: blog -Version: 2.37 +Version: 2.38 %define sonum 2 Release: 0 Summary: Boot logging ++++++ showconsole-2.37.tar.gz -> showconsole-2.38.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/Makefile new/showconsole-2.38/Makefile --- old/showconsole-2.37/Makefile 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/Makefile 2026-04-13 14:11:49.000000000 +0200 @@ -15,7 +15,7 @@ DEBUG = DESTDIR = MAJOR := 2 -MINOR := 37 +MINOR := 38 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.37/blogd.8.in new/showconsole-2.38/blogd.8.in --- old/showconsole-2.37/blogd.8.in 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/blogd.8.in 2026-04-13 14:11:49.000000000 +0200 @@ -45,6 +45,24 @@ .B \-f This option is used at shutdown, that is reboot, halt, and poweroff but also for kexec. +.SH BOOT PARAMETERS +On +.B s390x +(64-bit IBM System/390) and +.B z/Architecture +the +.B blogd +knows currently one kernel command line parameter +.BI blog\&.timeout= <integer> +with +.I <integer> +the timeout for the +.B MORE +prompt on +.I 3215 +console. If set to +.I 0 +the boot process does not need manual support. .SH SIGNALS .B blogd knows a few signal to contol its behavior. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/blogd.c new/showconsole-2.38/blogd.c --- old/showconsole-2.37/blogd.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/blogd.c 2026-04-13 14:11:49.000000000 +0200 @@ -216,7 +216,7 @@ if (newfd != c->fd) close(newfd); epoll_addwrite(c->fd, &epoll_write_watchdog); - ret = 1; + ret = 1; #if defined(__s390__) || defined(__s390x__) if (major(c->dev) == 4 && minor(c->dev) == 64) break; @@ -345,23 +345,29 @@ o.c_cc[VMIN] = CMIN; } #if defined(__s390__) || defined(__s390x__) - if (major(c->dev) == 4 && minor(c->dev) == 64 && final == 0) { - char *msg; - int vmcp; - - vmcp = openvmcp(); - if (vmcp) { - msg = queryterm(vmcp); - if (msg) { - parseterm(msg); - free(msg); - setterm(vmcp); + if ((c->flags & CON_3215) && final == 0) { + char *timeout; + + parse_cmdline(); /* Parse the kernel command line for blog.<key>=<val> */ + timeout = value_cmdline("timeout"); + + if (timeout && isinteger(timeout)) { + int vmcp = openvmcp(); + if (vmcp) { + char *msg = queryterm(vmcp); + if (msg) { + parseterm(msg); + free(msg); + setterm(vmcp, timeout); + } + close(vmcp); + atexit(vmcp_handler); /* Register vmcp restore exit handler */ } - close(vmcp); - atexit(vmcp_handler); /* Register vmcp restore exit handler */ + ioctl(c->fd, TIOCCBRK); + usleep(1000); } - ioctl(c->fd, TIOCCBRK); - usleep(1000); + + free_cmdline(); } #endif } @@ -513,7 +519,7 @@ } else { flags &= ~(O_NONBLOCK); - flags |= O_NOCTTY; + flags |= O_NOCTTY; if (fcntl(0, F_SETFL, flags) < 0) list_for_each_entry(c, &cons->node, node) { if (c->fd < 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/console.c new/showconsole-2.38/libconsole/console.c --- old/showconsole-2.37/libconsole/console.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/console.c 2026-04-13 14:11:49.000000000 +0200 @@ -1,8 +1,9 @@ /* * console.c * - * Copyright 2000,2015,2025 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany. - * Copyright 2015 SuSE Linux GmbH. + * Copyright 2000,2015,2025,2026 Werner Fink, 2000 SUSE GmbH Nuernberg, Germany. + * Copyright 2015 SUSE Linux GmbH. + * 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 @@ -155,7 +156,7 @@ * The stdio file pointer for our log file */ struct console *cons; -static FILE * flog = NULL; +FILE * flog = NULL; static int fdread = -1; static int fdfifo = -1; @@ -261,6 +262,135 @@ return r; } +#if defined(__s390__) || defined(__s390x__) +static ssize_t copyout3215 (int fd, const void *ptr, size_t cnt, ssize_t max) +{ + /* + * Workaround for s390x console mode 3215: + * 1. 3215 can not handle carriage return (\r). Instead of just dropping it, + * we translate it to a newline (\n) if the line is not empty, to simulate + * overwriting without concatenating strings indefinitely. + * 2. Be sure that there is a \n after 130 chars to flush the device 3215 driver. + */ + const char *conbuf = (const char *)ptr; + /* + * Missing: detect lines across chunks + */ + size_t line_start = 0; + size_t i = 0; + ssize_t ret, total_written = 0; + static int skip_next_lf = 0; /* It remembers \r\n across chunk boundaries. */ + + while (i < cnt) { + size_t current_line_len; + char linebuf[132]; /* For atomar write: 130 char max + \n + rest */ + + /* 0. Catch CRLF across chunks */ + if (skip_next_lf && conbuf[i] == '\n') { + skip_next_lf = 0; + line_start = i+1; + i++; + continue; + } + skip_next_lf = 0; + + current_line_len = i - line_start; + + /* 1. Search for end of line (could be \n, \r or 130 char limit reached) */ + if (conbuf[i] == '\n' || conbuf[i] == '\r') { + if (current_line_len > 0) { + memcpy(linebuf, &conbuf[line_start], current_line_len); + linebuf[current_line_len] = '\n'; + + ret = copyout(fd, linebuf, current_line_len + 1, max); + if (ret < 0) + goto error; + total_written += ret; + } else if (conbuf[i] == '\n') { + /* + * Only create a blank line with a true \n! + * An isolated \r at the beginning of a line will be silently ignored. + */ + ret = copyout(fd, "\n", 1, max); + if (ret < 0) + goto error; + total_written += ret; + } + + if (conbuf[i] == '\r') { + if ((i+1 < cnt) && conbuf[i+1] == '\n') { + i++; /* Ignore CRLF in the same chunk */ + } else if (i+1 == cnt) { + skip_next_lf = 1; /* Set marker for the next chunk at 0. */ + } + } + + line_start = i+1; + i = line_start; + continue; + } + + /* 2. Ouch: Reached 130 without any newline */ + if (current_line_len >= 130) { + /* Are there any spaces in the last 130 characters? */ + size_t last_space = i; + int found_space = 0; + + for (size_t s = i; s > line_start; s--) { + if (conbuf[s] == ' ') { + last_space = s; + found_space = 1; + break; + } + } + + if (found_space) { + /* Copy up to the spaces */ + size_t write_len = last_space - line_start; + memcpy(linebuf, &conbuf[line_start], write_len); + linebuf[write_len] = '\n'; + + ret = copyout(fd, &conbuf[line_start], write_len + 1, max); + if (ret < 0) + goto error; + total_written += ret; + + line_start = last_space + 1; /* continue after the space */ + } else { + /* No space found -> hard newline at 130 chars */ + memcpy(linebuf, &conbuf[line_start], 130); + linebuf[130] = '\n'; + + ret = copyout(fd, &conbuf[line_start], 130 + 1, max); + if (ret < 0) + goto error; + total_written += ret; + + line_start = line_start + 130; + } + i = line_start; + continue; + } + i++; + } + + /* 3. final write out the rest */ + if (line_start < cnt) { + ret = copyout(fd, &conbuf[line_start], cnt - line_start, max); + if (ret < 0) + goto error; + total_written += ret; + } + + if (total_written != cnt) /* We might not return more or less then we got from the outer ringbuffer */ + total_written = cnt; + + return total_written; +error: + return -1; +} +#endif + /* * Twice used: safe in */ @@ -452,9 +582,11 @@ ret = 1; if (evlist[n].events & (EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLERR)) { +#ifdef DEBUG if (evlist[n].events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) { warn("epoll returned RDHUP, HUP or ERR on fd %d", fd); } +#endif efunc(fd); continue; } @@ -609,13 +741,17 @@ struct console *c; int ret, n = 20; +#ifdef DEBUG /* Maybe we've catched a signal, therefore */ if (!flog && !nsigsys) warn("no message logging because /var file system is not accessible"); +#endif list_for_each_entry(c, &cons->node, node) { if (c->fd < 0) continue; + if (c->flags & CON_3215) + continue; (void)tcdrain(c->fd); /* Hold in sync with console */ } @@ -663,6 +799,8 @@ list_for_each_entry(c, &cons->node, node) { if (c->fd < 0) continue; + if (c->flags & CON_3215) + continue; (void)tcdrain(c->fd); } return; @@ -680,13 +818,25 @@ return 0; } newc->tlock = 0; - newc->max_canon = _POSIX_MAX_CANON; +#if defined(__s390__) || defined(__s390x__) + if (newc->flags & CON_3215) + newc->max_canon = 130; + else +#endif + newc->max_canon = _POSIX_MAX_CANON; memset(&newc->ltio, 0, sizeof(newc->ltio)); memset(&newc->otio, 0, sizeof(newc->otio)); memset(&newc->ctio, 0, sizeof(newc->ctio)); #if defined(__s390__) || defined(__s390x__) - if (major(newc->dev) == 4 && minor(newc->dev) == 64) + if (newc->flags & CON_3215) + /* + * WARNING: Do not remove this early return! + * The s390x 3215 console MUST remain in O_NONBLOCK mode. + * Since blogd is single-threaded, setting this half-duplex device + * to blocking would completely freeze the daemon as soon as the + * kernel buffer fills up (e.g. during heavy \r floods from fsck). + */ return 1; #endif if ((tflags = fcntl(newc->fd, F_GETFL)) < 0) @@ -720,6 +870,13 @@ newc->dev = dev; newc->pid = -1; +#if defined(__s390__) || defined(__s390x__) + if (newc->flags & CON_3215) + newc->out = copyout3215; + else +#endif + newc->out = copyout; + if (io && !consinitIO(newc)) { free(newc); return 0; @@ -804,7 +961,14 @@ if (sscanf(dev, "%u:%u", &maj, &min) != 2) error("can not determine device numbers for %s: %m", tty); - +#if defined(__s390__) || defined(__s390x__) + if (maj == 4 && min == 64) + flags |= CON_3215; + if (maj == 4 && min >= 65) + flags |= CON_SCLP; + else if (maj == 227 && min >= 1) + flags |= CON_3270; +#endif consalloc(&c, tty, flags, makedev(maj, min), io); free(tty); } @@ -920,10 +1084,12 @@ size_t ret; if (c->fd < 0) continue; - ret = copyout(c->fd, thead, len, c->max_canon); + ret = c->out(c->fd, thead, len, c->max_canon); 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; @@ -945,7 +1111,7 @@ size_t ret; if (c->fd < 0) continue; - ret = copyout(c->fd, trans, cnt, c->max_canon); + ret = c->out(c->fd, trans, cnt, c->max_canon); if (ret < 1) { if (cnt <= (size_t)(tend - ttail)) { memcpy(ttail, trans, cnt); @@ -953,6 +1119,8 @@ } break; } + if (c->flags & CON_3215) + continue; (void)tcdrain(c->fd); /* Write copy of input to real tty */ } flush: @@ -1458,7 +1626,7 @@ struct console *d; char *message; int eightbit; - int len, fdc; + int len, fdc, tflags; if (fdfifo >= 0) close(fdfifo); @@ -1506,6 +1674,15 @@ if (fdc > 1) close(fdc); + /* + * Mandatory: Remove none blocking mode for reading + * For mainframes console required to enforce the + * driver to READ CCW on 3215. + */ + tflags = fcntl(0, F_GETFL); + if (tflags >= 0) + fcntl(0, F_SETFL, tflags & ~O_NONBLOCK); + if (c->flags & CON_CONSDEV) { int wait = 200; while (wait > 0 && (len = klogctl(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0)) > 0) { @@ -1517,11 +1694,22 @@ again: clear_input(0); #if defined(__s390__) || defined(__s390x__) - if ((major(c->dev) == 4 && minor(c->dev) >= 65) || - (major(c->dev) == 227 && minor(c->dev) >= 1)) + if (c->flags & CON_3215) { + /* + * The 3215 console MUST have a trailing newline. + * Otherwise the half-duplex driver won't flush the write buffer + * and blocks the subsequent readpw() call forever. + */ + len = asprintf(&message, "\n===>> %s:\n", pwprompt); + } else if (c->flags & (CON_SCLP|CON_3270)) { + /* + * The 3270 console can do ANSI colouring and carriage returns, + * as well as the sclp consoles which are a full featured ttys. + */ len = asprintf(&message, BOLD RED "\n\r%s: " NORM, pwprompt); - else - len = asprintf(&message, "\n\r===>> %s: ", pwprompt); + } else { + len = asprintf(&message, "\n===>> %s: ", pwprompt); + } #else if (c->flags & CON_SERIAL) len = asprintf(&message, BOLD RED "\n\r%s: " NORM, pwprompt); @@ -1532,12 +1720,48 @@ warn("can not set password prompt"); _exit(1); } - safeout(1, message, len, c->max_canon); + /* + * Do not use safeout() here! safeout() drops the message + * after 100ms on EAGAIN. We MUST wait and insist on writing the prompt. + */ + { + size_t written = 0; + while (written < len) { + ssize_t p = write(1, message + written, len - written); + if (p < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* * Driver buffer is full (e.g. fsck traffic jam). + * Use io.c helper to wait efficiently via ppoll() + * until the terminal accepts data again. + */ + can_write(1, 100); + continue; + } + warn("can not set password prompt on %s: %m", c->tty); + break; /* Hard error */ + } + written += p; + } + } free(message); /* We read byte for byte */ newtio = c->ctio; +#if defined(__s390__) || defined(__s390x__) + if (c->flags & CON_3270) + /* + * ONLY the 3270 block-mode terminal MUST keep ICANON enabled! + * Otherwise the tty3270 driver switches to raw mode and fails + * to apply the non-display hardware attribute to the input field. + */ + newtio.c_lflag &= ~(ECHO); + else + newtio.c_lflag &= ~(ECHO|ICANON); +#else newtio.c_lflag &= ~(ECHO|ICANON); +#endif newtio.c_lflag |= ECHONL; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/dir.c new/showconsole-2.38/libconsole/dir.c --- old/showconsole-2.37/libconsole/dir.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/dir.c 2026-04-13 14:11:49.000000000 +0200 @@ -15,7 +15,7 @@ #include "libconsole.h" /* - * push and popd direcotry changes + * push and popd directory changes */ typedef struct pwd_struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/libconsole.h new/showconsole-2.38/libconsole/libconsole.h --- old/showconsole-2.37/libconsole/libconsole.h 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/libconsole.h 2026-04-13 14:11:49.000000000 +0200 @@ -40,6 +40,9 @@ # ifndef typeof # define typeof __typeof__ # endif +# ifndef unused +# define unused __unused__ +# endif #endif #ifndef attribute # define attribute(attr) __attribute__(attr) @@ -104,6 +107,7 @@ int flags; int fd, tlock; ssize_t max_canon; + ssize_t (*out)(int, const void *, size_t, ssize_t); struct termios ltio, otio, ctio; }; @@ -114,6 +118,9 @@ #define CON_ANYTIME (16) /* Safe to call when cpu is offline */ #define CON_BRL (32) /* Used for a braille device */ #define CON_SERIAL (64) /* Serial line */ +#define CON_3215 (128) /* s390x 3215 halfduplex console */ +#define CON_3270 (256) /* s390x 3270 console */ +#define CON_SCLP (512) /* s390x sclp terminals */ extern sigset_t omask; extern int final; @@ -178,6 +185,9 @@ /* proc.c */ extern char *proc2exe(const pid_t pid); extern void list_fd(const pid_t pid); +extern void parse_cmdline(void); +extern char* value_cmdline(const char*); +void free_cmdline(void); /* readpw.c */ extern ssize_t readpw(int fd, char *pass, int eightbit); @@ -203,11 +213,12 @@ /* vmcp.c */ #if defined(__s390__) || defined(__s390x__) -int openvmcp(void); -char* queryterm(int fd); -int setterm(int fd); -int restoreterm(int fd); -void parseterm(char *msg); +extern int isinteger(const char *str); +extern int openvmcp(void); +extern char* queryterm(int fd); +extern int setterm(int fd, char *tout); +extern int restoreterm(int fd); +extern void parseterm(char *msg); #endif #define MAX_PASSLEN LINE_MAX diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/log.c new/showconsole-2.38/libconsole/log.c --- old/showconsole-2.37/libconsole/log.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/log.c 2026-04-13 14:11:49.000000000 +0200 @@ -36,7 +36,7 @@ /* * The stdio file pointer for our log file */ -static FILE *flog = NULL; +extern FILE *flog; /* * Signal control for writing on log file @@ -634,15 +634,17 @@ FILE *open_logging(int fd) { + FILE *log; + lock(&llock); - flog = fdopen(fd, "a"); - if (!flog) { + log = fdopen(fd, "a"); + if (!log) { unlock(&llock); - error("Can not open boot loggin file"); + error("Can not open boot logging file"); } unlock(&llock); - return flog; + return log; } FILE *close_logging(void) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/proc.c new/showconsole-2.38/libconsole/proc.c --- old/showconsole-2.37/libconsole/proc.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/proc.c 2026-04-13 14:11:49.000000000 +0200 @@ -13,7 +13,9 @@ #include <limits.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/types.h> +#include "listing.h" #include "libconsole.h" /* @@ -71,3 +73,139 @@ } closedir(dir); } + +/* + * Parse kernel command line for our entries + */ +static list_t lparameter = { &(lparameter), &(lparameter) }; +typedef struct parameter_s { + list_t handle; + char *val; + char *key; +} parameter_t; +static parameter_t *parameter = (parameter_t*)0; + +void parse_cmdline(void) { + char buf[4096]; + list_t *head; + FILE *fp; + +#ifdef DEBUG_PROC + fp = fopen("cmdline", "r"); +#else + fp = fopen("/proc/cmdline", "r"); +#endif + if (!fp) + return; + + if (fgets(buf, sizeof(buf), fp)) { + char *saveptr; + char *token = strtok_r(buf, " \n", &saveptr); + + while (token) { + const char *prefix = "blog."; + const size_t plen = strlen(prefix); + + if (strncmp(token, prefix , plen) == 0) { + char *kv = token + plen; + char *eq = strchr(kv, '='); + + if (eq) { + parameter_t *pm; + int exists = 0; + + *eq = '\0'; + char *key = kv; + char *val = eq + 1; + + if (*val == '\0' || *val == ' ') { + *eq = '='; /* restore token for strtok_r */ + token = strtok_r(NULL, " \n", &saveptr); + continue; + } + + list_for_each_entry(pm, &lparameter, handle) { + if (strcmp(pm->key, key) == 0) { + free(pm->val); + pm->val = strdup(val); + exists++; + } + } + if (!exists) { + if (posix_memalign((void**)&pm, sizeof(void*), alignof(parameter_t)+strlen(key)+1) != 0 || !pm) + error("memory allocation"); + pm->key = ((char*)pm)+alignof(parameter_t); + strcpy(pm->key, key); + pm->val = strdup(val); + + if (!parameter) { + head = &lparameter; + parameter = (parameter_t *)head; + } else + head = &(parameter)->handle; + insert(&pm->handle, head); + } + *eq = '='; /* restore token for strtok_r */ + } + } + token = strtok_r(NULL, " \n", &saveptr); + } + } + fclose(fp); +} + +char* value_cmdline(const char* key) { + parameter_t *pm; + list_for_each_entry(pm, &lparameter, handle) { + if (strcmp(pm->key, key) == 0) { + return pm->val; + } + } + return (char*)0; +} + +void free_cmdline(void) { + parameter_t *pm, *n; + list_for_each_entry_safe(pm, n, &lparameter, handle) { + free(pm->val); + delete(&pm->handle); + free(pm); + } +} +#ifdef DEBUG_PROC +static int _isinteger(const char *str) +{ + int errs = errno, ret = 1; + char *endptr; + + errno = 0; + long attribute((unused)) val = strtol(str, &endptr, 10); + + /* Check if no digits were found at all */ + if (str == endptr) + ret = 0; + + /* Check for overflow or underflow */ + if (errno == ERANGE) + ret = 0; + + /* Check for trailing non-numeric characters (e.g., "123abc") */ + if (*endptr != '\0') + ret = 0; + + errno = errs; + return ret; +} +int main(void) +{ + parameter_t *pm; + char *key; + parse_cmdline(); + list_for_each_entry(pm, &lparameter, handle) { + printf("key %s = val %s\n", pm->key, pm->val); + } + key = value_cmdline("timeout"); + if (key) + printf("%s %d\n", key, _isinteger(key)); +} +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/readpw.c new/showconsole-2.38/libconsole/readpw.c --- old/showconsole-2.37/libconsole/readpw.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/readpw.c 2026-04-13 14:11:49.000000000 +0200 @@ -39,15 +39,32 @@ struct chardata cp; int ret; - cp.eol = *ptr = '\0'; + cp.eol = *ptr = '\0'; while (cp.eol == '\0') { char ascval, c; errno = 0; - +#if 0 + /* + * Sidemark: DO NOT USE THIS ON 3215 OF S390 + * Wait in input without busy waiting. + * If we use a negative timeout the ppoll() blocks + * up to the point where even a halfduplex 3215 + * console provides input data. + */ + if (!can_read(fd, -1)) { + if (errno == EINTR) + continue; + warn("can_read failed on %s: %m", currenttty); + return -1; + } +#endif ret = read(fd, &c, 1); if (ret < 0) { if (errno == EINTR || errno == EAGAIN) { + /* + * Due to can_read() EAGAIN should not happen. + */ usleep(250000); continue; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/showconsole-2.37/libconsole/vmcp.c new/showconsole-2.38/libconsole/vmcp.c --- old/showconsole-2.37/libconsole/vmcp.c 2026-03-18 12:18:33.000000000 +0100 +++ new/showconsole-2.38/libconsole/vmcp.c 2026-04-13 14:11:49.000000000 +0200 @@ -25,6 +25,31 @@ #define VMCP_SETBUF _IOW(0x10, 2, int) #define VMCP_GETCODE _IOR(0x10, 1, int) +int isinteger(const char *str) +{ + int errs = errno, ret = 1; + long attribute((unused)) val; + char *endptr; + + errno = 0; + val = strtol(str, &endptr, 10); + + /* Check if no digits were found at all */ + if (str == endptr) + ret = 0; + + /* Check for overflow or underflow */ + if (errno == ERANGE) + ret = 0; + + /* Check for trailing non-numeric characters (e.g., "123abc") */ + if (*endptr != '\0') + ret = 0; + + errno = errs; + return ret; +} + int openvmcp(void) { return open(VMCP_DEVICE_NODE, O_RDWR|O_NOCTTY); @@ -41,55 +66,59 @@ buffersize = num * pagesize; if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) - goto out; + goto out; do { rc = write(fd, question, strlen(question)); - if (rc < 0) { + if (rc < 0) { if (errno != EINTR) goto out; - } + } } while (rc < 0); if (ioctl(fd, VMCP_GETCODE, &rc) == -1) - goto out; + goto out; if (ioctl(fd, VMCP_GETSIZE, &buffersize) == -1) - goto out; + goto out; ret = (char*)malloc(buffersize); if (!ret) - goto out; + goto out; do { rc = read(fd, ret, buffersize); - if (rc < 0) { + if (rc < 0) { if (errno != EINTR) goto out; - } + } } while (rc < 0); out: return ret; } -int setterm(int fd) +int setterm(int fd, char *tout) { - const char* instruction = "TERMINAL MORE 0 0 HOLD OFF"; + char *instruction; long pagesize = sysconf(_SC_PAGESIZE); int rc = 0, num, buffersize; int ret = -1; + if (asprintf(&instruction, "TERMINAL MORE %s 0 HOLD OFF", tout) == -1) + goto out; + num = (strlen(instruction) + pagesize - 1)/pagesize; buffersize = num * pagesize; if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) - goto out; + goto out; do { rc = write(fd, instruction, strlen(instruction)); - if (rc < 0) { + if (rc < 0) { if (errno != EINTR) goto out; - } + } } while (rc < 0); + free(instruction); if (ioctl(fd, VMCP_GETCODE, &rc) == -1) - goto out; + goto out; if (ioctl(fd, VMCP_GETSIZE, &buffersize) == -1) - goto out; + goto out; if (rc == 0 && buffersize == 0) ret = 0; out: @@ -114,19 +143,19 @@ buffersize = num * pagesize; if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) - goto out; + goto out; do { rc = write(fd, instruction, strlen(instruction)); - if (rc < 0) { + if (rc < 0) { if (errno != EINTR) goto out; - } + } } while (rc < 0); free(instruction); if (ioctl(fd, VMCP_GETCODE, &rc) == -1) - goto out; + goto out; if (ioctl(fd, VMCP_GETSIZE, &buffersize) == -1) - goto out; + goto out; if (rc == 0 && buffersize == 0) ret = 0; out:
