* [pseudo][PATCH 01/23] Makefile.in: Move version to 1.99.0 to prep for 2.0 development
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
@ 2026-07-03 0:45 ` Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 02/23] pseudo_util: Add log severity flags Mark Hatle
` (21 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:45 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
A pseudo-1.9 branch has been created fro backporting to the stable
development.
Planned 2.0 development includes:
* diagnostic message updates
* environment rework
* parallel move/rename
* review of existing function wrapping
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
Makefile.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.in b/Makefile.in
index aed9dda..6640a73 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,7 @@ BITS=@BITS@
ARCH_FLAGS=@ARCH_FLAGS@
MARK64=@MARK64@
RPATH=@RPATH@
-VERSION=1.9.8
+VERSION=1.99.0
LIB=@LIB@
BIN=bin
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 02/23] pseudo_util: Add log severity flags
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 01/23] Makefile.in: Move version to 1.99.0 to prep for 2.0 development Mark Hatle
@ 2026-07-03 0:45 ` Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 03/23] pseudo: Add new logging macros Mark Hatle
` (20 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:45 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Create an infrastructure to make use of severity flags from pseudo_tables.
After that it is now possible to set severity flags from env (PSEUDO_SEVERITY) and from terminal via optargs.
[YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo.c | 5 ++++-
pseudo.h | 3 +++
pseudo_util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/pseudo.c b/pseudo.c
index 25711b6..e5fe5cf 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -134,7 +134,7 @@ main(int argc, char *argv[]) {
* wrong. The + suppresses this annoying behavior, but may not
* be compatible with sane option libraries.
*/
- while ((o = getopt(argc, argv, "+BCdfhi:lm:M:p:P:r:R:St:vVx:")) != -1) {
+ while ((o = getopt(argc, argv, "+BCdfhi:klm:M:p:P:r:R:St:vVx:")) != -1) {
switch (o) {
case 'B': /* rebuild database */
opt_B = 1;
@@ -231,6 +231,9 @@ main(int argc, char *argv[]) {
printf("Set PSEUDO_PREFIX to run with a different prefix.\n");
exit(0);
break;
+ case 'k': /* debug severity */
+ pseudo_severity_set(optarg);
+ break;
case 'x': /* debug flags */
pseudo_debug_set(optarg);
break;
diff --git a/pseudo.h b/pseudo.h
index b6c13f2..e48d38a 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -26,8 +26,11 @@ extern void pseudo_debug_terse(void);
extern void pseudo_debug_set(char *);
extern void pseudo_debug_clear(char *);
extern void pseudo_debug_flags_finalize(void);
+extern void pseudo_severity_set(char *);
+extern void pseudo_severity_flags_finalize(void);
extern unsigned long pseudo_util_debug_flags;
extern unsigned long pseudo_util_evlog_flags;
+extern unsigned long pseudo_util_severity_flags;
extern int pseudo_util_debug_fd;
extern int pseudo_disabled;
extern int pseudo_allow_fsync;
diff --git a/pseudo_util.c b/pseudo_util.c
index 2b0cc04..f8f2a2f 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -63,6 +63,7 @@ static struct pseudo_variables pseudo_env[] = {
#endif
{ "PSEUDO_EVLOG", 12, NULL },
{ "PSEUDO_EVLOG_FILE", 17, NULL },
+ { "PSEUDO_SEVERITY", 15, NULL },
{ NULL, 0, NULL } /* Magic terminator */
};
@@ -90,6 +91,7 @@ static int pseudo_evlog_next_entry = 0;
static void pseudo_evlog_set(char *);
static void pseudo_evlog_flags_finalize(void);
static unsigned long pseudo_debug_flags_in(char *);
+static unsigned long pseudo_severity_flags_in(char *);
/* -1 - init hasn't been run yet
* 0 - init has been run
@@ -247,10 +249,17 @@ pseudo_init_util(void) {
pseudo_evlog_flags_finalize();
}
free(env);
+ env = pseudo_get_value("PSEUDO_SEVERITY");
+ if (env) {
+ pseudo_severity_set(env);
+ pseudo_severity_flags_finalize();
+ }
+ free(env);
}
unsigned long pseudo_util_debug_flags = 0;
unsigned long pseudo_util_evlog_flags = 0;
+unsigned long pseudo_util_severity_flags = 0;
int pseudo_util_debug_fd = 2;
int pseudo_util_evlog_fd = 2;
static int debugged_newline = 1;
@@ -433,6 +442,11 @@ pseudo_evlog_set(char *s) {
pseudo_util_evlog_flags = pseudo_debug_flags_in(s);
}
+void
+pseudo_severity_set(char *s) {
+ pseudo_util_severity_flags = pseudo_severity_flags_in(s);
+}
+
/* This exists because we don't want to allocate a bunch of strings
* and free them immediately if you have several flags set.
*/
@@ -457,6 +471,11 @@ pseudo_evlog_flags_finalize(void) {
pseudo_flags_finalize(pseudo_util_evlog_flags, "PSEUDO_EVLOG");
}
+void
+pseudo_severity_flags_finalize(void) {
+ pseudo_flags_finalize(pseudo_util_severity_flags, "PSEUDO_SEVERITY");
+}
+
static unsigned long
pseudo_debug_flags_in(char *s) {
unsigned long flags = 0;
@@ -471,6 +490,31 @@ pseudo_debug_flags_in(char *s) {
return flags;
}
+static unsigned long
+pseudo_severity_flags_in(char *s) {
+ unsigned long flags = 0;
+ char *token = NULL;
+ char *saveptr = NULL;
+ char *s_copy = NULL;
+
+ if (!s)
+ return flags;
+
+ s_copy = strdup(s);
+
+ token = strtok_r(s_copy, " ,;", &saveptr);
+ while (token != NULL) {
+ pseudo_sev_t id = pseudo_sev_id(token);
+ if (id > SEVERITY_NONE && id < SEVERITY_MAX) {
+ flags |= (1UL << id);
+ }
+ token = strtok_r(NULL, " ,;", &saveptr);
+ }
+
+ free(s_copy);
+ return flags;
+}
+
void
pseudo_debug_clear(char *s) {
if (!s)
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 03/23] pseudo: Add new logging macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 01/23] Makefile.in: Move version to 1.99.0 to prep for 2.0 development Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 02/23] pseudo_util: Add log severity flags Mark Hatle
@ 2026-07-03 0:45 ` Mark Hatle
2026-07-03 0:45 ` [pseudo][PATCH 04/23] pseudo_util: Change pseudo_diag() calls to appropriate " Mark Hatle
` (19 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:45 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
They are designed to replace various direct pseudo_diag()
call across the program and add new "smart" logging functionality.
CRITICAL and ERROR messages are shown no matter what,
INFO and WARNING only if the corresponding flag is set.
The patch is based on: [pseudo,v2] pseudo_util: Add log severity flags
and implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
enums/sev.in | 2 +-
pseudo.h | 17 +++++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/enums/sev.in b/enums/sev.in
index 24c2c6e..44dffde 100644
--- a/enums/sev.in
+++ b/enums/sev.in
@@ -1,4 +1,4 @@
-sev: SEVERITY
+sev: SEVERITY; FLAGS
debug
info
warn
diff --git a/pseudo.h b/pseudo.h
index e48d38a..d214ba2 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -41,6 +41,23 @@ extern int pseudo_evlog_internal(char *, ...) __attribute__ ((format (printf, 1,
} while (0)
extern void pseudo_evlog_dump(void);
#ifndef NDEBUG
+#define pseudo_critical(fmt, ...) do { \
+ pseudo_diag("CRITICAL: " fmt, ##__VA_ARGS__); \
+ abort(); \
+} while (0)
+#define pseudo_error(fmt, ...) do { \
+ pseudo_diag("ERROR: " fmt, ##__VA_ARGS__); \
+} while (0)
+#define pseudo_warning(fmt, ...) do { \
+ if (pseudo_util_severity_flags & SEVERITYF_WARN) { \
+ pseudo_diag("WARNING: " fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
+#define pseudo_info(fmt, ...) do { \
+ if (pseudo_util_severity_flags & SEVERITYF_INFO) { \
+ pseudo_diag("INFO: " fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
#define pseudo_debug(x, ...) do { \
if ((x) & PDBGF_VERBOSE) { \
if ((pseudo_util_debug_flags & PDBGF_VERBOSE) && (pseudo_util_debug_flags & ((x) & ~PDBGF_VERBOSE))) { pseudo_diag(__VA_ARGS__); } \
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 04/23] pseudo_util: Change pseudo_diag() calls to appropriate logging macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (2 preceding siblings ...)
2026-07-03 0:45 ` [pseudo][PATCH 03/23] pseudo: Add new logging macros Mark Hatle
@ 2026-07-03 0:45 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 05/23] pseudo_db: Change pseudo_diag() calls to appropriate macros Mark Hatle
` (18 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:45 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
The patch is based on: [pseudo] pseudo: Add new logging macros
and implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_util.c | 88 +++++++++++++++++++++++++--------------------------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index f8f2a2f..dbd979e 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -177,7 +177,7 @@ pseudo_get_value(const char *key) {
value = NULL;
if (!pseudo_env[i].key)
- pseudo_diag("Unknown variable %s.\n", key);
+ pseudo_warning("Unknown variable %s.\n", key);
return value;
}
@@ -202,12 +202,12 @@ pseudo_set_value(const char *key, const char *value) {
if (new)
pseudo_env[i].value = new;
else
- pseudo_diag("warning: failed to save new value (%s) for key %s\n",
+ pseudo_warning("failed to save new value (%s) for key %s\n",
value, key);
} else
pseudo_env[i].value = NULL;
} else {
- if (!pseudo_util_initted) pseudo_diag("Unknown variable %s.\n", key);
+ if (!pseudo_util_initted) pseudo_warning("Unknown variable %s.\n", key);
rc = -EINVAL;
}
@@ -350,7 +350,7 @@ without_libpseudo(char *list) {
}
list = strdup(list);
if (!list) {
- pseudo_diag("Couldn't allocate memory to remove libpseudo from environment.\n");
+ pseudo_error("Couldn't allocate memory to remove libpseudo from environment.\n");
}
while (list && !(*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
char *start = list + pmatch[0].rm_so;
@@ -360,7 +360,7 @@ without_libpseudo(char *list) {
memmove(start, end, strlen(end) + 1);
++counter;
if (counter > 5) {
- pseudo_diag("Found way too many libpseudo.so in environment, giving up.\n");
+ pseudo_error("Found way too many libpseudo.so in environment, giving up.\n");
return list;
}
}
@@ -621,7 +621,7 @@ pseudo_evlog_internal(char *fmt, ...) {
event_log[i].data = pseudo_evlog_buffer + (PSEUDO_EVLOG_LENGTH * i);
}
} else {
- pseudo_diag("fatal: can't allocate event log storage.\n");
+ pseudo_error("can't allocate event log storage.\n");
}
}
@@ -668,7 +668,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
if (!newpath ||
!pcurrent || !*pcurrent ||
!root || !element) {
- pseudo_diag("pseudo_append_element: invalid args.\n");
+ pseudo_warning("pseudo_append_element: invalid args.\n");
return -1;
}
@@ -689,7 +689,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
* fall through and do standard processing
*/
if (!proc_path)
- pseudo_diag("allocation failed seeking memory for path (%s).\n", newpath);
+ pseudo_warning("allocation failed seeking memory for path (%s).\n", newpath);
else
is_proc = 1;
}
@@ -729,7 +729,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
/* current length, plus / <element> / \0 */
/* => curlen + elen + 3 */
if (curlen + elen + 3 > allocated) {
- pseudo_diag("pseudo_append_element: path too long (wanted %lu bytes).\n", (unsigned long) curlen + elen + 3);
+ pseudo_error("pseudo_append_element: path too long (wanted %lu bytes).\n", (unsigned long) curlen + elen + 3);
return -1;
}
/* append a slash */
@@ -798,7 +798,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
char *target_link_path = malloc(pseudo_path_max());
if (!target_link_path)
- pseudo_diag("allocation failed seeking memory for path (%s/%s).\n", proc_path, linkbuf);
+ pseudo_error("allocation failed seeking memory for path (%s/%s).\n", proc_path, linkbuf);
/* Fall through, nothing we can do here */
else {
snprintf(target_link_path, target_link_max, "%s/%s", proc_path, linkbuf);
@@ -865,7 +865,7 @@ pseudo_append_elements(char *newpath, char *root, size_t allocated, char **curre
if (!newpath || !root ||
!current || !*current ||
!path) {
- pseudo_diag("pseudo_append_elements: invalid arguments.");
+ pseudo_error("pseudo_append_elements: invalid arguments.");
return -1;
}
if (!sbuf) {
@@ -935,7 +935,7 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel
int trailing_slash = 0;
if (!path) {
- pseudo_diag("can't fix empty path.\n");
+ pseudo_warning("can't fix empty path.\n");
return 0;
}
if (baselen == 1) {
@@ -957,7 +957,7 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel
if (!pathbufs[pathbuf]) {
pathbufs[pathbuf] = malloc(newpathlen);
if (!pathbufs[pathbuf]) {
- pseudo_diag("allocation failed seeking memory for path (%s).\n", path);
+ pseudo_error("allocation failed seeking memory for path (%s).\n", path);
return 0;
}
}
@@ -976,7 +976,7 @@ pseudo_fix_path(const char *base, const char *path, size_t rootlen, size_t basel
* easier for the library.
*/
if (!newpath) {
- pseudo_diag("allocation failed seeking memory for path (%s).\n", path);
+ pseudo_error("allocation failed seeking memory for path (%s).\n", path);
return 0;
}
newpath[0] = '\0';
@@ -1037,7 +1037,7 @@ void pseudo_dropenv() {
if (ld_preload) {
ld_preload = without_libpseudo(ld_preload);
if (!ld_preload) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
}
if (ld_preload && strlen(ld_preload)) {
SETENV(PRELINK_LIBRARIES, ld_preload, 1);
@@ -1056,7 +1056,7 @@ pseudo_dropenvp(char * const *envp) {
new_envp = malloc((i + 1) * sizeof(*new_envp));
if (!new_envp) {
- pseudo_diag("fatal: can't allocate new environment.\n");
+ pseudo_error("can't allocate new environment.\n");
return NULL;
}
@@ -1065,7 +1065,7 @@ pseudo_dropenvp(char * const *envp) {
if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) {
char *new_val = without_libpseudo(envp[i]);
if (!new_val) {
- pseudo_diag("fatal: can't allocate new environment variable.\n");
+ pseudo_error("can't allocate new environment variable.\n");
return 0;
} else {
/* don't keep an empty value; if the whole string is
@@ -1111,7 +1111,7 @@ pseudo_setupenv() {
size_t len = strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_PATH);
} else {
snprintf(newenv, len, "%s:%s64", libdir_path, libdir_path);
SETENV(PRELINK_PATH, newenv, 1);
@@ -1121,7 +1121,7 @@ pseudo_setupenv() {
size_t len = strlen(ld_library_path) + 1 + strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_PATH);
} else {
snprintf(newenv, len, "%s:%s:%s64", ld_library_path, libdir_path, libdir_path);
SETENV(PRELINK_PATH, newenv, 1);
@@ -1136,7 +1136,7 @@ pseudo_setupenv() {
if (ld_preload) {
ld_preload = with_libpseudo(ld_preload, libdir_path);
if (!ld_preload) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
} else {
SETENV(PRELINK_LIBRARIES, ld_preload, 1);
free(ld_preload);
@@ -1144,7 +1144,7 @@ pseudo_setupenv() {
} else {
ld_preload = with_libpseudo("", libdir_path);
if (!ld_preload) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
} else {
SETENV(PRELINK_LIBRARIES, ld_preload, 1);
free(ld_preload);
@@ -1216,7 +1216,7 @@ pseudo_setupenvp(char * const *envp) {
j = 0;
new_envp = malloc((env_count + 1) * sizeof(*new_envp));
if (!new_envp) {
- pseudo_diag("fatal: can't allocate new environment.\n");
+ pseudo_error("can't allocate new environment.\n");
return NULL;
}
@@ -1225,7 +1225,7 @@ pseudo_setupenvp(char * const *envp) {
size_t len = strlen(PRELINK_PATH "=") + strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_PATH);
} else {
snprintf(newenv, len, PRELINK_PATH "=%s:%s64", libdir_path, libdir_path);
new_envp[j++] = newenv;
@@ -1234,7 +1234,7 @@ pseudo_setupenvp(char * const *envp) {
size_t len = strlen(ld_library_path) + 1 + strlen(libdir_path) + 1 + (strlen(libdir_path) + 2) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_PATH);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_PATH);
} else {
snprintf(newenv, len, "%s:%s:%s64", ld_library_path, libdir_path, libdir_path);
new_envp[j++] = newenv;
@@ -1247,18 +1247,18 @@ pseudo_setupenvp(char * const *envp) {
if (ld_preload) {
ld_preload = with_libpseudo(ld_preload, libdir_path);
if (!ld_preload) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
} else
new_envp[j++] = ld_preload;
} else {
ld_preload = with_libpseudo("", libdir_path);
if (!ld_preload) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
} else {
size_t len = strlen(PRELINK_LIBRARIES "=") + strlen(ld_preload) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new %s variable.\n", PRELINK_LIBRARIES);
+ pseudo_error("can't allocate new %s variable.\n", PRELINK_LIBRARIES);
} else {
snprintf(newenv, len, PRELINK_LIBRARIES "=%s", ld_preload);
new_envp[j++] = newenv;
@@ -1287,7 +1287,7 @@ pseudo_setupenvp(char * const *envp) {
size_t len = strlen(pseudo_env[i].key) + 1 + strlen(pseudo_env[i].value) + 1;
char *newenv = malloc(len);
if (!newenv) {
- pseudo_diag("fatal: can't allocate new variable.\n");
+ pseudo_error("can't allocate new variable.\n");
} else {
snprintf(newenv, len, "%s=%s", pseudo_env[i].key, pseudo_env[i].value);
new_envp[j++] = newenv;
@@ -1339,7 +1339,7 @@ pseudo_prefix_path(char *file) {
char * prefix = pseudo_get_prefix(NULL);
if (!prefix) {
- pseudo_diag("You must set the PSEUDO_PREFIX environment variable to run pseudo.\n");
+ pseudo_error("You must set the PSEUDO_PREFIX environment variable to run pseudo.\n");
exit(1);
}
@@ -1356,7 +1356,7 @@ pseudo_bindir_path(char *file) {
char * bindir = pseudo_get_bindir();
if (!bindir) {
- pseudo_diag("You must set the PSEUDO_BINDIR environment variable to run pseudo.\n");
+ pseudo_error("You must set the PSEUDO_BINDIR environment variable to run pseudo.\n");
exit(1);
}
@@ -1373,7 +1373,7 @@ pseudo_libdir_path(char *file) {
char * libdir = pseudo_get_libdir();
if (!libdir) {
- pseudo_diag("You must set the PSEUDO_LIBDIR environment variable to run pseudo.\n");
+ pseudo_error("You must set the PSEUDO_LIBDIR environment variable to run pseudo.\n");
exit(1);
}
@@ -1390,7 +1390,7 @@ pseudo_localstatedir_path(char *file) {
char * localstatedir = pseudo_get_localstatedir();
if (!localstatedir) {
- pseudo_diag("You must set the PSEUDO_LOCALSTATEDIR environment variable to run pseudo.\n");
+ pseudo_error("You must set the PSEUDO_LOCALSTATEDIR environment variable to run pseudo.\n");
exit(1);
}
@@ -1424,7 +1424,7 @@ pseudo_get_prefix(char *pathname) {
tmp_path = pseudo_fix_path(NULL, mypath, 0, 0, 0, AT_SYMLINK_NOFOLLOW);
/* point s to the end of the fixed path */
if ((int) strlen(tmp_path) >= pseudo_path_max()) {
- pseudo_diag("Can't expand path '%s' -- expansion exceeds %d.\n",
+ pseudo_error("Can't expand path '%s' -- expansion exceeds %d.\n",
mypath, (int) pseudo_path_max());
} else {
s = mypath + snprintf(mypath, pseudo_path_max(), "%s", tmp_path);
@@ -1446,7 +1446,7 @@ pseudo_get_prefix(char *pathname) {
strcpy(mypath, "/");
}
- pseudo_diag("Warning: PSEUDO_PREFIX unset, defaulting to %s.\n",
+ pseudo_warning("PSEUDO_PREFIX unset, defaulting to %s.\n",
mypath);
pseudo_set_value("PSEUDO_PREFIX", mypath);
s = pseudo_get_value("PSEUDO_PREFIX");
@@ -1702,7 +1702,7 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
}
pseudo_path = pseudo_localstatedir_path(defname);
if (!pseudo_path) {
- pseudo_diag("can't get path for prefix/%s\n", PSEUDO_LOGFILE);
+ pseudo_error("can't get path for prefix/%s\n", PSEUDO_LOGFILE);
return -1;
}
} else {
@@ -1716,7 +1716,7 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
break;
case 'd':
if (pid) {
- pseudo_diag("found second %%d in PSEUDO_DEBUG_FILE, ignoring.\n");
+ pseudo_info("found second %%d in PSEUDO_DEBUG_FILE, ignoring.\n");
return -1;
} else {
pid = s;
@@ -1724,7 +1724,7 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
break;
case 's':
if (prog) {
- pseudo_diag("found second %%s in PSEUDO_DEBUG_FILE, ignoring.\n");
+ pseudo_info("found second %%s in PSEUDO_DEBUG_FILE, ignoring.\n");
return -1;
} else {
prog = s;
@@ -1732,10 +1732,10 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
break;
default:
if (isprint(s[1])) {
- pseudo_diag("found unknown format character '%c' in PSEUDO_DEBUG_FILE, ignoring.\n",
+ pseudo_info("found unknown format character '%c' in PSEUDO_DEBUG_FILE, ignoring.\n",
s[1]);
} else {
- pseudo_diag("found unknown format character '\\x%02x' in PSEUDO_DEBUG_FILE, ignoring.\n",
+ pseudo_info("found unknown format character '\\x%02x' in PSEUDO_DEBUG_FILE, ignoring.\n",
(unsigned char) s[1]);
}
return -1;
@@ -1750,7 +1750,7 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
len += strlen(program_invocation_short_name);
pseudo_path = malloc(len);
if (!pseudo_path) {
- pseudo_diag("can't allocate space for debug file name.\n");
+ pseudo_error("can't allocate space for debug file name.\n");
return -1;
}
if (pid && prog) {
@@ -1770,7 +1770,7 @@ pseudo_logfile(char *filename, char *defname, int prefer_fd) {
}
fd = open(pseudo_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
if (fd == -1) {
- pseudo_diag("help: can't open log file %s: %s\n", pseudo_path, strerror(errno));
+ pseudo_error("help: can't open log file %s: %s\n", pseudo_path, strerror(errno));
} else {
/* try to force fd to prefer_fd. We do this because glibc's malloc
* debug unconditionally writes to fd 2, and we don't want
@@ -1799,7 +1799,7 @@ pseudo_debug_logfile(char *defname, int prefer_fd) {
fd = pseudo_logfile(filename, defname, prefer_fd);
if (fd > -1) {
- pseudo_diag("debug_logfile: fd %d\n", fd);
+ pseudo_info("debug_logfile: fd %d\n", fd);
pseudo_util_debug_fd = fd;
return 0;
}
@@ -1864,7 +1864,7 @@ pseudo_dump_data(char *name, const void *v, size_t len) {
const unsigned char *base = v;
const unsigned char *data = base;
int remaining = len;
- pseudo_diag("%s at %p [%d byte%s]:\n",
+ pseudo_info("%s at %p [%d byte%s]:\n",
name ? name : "data", v, (int) len, len == 1 ? "" : "s");
while (remaining > 0) {
char *hexptr = hexbuf;
@@ -1882,7 +1882,7 @@ pseudo_dump_data(char *name, const void *v, size_t len) {
}
*hexptr = '\0';
*asciiptr = '\0';
- pseudo_diag("0x%06x %-50.50s '%.16s'\n",
+ pseudo_info("0x%06x %-50.50s '%.16s'\n",
(int) (data - base),
hexbuf, asciibuf);
remaining = remaining - 16;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 05/23] pseudo_db: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (3 preceding siblings ...)
2026-07-03 0:45 ` [pseudo][PATCH 04/23] pseudo_util: Change pseudo_diag() calls to appropriate " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 06/23] pseudo_client: " Mark Hatle
` (17 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_db.c | 122 ++++++++++++++++++++++++++--------------------------
1 file changed, 61 insertions(+), 61 deletions(-)
diff --git a/pseudo_db.c b/pseudo_db.c
index 6a33f20..6945a83 100644
--- a/pseudo_db.c
+++ b/pseudo_db.c
@@ -27,7 +27,7 @@
#ifdef NPROFILE
void xProfile(void * pArg, const char * pQuery, sqlite3_uint64 pTimeTaken)
{
- pseudo_diag("profile: %lld %s\n", pTimeTaken, pQuery);
+ pseudo_info("profile: %lld %s\n", pTimeTaken, pQuery);
}
#endif
@@ -647,7 +647,7 @@ cleanup_db(void) {
localtime_r(&stamp.tv_sec, &stamp_tm);
strftime(datebuf, 64, "%H:%M:%S", &stamp_tm);
- pseudo_diag("db cleanup for server shutdown, %s.%03d\n",
+ pseudo_info("db cleanup for server shutdown, %s.%03d\n",
datebuf, (int) (stamp.tv_usec / 1000));
#ifdef USE_MEMORY_DB
if (real_file_db) {
@@ -657,7 +657,7 @@ cleanup_db(void) {
gettimeofday(&stamp, NULL);
localtime_r(&stamp.tv_sec, &stamp_tm);
strftime(datebuf, 64, "%H:%M:%S", &stamp_tm);
- pseudo_diag("memory-to-file backup complete, %s.%03d.\n",
+ pseudo_info("memory-to-file backup complete, %s.%03d.\n",
datebuf, (int) (stamp.tv_usec / 1000));
#endif
if (file_db)
@@ -667,7 +667,7 @@ cleanup_db(void) {
gettimeofday(&stamp, NULL);
localtime_r(&stamp.tv_sec, &stamp_tm);
strftime(datebuf, 64, "%H:%M:%S", &stamp_tm);
- pseudo_diag("db cleanup finished, %s.%03d\n",
+ pseudo_info("db cleanup finished, %s.%03d\n",
datebuf, (int) (stamp.tv_usec / 1000));
}
@@ -704,7 +704,7 @@ get_db(struct database_info *dbinfo) {
rc = sqlite3_open(dbfile, &db);
free(dbfile);
if (rc) {
- pseudo_diag("Failed: %s\n", sqlite3_errmsg(db));
+ pseudo_error("Failed: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
*(dbinfo->db) = NULL;
return 1;
@@ -733,7 +733,7 @@ get_db(struct database_info *dbinfo) {
"ORDER BY name;";
rc = sqlite3_get_table(db, sql, &results, &rows, &columns, &errmsg);
if (rc) {
- pseudo_diag("Failed: %s\n", errmsg);
+ pseudo_error("Failed: %s\n", errmsg);
} else {
rc = make_tables(db, dbinfo->tables, dbinfo->indexes, dbinfo->migrations, results, rows);
sqlite3_free_table(results);
@@ -760,7 +760,7 @@ get_dbs(void) {
#endif
for (i = 0; db_infos[i].db; ++i) {
if (get_db(&db_infos[i])) {
- pseudo_diag("Error getting '%s' database.\n",
+ pseudo_error("Error getting '%s' database.\n",
db_infos[i].pathname);
err = 1;
}
@@ -780,12 +780,12 @@ pdb_log_traits(pseudo_query_t *traits) {
int rc;
if (!log_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 1;
}
e = calloc(1, sizeof(*e));
if (!e) {
- pseudo_diag("can't allocate space for log entry.");
+ pseudo_error("can't allocate space for log entry.");
return 1;
}
for (trait = traits; trait; trait = trait->next) {
@@ -854,7 +854,7 @@ pdb_log_traits(pseudo_query_t *traits) {
case PSQF_ID:
case PSQF_ORDER:
default:
- pseudo_diag("Invalid trait %s for log creation.\n",
+ pseudo_error("Invalid trait %s for log creation.\n",
pseudo_query_field_name(trait->field));
free(e);
return 1;
@@ -878,7 +878,7 @@ pdb_log_entry(log_entry *e) {
int rc;
if (!log_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 1;
}
@@ -976,7 +976,7 @@ pdb_log_msg(pseudo_sev_t severity, pseudo_msg_t *msg, const char *program, const
}
if (!log_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 1;
}
@@ -1062,7 +1062,7 @@ frag(buffer *b, char *fmt, ...) {
int rc;
if (!b) {
- pseudo_diag("frag called without buffer.\n");
+ pseudo_error("frag called without buffer.\n");
return -1;
}
curlen = b->tail - b->data;
@@ -1075,7 +1075,7 @@ frag(buffer *b, char *fmt, ...) {
newlen *= 2;
char *newbuf = malloc(newlen);
if (!newbuf) {
- pseudo_diag("failed to allocate SQL buffer.\n");
+ pseudo_error("failed to allocate SQL buffer.\n");
return -1;
}
memcpy(newbuf, b->data, curlen + 1);
@@ -1088,7 +1088,7 @@ frag(buffer *b, char *fmt, ...) {
rc = vsnprintf(b->tail, b->buflen - curlen, fmt, ap);
va_end(ap);
if ((rc > 0) && ((size_t) rc >= (b->buflen - curlen))) {
- pseudo_diag("tried to reallocate larger buffer, failed. giving up.\n");
+ pseudo_error("tried to reallocate larger buffer, failed. giving up.\n");
return -1;
}
}
@@ -1110,24 +1110,24 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
static buffer *sql;
if (!log_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return NULL;
}
if (!stmt_type) {
- pseudo_diag("can't prepare a statement without a type.\n");
+ pseudo_warning("can't prepare a statement without a type.\n");
}
if (!sql) {
sql = malloc(sizeof *sql);
if (!sql) {
- pseudo_diag("can't allocate SQL buffer.\n");
+ pseudo_error("can't allocate SQL buffer.\n");
return NULL;
}
sql->buflen = 512;
sql->data = malloc(sql->buflen);
if (!sql->data) {
- pseudo_diag("can't allocate SQL text buffer.\n");
+ pseudo_error("can't allocate SQL text buffer.\n");
free(sql);
sql = 0;
return NULL;
@@ -1193,7 +1193,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
case PSQT_LIKE:
case PSQT_NOTLIKE:
case PSQT_SQLPAT:
- pseudo_diag("Error: Can't use a LIKE match on non-text fields.\n");
+ pseudo_error("Can't use a LIKE match on non-text fields.\n");
return 0;
break;
default:
@@ -1210,7 +1210,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
case PSQT_LIKE:
case PSQT_NOTLIKE:
case PSQT_SQLPAT:
- pseudo_diag("Error: Can't use a LIKE match on non-text fields.\n");
+ pseudo_error("Error: Can't use a LIKE match on non-text fields.\n");
return 0;
break;
default:
@@ -1235,7 +1235,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
order_dir = "ASC";
break;
default:
- pseudo_diag("Ordering must be < or >.\n");
+ pseudo_error("Ordering must be < or >.\n");
return 0;
break;
}
@@ -1245,7 +1245,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
case PSQT_LIKE:
case PSQT_NOTLIKE:
case PSQT_SQLPAT:
- pseudo_diag("Error: Can't use a LIKE match on non-text fields.\n");
+ pseudo_error("Can't use a LIKE match on non-text fields.\n");
return 0;
break;
default:
@@ -1300,7 +1300,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni
sqlite3_bind_int64(stmt, field++, trait->data.ivalue);
break;
default:
- pseudo_diag("Inexplicably invalid field type %d\n", trait->field);
+ pseudo_error("Inexplicably invalid field type %d\n", trait->field);
sqlite3_finalize(stmt);
return NULL;
}
@@ -1322,7 +1322,7 @@ pdb_delete(pseudo_query_t *traits, unsigned long fields) {
dberr(log_db, "deletion failed");
return -1;
} else {
- pseudo_diag("Deleted records, vacuuming log database (may take a while).\n");
+ pseudo_info("Deleted records, vacuuming log database (may take a while).\n");
/* we can't do anything about it if this fails... */
sqlite3_exec(log_db, "VACUUM;", NULL, NULL, NULL);
}
@@ -1347,7 +1347,7 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int unique) {
h->fields = fields;
h->stmt = stmt;
} else {
- pseudo_diag("failed to allocate memory for log_history\n");
+ pseudo_error("failed to allocate memory for log_history\n");
sqlite3_finalize(stmt);
}
return h;
@@ -1378,7 +1378,7 @@ pdb_history_entry(log_history h) {
}
l = calloc(1, sizeof(log_entry));
if (!l) {
- pseudo_diag("couldn't allocate log entry.\n");
+ pseudo_error("couldn't allocate log entry.\n");
return 0;
}
@@ -1449,12 +1449,12 @@ pdb_history_entry(log_history h) {
case PSQF_ORDER:
case PSQF_FTYPE:
case PSQF_PERM:
- pseudo_diag("field %s should not be in the fields list.\n",
+ pseudo_warning("field %s should not be in the fields list.\n",
pseudo_query_field_name(f));
return 0;
break;
default:
- pseudo_diag("unknown field %d\n", f);
+ pseudo_warning("unknown field %d\n", f);
return 0;
break;
}
@@ -1498,7 +1498,7 @@ pdb_clear_unused_xattrs(void) {
int rc;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return;
}
if (!delete) {
@@ -1528,7 +1528,7 @@ pdb_clear_xattrs(pseudo_msg_t *msg) {
if (!msg)
return;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return;
}
if (!delete) {
@@ -1565,7 +1565,7 @@ pdb_copy_xattrs(pseudo_msg_t *oldmsg, pseudo_msg_t *msg) {
if (!oldmsg || !msg)
return;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return;
}
if (!copy) {
@@ -1596,7 +1596,7 @@ pdb_check_xattrs(pseudo_msg_t *msg) {
if (!msg)
return;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return;
}
if (!scan) {
@@ -1643,7 +1643,7 @@ pdb_link_file(pseudo_msg_t *msg) {
" VALUES (?, ?, ?, ?, ?, ?, ?, 0);";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!insert) {
@@ -1689,7 +1689,7 @@ pdb_unlink_file_dev(pseudo_msg_t *msg) {
char *sql = "DELETE FROM files WHERE dev = ? AND ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!sql_delete) {
@@ -1724,7 +1724,7 @@ pdb_update_file_path(pseudo_msg_t *msg) {
"WHERE path = 'NAMELESS FILE' and dev = ? AND ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!update) {
@@ -1759,7 +1759,7 @@ pdb_may_unlink_file(pseudo_msg_t *msg, int deleting) {
char *sql_mark_file = "UPDATE files SET deleting = ? WHERE path = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!mark_file) {
@@ -1804,7 +1804,7 @@ pdb_cancel_unlink_file(pseudo_msg_t *msg) {
char *sql_mark_file = "UPDATE files SET deleting = 0 WHERE path = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!mark_file) {
@@ -1846,7 +1846,7 @@ pdb_did_unlink_files(int deleting) {
char *sql_delete_exact = "DELETE FROM files WHERE deleting = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!delete_exact) {
@@ -1857,7 +1857,7 @@ pdb_did_unlink_files(int deleting) {
}
}
if (deleting == 0) {
- pseudo_diag("did_unlink_files: deleting must be non-zero.\n");
+ pseudo_error("did_unlink_files: deleting must be non-zero.\n");
return 0;
}
sqlite3_bind_int(delete_exact, 1, deleting);
@@ -1882,7 +1882,7 @@ pdb_did_unlink_file(char *path, pseudo_msg_t *msg, int deleting) {
char *sql_delete_exact = "DELETE FROM files WHERE path = ? AND deleting = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!delete_exact) {
@@ -1925,7 +1925,7 @@ pdb_unlink_file(pseudo_msg_t *msg) {
char *sql_delete_exact = "DELETE FROM files WHERE path = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!delete_exact) {
@@ -1973,7 +1973,7 @@ pdb_unlink_contents(pseudo_msg_t *msg) {
"(path > (? || '/') AND path < (? || '0'));";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!delete_sub) {
@@ -2025,7 +2025,7 @@ pdb_rename_file(const char *oldpath, pseudo_msg_t *msg) {
"WHERE (path > (? || '/') AND path < (? || '0'));";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!update_exact) {
@@ -2098,7 +2098,7 @@ pdb_renumber_all(dev_t from, dev_t to) {
" WHERE dev = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!files_update) {
@@ -2166,7 +2166,7 @@ pdb_update_inode(pseudo_msg_t *msg) {
if (!oldmsg) {
oldmsg = malloc(sizeof(*msg) + pseudo_path_max());
if (!oldmsg) {
- pseudo_diag("%s: out of memory\n", __func__);
+ pseudo_error("%s: out of memory\n", __func__);
return 1;
}
}
@@ -2175,7 +2175,7 @@ pdb_update_inode(pseudo_msg_t *msg) {
" SET dev = ?, ino = ? "
" WHERE path = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!update) {
@@ -2189,7 +2189,7 @@ pdb_update_inode(pseudo_msg_t *msg) {
return 1;
}
if (!msg->pathlen) {
- pseudo_diag("Can't update the inode of a file without its path.\n");
+ pseudo_error("Can't update the inode of a file without its path.\n");
return 1;
}
memcpy(oldmsg, msg, sizeof(*msg) + msg->pathlen);
@@ -2240,7 +2240,7 @@ pdb_update_file(pseudo_msg_t *msg) {
" WHERE dev = ? AND ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!update) {
@@ -2281,7 +2281,7 @@ pdb_find_file_exact(pseudo_msg_t *msg) {
char *sql = "SELECT * FROM files WHERE path = ? AND dev = ? AND ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2332,7 +2332,7 @@ pdb_find_file_path(pseudo_msg_t *msg) {
char *sql = "SELECT * FROM files WHERE path = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 1;
}
if (!select) {
@@ -2389,7 +2389,7 @@ pdb_get_file_path(pseudo_msg_t *msg) {
char *response;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2438,7 +2438,7 @@ pdb_find_file_dev(pseudo_msg_t *msg, char **path) {
char *sql = "SELECT * FROM files WHERE dev = ? AND ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2492,7 +2492,7 @@ pdb_get_xattr(pseudo_msg_t *msg, char **value, size_t *len) {
char *sql = "SELECT value FROM xattrs WHERE dev = ? AND ino = ? AND name = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2523,7 +2523,7 @@ pdb_get_xattr(pseudo_msg_t *msg, char **value, size_t *len) {
*/
*value = malloc(length);
if (!*value) {
- pseudo_diag("%s: out of memory\n", __func__);
+ pseudo_error("%s: out of memory\n", __func__);
sqlite3_reset(select);
sqlite3_clear_bindings(select);
return 1;
@@ -2561,7 +2561,7 @@ pdb_list_xattr(pseudo_msg_t *msg, char **value, size_t *len) {
char *sql = "SELECT name FROM xattrs WHERE dev = ? AND ino = ? ORDER BY name;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2615,7 +2615,7 @@ pdb_remove_xattr(pseudo_msg_t *msg, char *value, size_t len) {
char *sql = "DELETE FROM xattrs WHERE dev = ? AND ino = ? AND name = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!delete) {
@@ -2656,7 +2656,7 @@ pdb_set_xattr(pseudo_msg_t *msg, char *value, size_t len, int flags) {
size_t vlen;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2769,7 +2769,7 @@ pdb_find_file_ino(pseudo_msg_t *msg) {
char *sql = "SELECT * FROM files WHERE ino = ?;";
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
if (!select) {
@@ -2813,7 +2813,7 @@ pdb_files(void) {
pdb_file_list l;
if (!file_db && get_dbs()) {
- pseudo_diag("%s: database error.\n", __func__);
+ pseudo_error("%s: database error.\n", __func__);
return 0;
}
@@ -2852,7 +2852,7 @@ pdb_file(pdb_file_list l) {
s = sqlite3_column_text(l->stmt, column++);
m = pseudo_msg_new(0, (const char *) s);
if (!m) {
- pseudo_diag("couldn't allocate file message.\n");
+ pseudo_error("couldn't allocate file message.\n");
return NULL;
}
pseudo_debug(PDBGF_DB, "pdb_file: '%s'\n", s ? (const char *) s : "<nil>");
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 06/23] pseudo_client: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (4 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 05/23] pseudo_db: Change pseudo_diag() calls to appropriate macros Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 07/23] pseudo_server: " Mark Hatle
` (16 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_client.c | 96 ++++++++++++++++++++++++-------------------------
1 file changed, 47 insertions(+), 49 deletions(-)
diff --git a/pseudo_client.c b/pseudo_client.c
index 7041366..69e5cbc 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -166,7 +166,7 @@ build_passwd_paths(void)
/* allocation and/or return */
if (passwd_paths) {
if (np != npasswd_paths) {
- pseudo_diag("internal error: path allocation was inconsistent.\n");
+ pseudo_error("internal error: path allocation was inconsistent.\n");
} else {
/* yes, we allocated one extra for a trailing
* null pointer.
@@ -178,14 +178,14 @@ build_passwd_paths(void)
passwd_paths = malloc((np + 1) * sizeof(*passwd_paths));
npasswd_paths = np;
if (!passwd_paths) {
- pseudo_diag("couldn't allocate storage for password paths.\n");
+ pseudo_error("couldn't allocate storage for password paths.\n");
exit(1);
}
np = 0;
}
} while (++pass < 2);
/* in theory the second pass already returned, but. */
- pseudo_diag("should totally not have gotten here.\n");
+ pseudo_error("should totally not have gotten here.\n");
return;
}
@@ -567,11 +567,11 @@ pseudo_init_client(void) {
}
pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD);
} else {
- pseudo_diag("No prefix available to to find server.\n");
+ pseudo_error("No prefix available to to find server.\n");
exit(1);
}
if (pseudo_prefix_dir_fd == -1) {
- pseudo_diag("Can't open prefix path '%s' for server: %s\n",
+ pseudo_error("Can't open prefix path '%s' for server: %s\n",
pseudo_path,
strerror(errno));
exit(1);
@@ -590,11 +590,11 @@ pseudo_init_client(void) {
}
pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD);
} else {
- pseudo_diag("No local state directory available for server/file interactions.\n");
+ pseudo_error("No local state directory available for server/file interactions.\n");
exit(1);
}
if (pseudo_localstate_dir_fd == -1) {
- pseudo_diag("Can't open local state path '%s': %s\n",
+ pseudo_error("Can't open local state path '%s': %s\n",
pseudo_path,
strerror(errno));
exit(1);
@@ -633,7 +633,7 @@ pseudo_init_client(void) {
if (pseudo_chroot) {
pseudo_chroot_len = strlen(pseudo_chroot);
} else {
- pseudo_diag("Can't store chroot path '%s'\n", env);
+ pseudo_error("Can't store chroot path '%s'\n", env);
}
}
free(env);
@@ -662,7 +662,7 @@ pseudo_init_client(void) {
static void
pseudo_file_close(int *fd, FILE **fp) {
if (!fp || !fd) {
- pseudo_diag("pseudo_file_close: needs valid pointers.\n");
+ pseudo_error("pseudo_file_close: needs valid pointers.\n");
return;
}
pseudo_antimagic();
@@ -698,7 +698,7 @@ pseudo_file_close(int *fd, FILE **fp) {
static FILE *
pseudo_file_open(char *name, int *fd, FILE **fp) {
if (!fp || !fd || !name) {
- pseudo_diag("pseudo_file_open: needs valid pointers.\n");
+ pseudo_error("pseudo_file_open: needs valid pointers.\n");
return NULL;
}
pseudo_file_close(fd, fp);
@@ -734,7 +734,7 @@ pseudo_pwd_lck_open(void) {
if (!pseudo_pwd_lck_name) {
pseudo_pwd_lck_name = malloc(pseudo_path_max());
if (!pseudo_pwd_lck_name) {
- pseudo_diag("couldn't allocate space for passwd lockfile path.\n");
+ pseudo_error("couldn't allocate space for passwd lockfile path.\n");
return -1;
}
}
@@ -815,7 +815,7 @@ pseudo_client_chroot(const char *path) {
pseudo_chroot_len = strlen(path);
pseudo_chroot = malloc(pseudo_chroot_len + 1);
if (!pseudo_chroot) {
- pseudo_diag("Couldn't allocate chroot directory buffer.\n");
+ pseudo_error("Couldn't allocate chroot directory buffer.\n");
pseudo_chroot_len = 0;
errno = ENOMEM;
return -1;
@@ -834,7 +834,7 @@ pseudo_root_path(const char *func, int line, int dirfd, const char *path, int le
rc = base_path(dirfd, path, leave_last);
pseudo_magic();
if (!rc) {
- pseudo_diag("couldn't allocate absolute path for '%s'.\n",
+ pseudo_error("couldn't allocate absolute path for '%s'.\n",
path ? path : "null");
}
pseudo_debug(PDBGF_CHROOT, "root_path [%s, %d]: '%s' from '%s'\n",
@@ -849,7 +849,7 @@ pseudo_client_getcwd(void) {
char *cwd;
cwd = malloc(pseudo_path_max());
if (!cwd) {
- pseudo_diag("Can't allocate CWD buffer!\n");
+ pseudo_error("Can't allocate CWD buffer!\n");
return -1;
}
pseudo_debug(PDBGF_CLIENT | PDBGF_VERBOSE, "getcwd: trying to find cwd.\n");
@@ -874,7 +874,7 @@ pseudo_client_getcwd(void) {
}
return 0;
} else {
- pseudo_diag("Can't get CWD: %s\n", strerror(errno));
+ pseudo_error("Can't get CWD: %s\n", strerror(errno));
return -1;
}
}
@@ -901,7 +901,7 @@ pseudo_client_path_set(int fd, const char *path, char ***patharray, int *len) {
*len, fd + 1);
(*patharray) = realloc((*patharray), (fd + 1) * sizeof(char *));
if (!*patharray) {
- pseudo_diag("couldn't realloc fd path array to %ld entries\n", (fd + 1) * sizeof(char *));
+ pseudo_error("couldn't realloc fd path array to %ld entries\n", (fd + 1) * sizeof(char *));
exit(1);
}
for (i = *len; i < fd + 1; ++i)
@@ -1002,7 +1002,7 @@ client_spawn_server(void) {
if ((server_pid = pseudo_real_fork()) != 0) {
if (server_pid == -1) {
- pseudo_diag("couldn't fork server: %s\n", strerror(errno));
+ pseudo_error("couldn't fork server: %s\n", strerror(errno));
return 1;
}
pseudo_evlog(PDBGF_CLIENT, "spawned new server, pid %d\n", server_pid);
@@ -1109,7 +1109,7 @@ client_spawn_server(void) {
pseudo_setupenv();
pseudo_dropenv();
pseudo_real_execv(argv[0], argv);
- pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
+ pseudo_error("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
exit(1);
}
}
@@ -1187,7 +1187,7 @@ pseudo_fd(int fd, int how) {
/* Set close on exec, even if we didn't move it. */
if ((newfd >= 0) && (fcntl(newfd, F_SETFD, FD_CLOEXEC) < 0))
- pseudo_diag("Can't set close on exec flag: %s\n",
+ pseudo_error("Can't set close on exec flag: %s\n",
strerror(errno));
return(newfd);
@@ -1208,7 +1208,7 @@ client_connect(void) {
pseudo_evlog(PDBGF_CLIENT, "creating socket %s.\n", sun.sun_path);
if (connect_fd == -1) {
char *e = strerror(errno);
- pseudo_diag("Can't create socket: %s (%s)\n", sun.sun_path, e);
+ pseudo_error("Can't create socket: %s (%s)\n", sun.sun_path, e);
pseudo_evlog(PDBGF_CLIENT, "failed to create socket: %s\n", e);
return 1;
}
@@ -1216,14 +1216,14 @@ client_connect(void) {
pseudo_debug(PDBGF_CLIENT, "connecting socket...\n");
cwd_fd = open(".", O_RDONLY);
if (cwd_fd == -1) {
- pseudo_diag("Couldn't stash directory before opening socket: %s",
+ pseudo_error("Couldn't stash directory before opening socket: %s",
strerror(errno));
close(connect_fd);
connect_fd = -1;
return 1;
}
if (fchdir(pseudo_localstate_dir_fd) == -1) {
- pseudo_diag("Couldn't chdir to server directory [%d]: %s\n",
+ pseudo_error("Couldn't chdir to server directory [%d]: %s\n",
pseudo_localstate_dir_fd, strerror(errno));
close(connect_fd);
close(cwd_fd);
@@ -1236,7 +1236,7 @@ client_connect(void) {
pseudo_evlog(PDBGF_CLIENT, "connect failed: %s\n", e);
close(connect_fd);
if (fchdir(cwd_fd) == -1) {
- pseudo_diag("return to previous directory failed: %s\n",
+ pseudo_error("return to previous directory failed: %s\n",
strerror(errno));
}
close(cwd_fd);
@@ -1244,7 +1244,7 @@ client_connect(void) {
return 1;
}
if (fchdir(cwd_fd) == -1) {
- pseudo_diag("return to previous directory failed: %s\n",
+ pseudo_error("return to previous directory failed: %s\n",
strerror(errno));
}
close(cwd_fd);
@@ -1402,11 +1402,9 @@ pseudo_client_request(pseudo_msg_t *msg, size_t len, const char *path) {
}
}
}
- pseudo_diag("pseudo: server connection persistently failed, aborting.\n");
+ pseudo_error("pseudo: server connection persistently failed, aborting.\n");
pseudo_evlog_dump();
- pseudo_diag("event log dumped, aborting.\n");
- abort();
- pseudo_diag("aborted.\n");
+ pseudo_critical("event log dumped, aborting.\n");
return 0;
}
@@ -1430,11 +1428,11 @@ pseudo_client_shutdown(int wait_on_socket) {
pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, COPY_FD);
free(pseudo_path);
} else {
- pseudo_diag("No prefix available to to find server.\n");
+ pseudo_error("No prefix available to to find server.\n");
exit(1);
}
if (pseudo_prefix_dir_fd == -1) {
- pseudo_diag("Can't open prefix path (%s) for server. (%s)\n",
+ pseudo_error("Can't open prefix path (%s) for server. (%s)\n",
pseudo_prefix_path(NULL),
strerror(errno));
exit(1);
@@ -1454,11 +1452,11 @@ pseudo_client_shutdown(int wait_on_socket) {
pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, COPY_FD);
free(pseudo_path);
} else {
- pseudo_diag("No prefix available to to find server.\n");
+ pseudo_error("No prefix available to to find server.\n");
exit(1);
}
if (pseudo_localstate_dir_fd == -1) {
- pseudo_diag("Can't open local state path (%s) for server. (%s)\n",
+ pseudo_error("Can't open local state path (%s) for server. (%s)\n",
pseudo_localstatedir_path(NULL),
strerror(errno));
exit(1);
@@ -1479,13 +1477,13 @@ pseudo_client_shutdown(int wait_on_socket) {
}
ack = pseudo_msg_receive(connect_fd);
if (!ack) {
- pseudo_diag("server did not respond to shutdown query.\n");
+ pseudo_error("server did not respond to shutdown query.\n");
return 1;
}
if (ack->type != PSEUDO_MSG_ACK) {
- pseudo_diag("Server refused shutdown. Remaining client fds: %d\n", ack->fd);
- pseudo_diag("Client pids: %s\n", ack->path);
- pseudo_diag("Server will shut down after all clients exit.\n");
+ pseudo_info("Server refused shutdown. Remaining client fds: %d\n", ack->fd);
+ pseudo_info("Client pids: %s\n", ack->path);
+ pseudo_info("Server will shut down after all clients exit.\n");
}
if (wait_on_socket) {
/* try to receive a message the server won't send;
@@ -1520,14 +1518,14 @@ base_path(int dirfd, const char *path, int leave_last) {
if (basepath) {
baselen = strlen(basepath);
} else {
- pseudo_diag("got *at() syscall for unknown directory, fd %d\n", dirfd);
+ pseudo_error("got *at() syscall for unknown directory, fd %d\n", dirfd);
}
} else {
basepath = pseudo_cwd;
baselen = pseudo_cwd_len;
}
if (!basepath) {
- pseudo_diag("unknown base path for fd %d, path %s\n", dirfd, path);
+ pseudo_error("unknown base path for fd %d, path %s\n", dirfd, path);
return 0;
}
/* if there's a chroot path, and it's the start of basepath,
@@ -1756,7 +1754,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
if (op == OP_RENAME) {
va_list ap;
if (!path) {
- pseudo_diag("rename (%s) without new path.\n",
+ pseudo_warning("rename (%s) without new path.\n",
path ? path : "<nil>");
pseudo_magic();
return 0;
@@ -1766,7 +1764,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
va_end(ap);
/* last argument is the previous path of the file */
if (!path_extra_1) {
- pseudo_diag("rename (%s) without old path.\n",
+ pseudo_warning("rename (%s) without old path.\n",
path ? path : "<nil>");
pseudo_magic();
return 0;
@@ -1835,7 +1833,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
alloced_path = malloc(full_len);
alloced_len = full_len;
if (!alloced_path) {
- pseudo_diag("Can't allocate space for paths for a rename operation. Sorry.\n");
+ pseudo_error("Can't allocate space for paths for a rename operation. Sorry.\n");
alloced_len = 0;
pseudo_magic();
return 0;
@@ -1859,7 +1857,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
alloced_path = malloc(pathlen);
alloced_len = pathlen;
if (!alloced_path) {
- pseudo_diag("Can't allocate space for paths for a rename operation. Sorry.\n");
+ pseudo_error("Can't allocate space for paths for a rename operation. Sorry.\n");
alloced_len = 0;
pseudo_magic();
return 0;
@@ -1965,7 +1963,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
if (fd == connect_fd) {
connect_fd = pseudo_fd(connect_fd, COPY_FD);
if (connect_fd == -1) {
- pseudo_diag("tried to close connection, couldn't dup: %s\n", strerror(errno));
+ pseudo_error("tried to close connection, couldn't dup: %s\n", strerror(errno));
}
} else if (fd == pseudo_util_debug_fd) {
pseudo_util_debug_fd = pseudo_fd(fd, COPY_FD);
@@ -2037,7 +2035,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
do_request = 1;
break;
default:
- pseudo_diag("error: unknown or unimplemented operator %d (%s)", op, pseudo_op_name(op));
+ pseudo_error("unknown or unimplemented operator %d (%s)", op, pseudo_op_name(op));
break;
}
/* result can only be set when PSEUDO_XATTRDB resulted in a
@@ -2069,7 +2067,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
pseudo_debug(PDBGF_OP, "(%d) %s", getpid(), pseudo_res_name(result->result));
if (result->result == RESULT_ABORT) {
char *local_state_dir = pseudo_get_value("PSEUDO_LOCALSTATEDIR");
- pseudo_diag("abort()ing pseudo client by server request. See https://wiki.yoctoproject.org/wiki/Pseudo_Abort for more details on this.\n"
+ pseudo_info("abort()ing pseudo client by server request. See https://wiki.yoctoproject.org/wiki/Pseudo_Abort for more details on this.\n"
"Check logfile: %s/%s\n", local_state_dir, PSEUDO_LOGFILE);
abort();
}
@@ -2149,13 +2147,13 @@ populate_path_segs(void) {
}
path_segs = malloc((c+2) * sizeof(*path_segs));
if (!path_segs) {
- pseudo_diag("warning: failed to allocate space for %d path segments.\n",
+ pseudo_warning("failed to allocate space for %d path segments.\n",
c);
return;
}
path_lens = malloc((c + 2) * sizeof(*path_lens));
if (!path_lens) {
- pseudo_diag("warning: failed to allocate space for %d path lengths.\n",
+ pseudo_warning("failed to allocate space for %d path lengths.\n",
c);
free(path_segs);
path_segs = 0;
@@ -2163,7 +2161,7 @@ populate_path_segs(void) {
}
previous_path_segs = strdup(previous_path);
if (!previous_path_segs) {
- pseudo_diag("warning: failed to allocate space for path copy.\n");
+ pseudo_warning("failed to allocate space for path copy.\n");
free(path_segs);
path_segs = NULL;
free(path_lens);
@@ -2242,7 +2240,7 @@ pseudo_exec_path(const char *filename, int search_path) {
candidate = pseudo_fix_path(dir, filename, 0, len, NULL, 0);
pseudo_debug(PDBGF_CLIENT, "exec_path: got %s for non-absolute path\n", candidate);
} else {
- pseudo_diag("couldn't allocate intermediate path.\n");
+ pseudo_error("couldn't allocate intermediate path.\n");
candidate = NULL;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 07/23] pseudo_server: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (5 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 06/23] pseudo_client: " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 08/23] pseudo.c: " Mark Hatle
` (15 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_server.c | 92 ++++++++++++++++++++++++-------------------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/pseudo_server.c b/pseudo_server.c
index edfbce1..c1a97c8 100644
--- a/pseudo_server.c
+++ b/pseudo_server.c
@@ -68,7 +68,7 @@ void pseudo_antimagic(void) { }
void
quit_now(int signal) {
- pseudo_diag("Received signal %d, quitting.\n", signal);
+ pseudo_info("Received signal %d, quitting.\n", signal);
die_forcefully = 1;
}
@@ -116,12 +116,12 @@ pseudo_server_write_pid(pid_t pid) {
pseudo_path = pseudo_localstatedir_path(PSEUDO_PIDFILE);
if (!pseudo_path) {
- pseudo_diag("Couldn't get path for prefix/%s\n", PSEUDO_PIDFILE);
+ pseudo_error("Couldn't get path for prefix/%s\n", PSEUDO_PIDFILE);
return 1;
}
fp = fopen(pseudo_path, "w");
if (!fp) {
- pseudo_diag("Couldn't open %s: %s\n",
+ pseudo_error("Couldn't open %s: %s\n",
pseudo_path, strerror(errno));
return 1;
}
@@ -171,7 +171,7 @@ pseudo_server_start(int daemonize) {
pseudo_debug_logfile(PSEUDO_LOGFILE, 2);
child = fork();
if (child == -1) {
- pseudo_diag("Couldn't fork child process: %s\n",
+ pseudo_error("Couldn't fork child process: %s\n",
strerror(errno));
exit(PSEUDO_EXIT_FORK_FAILED);
}
@@ -204,18 +204,18 @@ pseudo_server_start(int daemonize) {
exit(0);
}
if (got_sigalrm) {
- pseudo_diag("Child process timeout after %d seconds.\n",
+ pseudo_error("Child process timeout after %d seconds.\n",
PSEUDO_CHILD_PROCESS_TIMEOUT);
exit(PSEUDO_EXIT_TIMEOUT);
}
if (rc == -1) {
- pseudo_diag("Failure in waitpid(): %s\n",
+ pseudo_error("Failure in waitpid(): %s\n",
strerror(save_errno));
exit(PSEUDO_EXIT_WAITPID);
}
if (WIFSIGNALED(status)) {
status = WTERMSIG(status);
- pseudo_diag("Child process exited from signal %d.\n",
+ pseudo_error("Child process exited from signal %d.\n",
status);
kill(getpid(), status);
/* can't use +128 because that's not valid */
@@ -223,15 +223,15 @@ pseudo_server_start(int daemonize) {
}
if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
- pseudo_diag("Child process exit status %d: %s\n",
+ pseudo_error("Child process exit status %d: %s\n",
status,
pseudo_exit_status_name(status));
if (status == 0) {
- pseudo_diag("Hang on, server should not have exited 0 without sending us sigusr1?\n");
+ pseudo_error("Hang on, server should not have exited 0 without sending us sigusr1?\n");
}
exit(status);
}
- pseudo_diag("Unknown exit status %d.\n", status);
+ pseudo_error("Unknown exit status %d.\n", status);
exit(PSEUDO_EXIT_GENERAL);
} else {
/* detach from parent session */
@@ -245,24 +245,24 @@ pseudo_server_start(int daemonize) {
}
}
- pseudo_diag("pid %d [parent %d], doing new pid setup and server start\n", getpid(), getppid());
+ pseudo_info("pid %d [parent %d], doing new pid setup and server start\n", getpid(), getppid());
pseudo_new_pid();
pseudo_debug(PDBGF_SERVER, "opening lock.\n");
lockpath = pseudo_localstatedir_path(NULL);
if (!lockpath) {
- pseudo_diag("Couldn't allocate a file path.\n");
+ pseudo_error("Couldn't allocate a file path.\n");
exit(PSEUDO_EXIT_LOCK_PATH);
}
mkdir_p(lockpath);
lockname = pseudo_localstatedir_path(PSEUDO_LOCKFILE);
if (!lockname) {
- pseudo_diag("Couldn't allocate a file path.\n");
+ pseudo_error("Couldn't allocate a file path.\n");
exit(PSEUDO_EXIT_LOCK_PATH);
}
lockfd = open(lockname, O_RDWR | O_CREAT, 0644);
if (lockfd < 0) {
- pseudo_diag("Can't open or create lockfile %s: %s\n",
+ pseudo_error("Can't open or create lockfile %s: %s\n",
lockname, strerror(errno));
exit(PSEUDO_EXIT_LOCK_FAILED);
}
@@ -275,7 +275,7 @@ pseudo_server_start(int daemonize) {
if (lockfd <= 2) {
newfd = fcntl(lockfd, F_DUPFD, 3);
if (newfd < 0) {
- pseudo_diag("Can't move lockfile to safe descriptor, leaving it on %d: %s\n",
+ pseudo_warning("Can't move lockfile to safe descriptor, leaving it on %d: %s\n",
lockfd, strerror(errno));
} else {
close(lockfd);
@@ -297,11 +297,11 @@ pseudo_server_start(int daemonize) {
if (save_errno == EACCES || save_errno == EAGAIN) {
rc = fcntl(lockfd, F_GETLK, &lock_data);
if (rc == 0 && lock_data.l_type != F_UNLCK) {
- pseudo_diag("lock already held by existing pid %d.\n",
+ pseudo_warning("lock already held by existing pid %d.\n",
lock_data.l_pid);
}
}
- pseudo_diag("Couldn't obtain lock: %s.\n", strerror(save_errno));
+ pseudo_error("Couldn't obtain lock: %s.\n", strerror(save_errno));
exit(PSEUDO_EXIT_LOCK_HELD);
} else {
@@ -314,14 +314,14 @@ pseudo_server_start(int daemonize) {
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (listen_fd < 0) {
- pseudo_diag("couldn't create listening socket: %s\n", strerror(errno));
+ pseudo_error("couldn't create listening socket: %s\n", strerror(errno));
exit(PSEUDO_EXIT_SOCKET_CREATE);
}
if (listen_fd <= 2) {
newfd = fcntl(listen_fd, F_DUPFD, 3);
if (newfd < 0) {
- pseudo_diag("couldn't dup listening socket: %s\n", strerror(errno));
+ pseudo_error("couldn't dup listening socket: %s\n", strerror(errno));
close(listen_fd);
exit(PSEUDO_EXIT_SOCKET_FD);
} else {
@@ -333,7 +333,7 @@ pseudo_server_start(int daemonize) {
/* cd to the data directory */
pseudo_path = pseudo_localstatedir_path(NULL);
if (!pseudo_path || chdir(pseudo_path) == -1) {
- pseudo_diag("can't get to '%s': %s\n",
+ pseudo_error("can't get to '%s': %s\n",
pseudo_path, strerror(errno));
exit(PSEUDO_EXIT_SOCKET_PATH);
}
@@ -341,21 +341,21 @@ pseudo_server_start(int daemonize) {
/* remove existing socket -- if it exists */
rc = unlink(sun.sun_path);
if (rc == -1 && errno != ENOENT) {
- pseudo_diag("Can't unlink existing socket: %s.\n",
+ pseudo_error("Can't unlink existing socket: %s.\n",
strerror(errno));
exit(PSEUDO_EXIT_SOCKET_UNLINK);
}
if (bind(listen_fd, (struct sockaddr *) &sun, sizeof(sun)) == -1) {
- pseudo_diag("couldn't bind listening socket: %s\n", strerror(errno));
+ pseudo_error("couldn't bind listening socket: %s\n", strerror(errno));
exit(PSEUDO_EXIT_SOCKET_BIND);
}
if (listen(listen_fd, 5) == -1) {
- pseudo_diag("couldn't listen on socket: %s\n", strerror(errno));
+ pseudo_error("couldn't listen on socket: %s\n", strerror(errno));
exit(PSEUDO_EXIT_SOCKET_LISTEN);
}
rc = pseudo_server_write_pid(getpid());
if (rc != 0) {
- pseudo_diag("warning: couldn't write pid file.\n");
+ pseudo_warning("couldn't write pid file.\n");
}
signal(SIGHUP, quit_now);
signal(SIGINT, quit_now);
@@ -366,9 +366,9 @@ pseudo_server_start(int daemonize) {
if (daemonize) {
pid_t ppid = getppid();
if (ppid == 1) {
- pseudo_diag("Setup complete, but parent is init, not sending SIGUSR1.\n");
+ pseudo_info("Setup complete, but parent is init, not sending SIGUSR1.\n");
} else {
- pseudo_diag("Setup complete, sending SIGUSR1 to pid %d.\n",
+ pseudo_info("Setup complete, sending SIGUSR1 to pid %d.\n",
ppid);
kill(ppid, SIGUSR1);
}
@@ -424,7 +424,7 @@ open_client(int fd) {
++active_clients;
return max_clients - 16;
} else {
- pseudo_diag("error allocating new client, fd %d\n", fd);
+ pseudo_error("error allocating new client, fd %d\n", fd);
close(fd);
return 0;
}
@@ -439,7 +439,7 @@ close_client(int client) {
clients[client].pid, clients[client].fd);
/* client went away... */
if (client > highest_client || client <= 0) {
- pseudo_diag("tried to close client %d (highest is %d)\n",
+ pseudo_info("tried to close client %d (highest is %d)\n",
client, highest_client);
return;
}
@@ -559,7 +559,7 @@ serve_client(int i) {
response_path = malloc(8 * active_clients);
if (!response_path) {
- pseudo_diag("out of memory allocating shutdown response\n");
+ pseudo_error("out of memory allocating shutdown response\n");
exit(PSEUDO_EXIT_GENERAL);
} else {
memset(response_path, 0, 8 * active_clients);
@@ -633,7 +633,7 @@ static void pseudo_server_loop_epoll(void)
clients = malloc(16 * sizeof(*clients));
if (!clients) {
- pseudo_diag("out of memory allocating client table.\n");
+ pseudo_error("out of memory allocating client table.\n");
exit(PSEUDO_EXIT_LISTEN_FD);
}
@@ -655,7 +655,7 @@ static void pseudo_server_loop_epoll(void)
pseudo_debug(PDBGF_SERVER, "server loop started.\n");
if (listen_fd < 0) {
- pseudo_diag("got into loop with no valid listen fd.\n");
+ pseudo_error("got into loop with no valid listen fd.\n");
exit(PSEUDO_EXIT_LISTEN_FD);
}
@@ -663,13 +663,13 @@ static void pseudo_server_loop_epoll(void)
int epollfd = epoll_create1(0);
if (epollfd == -1) {
- pseudo_diag("epoll_create1() failed.\n");
+ pseudo_error("epoll_create1() failed.\n");
exit(PSEUDO_EXIT_EPOLL_CREATE);
}
ev.events = EPOLLIN;
ev.data.u64 = 0;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clients[0].fd, &ev) == -1) {
- pseudo_diag("epoll_ctl() failed with listening socket.\n");
+ pseudo_error("epoll_ctl() failed with listening socket.\n");
exit(PSEUDO_EXIT_EPOLL_CTL);
}
@@ -724,7 +724,7 @@ static void pseudo_server_loop_epoll(void)
ev.events = EPOLLIN;
ev.data.u64 = open_client(fd);
if (ev.data.u64 != 0 && epoll_ctl(epollfd, EPOLL_CTL_ADD, clients[ev.data.u64].fd, &ev) == -1) {
- pseudo_diag("epoll_ctl() failed with accepted socket.\n");
+ pseudo_error("epoll_ctl() failed with accepted socket.\n");
exit(PSEUDO_EXIT_EPOLL_CTL);
}
} else if (errno == EMFILE) {
@@ -746,22 +746,22 @@ static void pseudo_server_loop_epoll(void)
}
pseudo_debug(PDBGF_SERVER, "server loop complete [%d clients left]\n", active_clients);
} else {
- pseudo_diag("epoll_wait failed: %s\n", strerror(errno));
+ pseudo_error("epoll_wait failed: %s\n", strerror(errno));
break;
}
if (do_list_clients) {
do_list_clients = 0;
- pseudo_diag("listing clients [1 through %d]:\n", highest_client);
+ pseudo_info("listing clients [1 through %d]:\n", highest_client);
for (i = 1; i <= highest_client; ++i) {
if (clients[i].fd == -1) {
- pseudo_diag("client %4d: inactive.\n", i);
+ pseudo_info("client %4d: inactive.\n", i);
continue;
}
- pseudo_diag("client %4d: fd %4d, pid %5d, program %s\n",
+ pseudo_info("client %4d: fd %4d, pid %5d, program %s\n",
i, clients[i].fd, clients[i].pid,
clients[i].program ? clients[i].program : "<unspecified>");
}
- pseudo_diag("done.\n");
+ pseudo_info("done.\n");
}
if (die_peacefully || die_forcefully) {
pseudo_debug(PDBGF_SERVER, "quitting.\n");
@@ -807,7 +807,7 @@ pseudo_server_loop(void) {
clients = malloc(16 * sizeof(*clients));
if (!clients) {
- pseudo_diag("out of memory allocating client table.\n");
+ pseudo_error("out of memory allocating client table.\n");
exit(PSEUDO_EXIT_LISTEN_FD);
}
@@ -830,7 +830,7 @@ pseudo_server_loop(void) {
pseudo_debug(PDBGF_SERVER, "server loop started.\n");
if (listen_fd < 0) {
- pseudo_diag("got into loop with no valid listen fd.\n");
+ pseudo_error("got into loop with no valid listen fd.\n");
exit(PSEUDO_EXIT_LISTEN_FD);
}
pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server started (pid %d)", getpid());
@@ -924,18 +924,18 @@ pseudo_server_loop(void) {
}
if (do_list_clients) {
do_list_clients = 0;
- pseudo_diag("listing clients [1 through %d]:\n", highest_client);
+ pseudo_info("listing clients [1 through %d]:\n", highest_client);
for (i = 1; i <= highest_client; ++i) {
if (clients[i].fd == -1) {
- pseudo_diag("client %4d: inactive.\n", i);
+ pseudo_info("client %4d: inactive.\n", i);
continue;
}
- pseudo_diag("client %4d: fd %4d, pid %5d, state %s, program %s\n",
+ pseudo_info("client %4d: fd %4d, pid %5d, state %s, program %s\n",
i, clients[i].fd, clients[i].pid,
FD_ISSET(clients[i].fd, &reads) ? "R" : "-",
clients[i].program ? clients[i].program : "<unspecified>");
}
- pseudo_diag("done.\n");
+ pseudo_info("done.\n");
}
if (die_peacefully || die_forcefully) {
pseudo_debug(PDBGF_SERVER, "quitting.\n");
@@ -981,6 +981,6 @@ pseudo_server_loop(void) {
timeout = (struct timeval) { .tv_sec = LOOP_DELAY, .tv_usec = 0 };
sigprocmask(SIG_BLOCK, &maskusr2, NULL);
}
- pseudo_diag("select failed: %s\n", strerror(errno));
+ pseudo_error("select failed: %s\n", strerror(errno));
}
#endif /* this is the else of #ifdef PSEUDO_EPOLL */
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 08/23] pseudo.c: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (6 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 07/23] pseudo_server: " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 09/23] pseudolog.c: " Mark Hatle
` (14 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo.c | 100 +++++++++++++++++++++++++++----------------------------
1 file changed, 50 insertions(+), 50 deletions(-)
diff --git a/pseudo.c b/pseudo.c
index e5fe5cf..11112dd 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -105,8 +105,8 @@ main(int argc, char *argv[]) {
pseudo_debug(PDBGF_SERVER, "[server %d] can't run daemon with libpseudo in %s\n", getpid(), PRELINK_LIBRARIES);
s = pseudo_get_value("PSEUDO_UNLOAD");
if (s) {
- pseudo_diag("pseudo: I can't seem to make %s go away. Sorry.\n", PRELINK_LIBRARIES);
- pseudo_diag("pseudo: %s: %s\n", PRELINK_LIBRARIES, ld_env);
+ pseudo_error("pseudo: I can't seem to make %s go away. Sorry.\n", PRELINK_LIBRARIES);
+ pseudo_error("pseudo: %s: %s\n", PRELINK_LIBRARIES, ld_env);
exit(PSEUDO_EXIT_PSEUDO_LOADED);
}
free(s);
@@ -155,7 +155,7 @@ main(int argc, char *argv[]) {
case 'i': /* renumber devices, assuming stable inodes */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, 0);
if (!s) {
- pseudo_diag("Can't resolve path '%s'\n", optarg);
+ pseudo_error("Can't resolve path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
opt_i = strdup(s);
@@ -168,7 +168,7 @@ main(int argc, char *argv[]) {
case 'm': /* move from... (see also 'M') */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, 0);
if (!s) {
- pseudo_diag("Can't resolve move-from path '%s'\n", optarg);
+ pseudo_error("Can't resolve move-from path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
opt_m = strdup(s);
@@ -176,7 +176,7 @@ main(int argc, char *argv[]) {
case 'M': /* move to... (see also 'm') */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, 0);
if (!s) {
- pseudo_diag("Can't resolve move-to path '%s'\n", optarg);
+ pseudo_error("Can't resolve move-to path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
opt_M = strdup(s);
@@ -184,7 +184,7 @@ main(int argc, char *argv[]) {
case 'p': /* passwd file path */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW);
if (!s) {
- pseudo_diag("Can't resolve passwd path '%s'\n", optarg);
+ pseudo_error("Can't resolve passwd path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
pseudo_set_value("PSEUDO_PASSWD", s);
@@ -192,7 +192,7 @@ main(int argc, char *argv[]) {
case 'P': /* prefix */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW);
if (!s) {
- pseudo_diag("Can't resolve prefix path '%s'\n", optarg);
+ pseudo_error("Can't resolve prefix path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
pseudo_set_value("PSEUDO_PREFIX", s);
@@ -201,7 +201,7 @@ main(int argc, char *argv[]) {
case 'R': /* pseudo root path */
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW);
if (!s) {
- pseudo_diag("Can't resolve root path '%s'\n", optarg);
+ pseudo_error("Can't resolve root path '%s'\n", optarg);
usage(EXIT_FAILURE);
}
pseudo_set_value("PSEUDO_CHROOT", s);
@@ -214,7 +214,7 @@ main(int argc, char *argv[]) {
case 't': /* timeout */
pseudo_server_timeout = pseudo_strtol_wrapper(optarg, &s, 10);
if (*s && !isspace(*s)) {
- pseudo_diag("Timeout must be an integer value.\n");
+ pseudo_error("Timeout must be an integer value.\n");
usage(EXIT_FAILURE);
}
optptr += snprintf(optptr, pseudo_path_max() - (optptr - opts),
@@ -239,7 +239,7 @@ main(int argc, char *argv[]) {
break;
case '?':
default:
- pseudo_diag("unknown/invalid argument (option '%c').\n", optopt);
+ pseudo_error("unknown/invalid argument (option '%c').\n", optopt);
usage(EXIT_FAILURE);
break;
}
@@ -250,7 +250,7 @@ main(int argc, char *argv[]) {
s = pseudo_get_prefix(argv[0]);
if (!s) {
- pseudo_diag("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n");
+ pseudo_error("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n");
exit(PSEUDO_EXIT_PSEUDO_PREFIX);
}
free(s);
@@ -261,29 +261,29 @@ main(int argc, char *argv[]) {
pseudo_msg_t *msg;
int rc;
if (!(opt_m && opt_M)) {
- pseudo_diag("You cannot move the database without specifying from and to.\n");
+ pseudo_error("You cannot move the database without specifying from and to.\n");
exit(EXIT_FAILURE);
}
if (stat(opt_M, &buf) < 0) {
- pseudo_diag("stat of '%s' failed: %s\n",
+ pseudo_error("stat of '%s' failed: %s\n",
opt_M, strerror(errno));
- pseudo_diag("The directory the database is being moved to must exist.\n");
+ pseudo_error("The directory the database is being moved to must exist.\n");
exit(EXIT_FAILURE);
}
msg = pseudo_msg_new(0, opt_M);
if (!msg) {
- pseudo_diag("Can't allocate message structure.\n");
+ pseudo_error("Can't allocate message structure.\n");
exit(EXIT_FAILURE);
}
rc = pdb_rename_file(opt_m, msg);
free(msg);
if (rc < 0) {
- pseudo_diag("Warning: Database move may have failed.\n");
- pseudo_diag("To try to restore, you can reverse the move.\n");
- pseudo_diag("To commit to this anyway, run pseudo -C to check the database.\n");
+ pseudo_warning("Database move may have failed.\n");
+ pseudo_warning("To try to restore, you can reverse the move.\n");
+ pseudo_warning("To commit to this anyway, run pseudo -C to check the database.\n");
exit(EXIT_FAILURE);
}
- pseudo_diag("Rename looked okay, running database sanity check.\n");
+ pseudo_info("Rename looked okay, running database sanity check.\n");
opt_C = 1;
}
@@ -292,32 +292,32 @@ main(int argc, char *argv[]) {
struct stat buf;
pseudo_msg_t *msg;
if (stat(opt_i, &buf) < 0) {
- pseudo_diag("stat of '%s' failed: %s\n",
+ pseudo_error("stat of '%s' failed: %s\n",
opt_i, strerror(errno));
- pseudo_diag("The file used to renumber the database must exist.\n");
+ pseudo_error("The file used to renumber the database must exist.\n");
exit(EXIT_FAILURE);
}
msg = pseudo_msg_new(0, opt_i);
if (!msg) {
- pseudo_diag("Couldn't allocate data structure for path.\n");
+ pseudo_error("Couldn't allocate data structure for path.\n");
exit(EXIT_FAILURE);
}
if (pdb_find_file_path(msg)) {
- pseudo_diag("Couldn't find a database entry for '%s'.\n", opt_i);
+ pseudo_error("Couldn't find a database entry for '%s'.\n", opt_i);
exit(EXIT_FAILURE);
}
if (buf.st_ino != msg->ino) {
- pseudo_diag("The database inode entry for '%s' doesn't match; you must use -b.\n",
+ pseudo_error("The database inode entry for '%s' doesn't match; you must use -b.\n",
opt_i);
exit(EXIT_FAILURE);
}
rc = pdb_renumber_all(msg->dev, buf.st_dev);
free(msg);
if (rc < 0) {
- pseudo_diag("Warning: Database renumber failed.\n");
+ pseudo_warning("Database renumber failed.\n");
exit(EXIT_FAILURE);
}
- pseudo_diag("Renumber looked okay, running database sanity check.\n");
+ pseudo_info("Renumber looked okay, running database sanity check.\n");
opt_C = 1;
}
@@ -332,13 +332,13 @@ main(int argc, char *argv[]) {
}
if (opt_d && opt_f) {
- pseudo_diag("You cannot run a foregrounded daemon.\n");
+ pseudo_error("You cannot run a foregrounded daemon.\n");
exit(PSEUDO_EXIT_PSEUDO_INVOCATION);
}
if (opt_f || opt_d) {
if (argc > optind) {
- pseudo_diag("pseudo: running program implies spawning background daemon.\n");
+ pseudo_error("pseudo: running program implies spawning background daemon.\n");
exit(PSEUDO_EXIT_PSEUDO_INVOCATION);
}
} else {
@@ -347,7 +347,7 @@ main(int argc, char *argv[]) {
if (opt_r) {
if (chdir(opt_r) == -1) {
- pseudo_diag("failed to chdir to '%s': %s\n",
+ pseudo_error("failed to chdir to '%s': %s\n",
opt_r, strerror(errno));
exit(EXIT_FAILURE);
}
@@ -378,7 +378,7 @@ main(int argc, char *argv[]) {
int len = strcspn(path, ":");
if ( snprintf(fullpath, pseudo_path_max(), "%.*s/%s",
len, path, argv[0]) > (int) pseudo_path_max()) {
- pseudo_diag("pseudo: path too long.\n");
+ pseudo_error("pseudo: path too long.\n");
exit(EXIT_FAILURE);
}
path += len;
@@ -392,7 +392,7 @@ main(int argc, char *argv[]) {
}
}
if (!found) {
- pseudo_diag("Can't find '%s' in $PATH.\n",
+ pseudo_error("Can't find '%s' in $PATH.\n",
argv[0]);
exit(EXIT_FAILURE);
}
@@ -401,7 +401,7 @@ main(int argc, char *argv[]) {
rc = fork();
if (rc == -1) {
- pseudo_diag("pseudo: fork failed: %s\n",
+ pseudo_error("pseudo: fork failed: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
} else {
@@ -424,7 +424,7 @@ main(int argc, char *argv[]) {
} else {
rc = execv(fullpath, argv);
if (rc == -1) {
- pseudo_diag("pseudo: can't run %s: %s\n",
+ pseudo_error("pseudo: can't run %s: %s\n",
argv[0], strerror(errno));
}
}
@@ -615,7 +615,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
*/
pdb_did_unlink_file(msg->path, NULL, by_path.deleting);
} else {
- pseudo_diag("inode mismatch: '%s' ino %llu in db, %llu in request.\n",
+ pseudo_error("inode mismatch: '%s' ino %llu in db, %llu in request.\n",
msg->path,
(unsigned long long) by_path.ino,
(unsigned long long) msg_header.ino);
@@ -634,14 +634,14 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
* the bogus entry that we noticed.
*/
if (S_ISDIR(by_path.mode) != S_ISDIR(msg_header.mode)) {
- pseudo_diag("dir mismatch: '%s' [%llu] db mode 0%o, header mode 0%o (unlinking db)\n",
+ pseudo_error("dir mismatch: '%s' [%llu] db mode 0%o, header mode 0%o (unlinking db)\n",
msg->path, (unsigned long long) by_path.ino,
(int) by_path.mode, (int) msg_header.mode);
/* unlink this path -- the inode may be in use elsewhere */
pdb_unlink_file(msg);
found_path = 0;
} else if (S_ISLNK(by_path.mode) != S_ISLNK(msg_header.mode)) {
- pseudo_diag("symlink mismatch: '%s' [%llu] db mode 0%o, header mode 0%o (unlinking db)\n",
+ pseudo_error("symlink mismatch: '%s' [%llu] db mode 0%o, header mode 0%o (unlinking db)\n",
msg->path, (unsigned long long) by_path.ino,
(int) by_path.mode, (int) msg_header.mode);
/* unlink this path -- the inode may be in use elsewhere */
@@ -649,7 +649,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
found_path = 0;
}
if (trailing_slash && !S_ISDIR(by_path.mode)) {
- pseudo_diag("dir quasi-mismatch: '%s' [%llu] db mode 0%o, incoming path had trailing slash. Not unlinking.\n",
+ pseudo_error("dir quasi-mismatch: '%s' [%llu] db mode 0%o, incoming path had trailing slash. Not unlinking.\n",
msg->path, (unsigned long long) by_path.ino,
(int) by_path.mode);
}
@@ -713,7 +713,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
pseudo_debug(PDBGF_FILE, "inode mismatch for '%s' -- old one was marked for deletion.\n",
msg->path);
} else {
- pseudo_diag("path mismatch [%d link%s]: ino %llu db '%s' req '%s'.\n",
+ pseudo_error("path mismatch [%d link%s]: ino %llu db '%s' req '%s'.\n",
msg->nlink,
msg->nlink == 1 ? "" : "s",
(unsigned long long) msg_header.ino,
@@ -734,7 +734,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
* entry. There is no way it can be right.
*/
if (S_ISDIR(by_ino.mode) != S_ISDIR(msg_header.mode)) {
- pseudo_diag("dir err : %llu ['%s'] (db '%s') db mode 0%o, header mode 0%o (unlinking db)\n",
+ pseudo_error("dir err : %llu ['%s'] (db '%s') db mode 0%o, header mode 0%o (unlinking db)\n",
(unsigned long long) msg_header.ino,
msg->pathlen ? msg->path : "no path",
path_by_ino ? path_by_ino : "no path",
@@ -746,7 +746,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
* can ever be a symlink; the test is generic as
* insurance against forgetting to fix it in a future
* update. */
- pseudo_diag("symlink err : %llu ['%s'] (db '%s') db mode 0%o, header mode 0%o (unlinking db)\n",
+ pseudo_error("symlink err : %llu ['%s'] (db '%s') db mode 0%o, header mode 0%o (unlinking db)\n",
(unsigned long long) msg_header.ino,
msg->pathlen ? msg->path : "no path",
path_by_ino ? path_by_ino : "no path",
@@ -771,7 +771,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
case OP_CLOSE:
/* these messages are handled entirely on the client side,
* as of this writing, but might be logged by accident: */
- pseudo_diag("error: op %s sent to server.\n", pseudo_op_name(msg->op));
+ pseudo_error("op %s sent to server.\n", pseudo_op_name(msg->op));
break;
case OP_EXEC: /* FALLTHROUGH */
case OP_OPEN:
@@ -785,7 +785,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
* ... But only if it wasn't a match on both inode *and*
* path, because if it were, that would be harmless.
*/
- pseudo_diag("creat for '%s' replaces existing %llu ['%s'].\n",
+ pseudo_info("creat for '%s' replaces existing %llu ['%s'].\n",
msg->pathlen ? msg->path : "no path",
(unsigned long long) by_ino.ino,
path_by_ino ? path_by_ino : "no path");
@@ -797,7 +797,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
pdb_link_file(msg);
} else {
/* again, an error, but leaving it alone for now. */
- pseudo_diag("creat ignored for existing file '%s'.\n",
+ pseudo_error("creat ignored for existing file '%s'.\n",
msg->pathlen ? msg->path : "no path");
}
break;
@@ -984,7 +984,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
* file DID NOT exist before the call. Fix database:
*/
if (found_path) {
- pseudo_diag("mkdir/mknod: '%s' [%llu] already existed (mode 0%o), unlinking\n",
+ pseudo_info("mkdir/mknod: '%s' [%llu] already existed (mode 0%o), unlinking\n",
msg->path, (unsigned long long) by_path.ino,
(int) by_path.mode);
pdb_unlink_file(msg);
@@ -1035,7 +1035,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **respon
pdb_remove_xattr(msg, oldpath, oldpathlen);
break;
default:
- pseudo_diag("unknown op from client %d, op %d [%s]\n",
+ pseudo_error("unknown op from client %d, op %d [%s]\n",
msg->client, msg->op,
msg->pathlen ? msg->path : "no path");
break;
@@ -1110,7 +1110,7 @@ pseudo_db_check(int fix) {
l = pdb_files();
if (!l) {
- pseudo_diag("Couldn't start file list, can't scan.\n");
+ pseudo_error("Couldn't start file list, can't scan.\n");
return EXIT_FAILURE;
}
while ((m = pdb_file(l)) != NULL) {
@@ -1123,7 +1123,7 @@ pseudo_db_check(int fix) {
pseudo_debug(PDBGF_DB, "Checking <%s>\n", m->path);
if (lstat(m->path, &buf)) {
if (!fix) {
- pseudo_diag("can't stat <%s>\n", m->path);
+ pseudo_error("can't stat <%s>\n", m->path);
errors = EXIT_FAILURE;
continue;
} else {
@@ -1180,7 +1180,7 @@ pseudo_db_check(int fix) {
rc = pdb_may_unlink_file(m, magic_cookie);
}
if (rc) {
- pseudo_diag("error updating file %s\n",
+ pseudo_error("error updating file %s\n",
m->path);
errors = EXIT_FAILURE;
}
@@ -1195,8 +1195,8 @@ pseudo_db_check(int fix) {
if (delete_some) {
rc = pdb_did_unlink_files(magic_cookie);
if (rc) {
- pseudo_diag("error nuking mismatched files.\n");
- pseudo_diag("database may not be fixed.\n");
+ pseudo_error("error nuking mismatched files.\n");
+ pseudo_error("database may not be fixed.\n");
errors = EXIT_FAILURE;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 09/23] pseudolog.c: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (7 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 08/23] pseudo.c: " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 10/23] wrappers: " Mark Hatle
` (13 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudolog.c | 76 ++++++++++++++++++++++++++---------------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/pseudolog.c b/pseudolog.c
index 44f7dbf..a497eb5 100644
--- a/pseudolog.c
+++ b/pseudolog.c
@@ -128,7 +128,7 @@ plog_query_type(char **string) {
return PSQT_UNKNOWN;
switch (**string) {
case '\0':
- pseudo_diag("Error: Value may not be an empty string.");
+ pseudo_error("Value may not be an empty string.");
return PSQT_UNKNOWN;
break;
case '>':
@@ -170,7 +170,7 @@ plog_query_type(char **string) {
break;
}
if (opt_l && type != PSQT_EXACT) {
- pseudo_diag("Error: Non-exact match requested while trying to create a log entry.\n");
+ pseudo_error("Non-exact match requested while trying to create a log entry.\n");
type = PSQT_UNKNOWN;
}
return type;
@@ -214,7 +214,7 @@ parse_file_type(char *string) {
return S_IFSOCK;
break;
default:
- pseudo_diag("unknown file type %c; should be one of [-bcdflps]\n",
+ pseudo_error("unknown file type %c; should be one of [-bcdflps]\n",
isprint(*string) ? *string : '?');
return -1;
break;
@@ -231,7 +231,7 @@ parse_partial_mode(char *string) {
case '-':
break;
default:
- pseudo_diag("unknown mode character: %c\n", string[0]);
+ pseudo_error("unknown mode character: %c\n", string[0]);
return -1;
break;
}
@@ -242,7 +242,7 @@ parse_partial_mode(char *string) {
case '-':
break;
default:
- pseudo_diag("unknown mode character: %c\n", string[1]);
+ pseudo_error("unknown mode character: %c\n", string[1]);
return -1;
break;
}
@@ -261,7 +261,7 @@ parse_partial_mode(char *string) {
case '-':
break;
default:
- pseudo_diag("unknown mode character: %c\n", string[2]);
+ pseudo_error("unknown mode character: %c\n", string[2]);
return -1;
break;
}
@@ -275,14 +275,14 @@ parse_mode_string(char *string) {
mode_t bits = 0;
if (len != 9 && len != 10) {
- pseudo_diag("mode strings must be of the form [-]rwxr-xr-x\n");
+ pseudo_error("mode strings must be of the form [-]rwxr-xr-x\n");
return -1;
}
if (len == 10) {
mode |= parse_file_type(string);
++string;
if (mode == (mode_t) -1) {
- pseudo_diag("mode strings with a file type must use a valid type [-bcdflps]\n");
+ pseudo_error("mode strings with a file type must use a valid type [-bcdflps]\n");
return -1;
}
}
@@ -341,14 +341,14 @@ parse_timestamp(char *string) {
}
}
if (!time_formats[i]) {
- pseudo_diag("Couldn't parse <%s> as a time. Current time in known formats is:\n",
+ pseudo_error("Couldn't parse <%s> as a time. Current time in known formats is:\n",
string);
localtime_r(&stamp_sec, &stamp_tm);
for (i = 0; time_formats[i]; ++i) {
strftime(timebuf, sizeof(timebuf), time_formats[i], &stamp_tm);
- pseudo_diag("\t%s\n", timebuf);
+ pseudo_info("\t%s\n", timebuf);
}
- pseudo_diag("Or, specify your own with -E; see strptime(3).\n");
+ pseudo_info("Or, specify your own with -E; see strptime(3).\n");
return -1;
}
return mktime(&stamp_tm);
@@ -360,31 +360,31 @@ plog_trait(int opt, char *string) {
char *endptr;
if (opt < 0 || opt > UCHAR_MAX) {
- pseudo_diag("Unknown/invalid option value: %d\n", opt);
+ pseudo_error("Unknown/invalid option value: %d\n", opt);
return 0;
}
if (!opt_to_field[opt]) {
if (isprint(opt)) {
- pseudo_diag("Unknown option: -%c\n", opt);
+ pseudo_error("Unknown option: -%c\n", opt);
} else {
- pseudo_diag("Unknown option: 0x%02x\n", opt);
+ pseudo_error("Unknown option: 0x%02x\n", opt);
}
return 0;
}
if (!*string) {
- pseudo_diag("invalid empty string for -%c\n", opt);
+ pseudo_error("invalid empty string for -%c\n", opt);
return 0;
}
new_trait = calloc(1, sizeof(*new_trait));
if (!new_trait) {
- pseudo_diag("Couldn't allocate requested trait (for -%c %s)\n",
+ pseudo_error("Couldn't allocate requested trait (for -%c %s)\n",
opt, string ? string : "<nil>");
return 0;
}
new_trait->field = opt_to_field[opt];
new_trait->type = plog_query_type(&string);
if (new_trait->type == PSQT_UNKNOWN) {
- pseudo_diag("Couldn't comprehend trait type for '%s'\n",
+ pseudo_error("Couldn't comprehend trait type for '%s'\n",
string ? string : "<nil>");
free(new_trait);
return 0;
@@ -393,7 +393,7 @@ plog_trait(int opt, char *string) {
case PSQF_ACCESS:
new_trait->data.ivalue = pseudo_access_fopen(string);
if (new_trait->data.ivalue == (unsigned long long) -1) {
- pseudo_diag("access flags should be specified like fopen(3) mode strings (or x for exec).\n");
+ pseudo_error("access flags should be specified like fopen(3) mode strings (or x for exec).\n");
free(new_trait);
return 0;
}
@@ -406,7 +406,7 @@ plog_trait(int opt, char *string) {
* first character is the terminating NUL, we may not
* access the second. */
if (string[0] && string[1]) {
- pseudo_diag("file type must be a single character [-bcdflps].\n");
+ pseudo_error("file type must be a single character [-bcdflps].\n");
free(new_trait);
return 0;
}
@@ -421,13 +421,13 @@ plog_trait(int opt, char *string) {
break;
case PSQF_ORDER:
if (string[0] && string[1]) {
- pseudo_diag("order type must be a single specifier character.\n");
+ pseudo_error("order type must be a single specifier character.\n");
free(new_trait);
return 0;
}
new_trait->data.ivalue = opt_to_field[(unsigned char) string[0]];
if (!new_trait->data.ivalue) {
- pseudo_diag("Unknown field type: %c\n", string[0]);
+ pseudo_error("Unknown field type: %c\n", string[0]);
}
break;
case PSQF_RESULT:
@@ -454,7 +454,7 @@ plog_trait(int opt, char *string) {
case PSQF_UID:
new_trait->data.ivalue = pseudo_strtoll_wrapper(string, &endptr, 0);
if (*endptr) {
- pseudo_diag("Unexpected garbage after number (%llu): '%s'\n",
+ pseudo_error("Unexpected garbage after number (%llu): '%s'\n",
new_trait->data.ivalue, endptr);
free(new_trait);
return 0;
@@ -485,7 +485,7 @@ plog_trait(int opt, char *string) {
new_trait->data.svalue = strdup(string);
break;
default:
- pseudo_diag("I don't know how I got here. Unknown field type %d.\n",
+ pseudo_error("I don't know how I got here. Unknown field type %d.\n",
new_trait->field);
free(new_trait);
return 0;
@@ -518,7 +518,7 @@ main(int argc, char **argv) {
case 'P':
s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW);
if (!s)
- pseudo_diag("Can't resolve prefix path '%s'\n", optarg);
+ pseudo_error("Can't resolve prefix path '%s'\n", optarg);
pseudo_set_value("PSEUDO_PREFIX", s);
break;
case 'v':
@@ -597,12 +597,12 @@ main(int argc, char **argv) {
pseudo_debug_flags_finalize();
if (optind < argc) {
- pseudo_diag("Error: Extra arguments not associated with any option.\n");
+ pseudo_error("extra arguments not associated with any option.\n");
usage(EXIT_FAILURE);
}
if (query_only && opt_l) {
- pseudo_diag("Error: -l cannot be used with query-only options or flags.\n");
+ pseudo_error("-l cannot be used with query-only options or flags.\n");
bad_args = 1;
}
@@ -611,22 +611,22 @@ main(int argc, char **argv) {
exit(EXIT_FAILURE);
if (!pseudo_get_prefix(argv[0])) {
- pseudo_diag("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n");
+ pseudo_error("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n");
exit(EXIT_FAILURE);
}
if (!pseudo_get_bindir()) {
- pseudo_diag("Can't figure out bindir. Set PSEUDO_BINDIR.\n");
+ pseudo_error("Can't figure out bindir. Set PSEUDO_BINDIR.\n");
exit(EXIT_FAILURE);
}
if (!pseudo_get_libdir()) {
- pseudo_diag("Can't figure out libdir. Set PSEUDO_LIBDIR.\n");
+ pseudo_error("Can't figure out libdir. Set PSEUDO_LIBDIR.\n");
exit(EXIT_FAILURE);
}
if (!pseudo_get_localstatedir()) {
- pseudo_diag("Can't figure out localstatedir. Set PSEUDO_LOCALSTATEDIR.\n");
+ pseudo_error("Can't figure out localstatedir. Set PSEUDO_LOCALSTATEDIR.\n");
exit(EXIT_FAILURE);
}
@@ -636,12 +636,12 @@ main(int argc, char **argv) {
int fields;
fields = format_scan(format);
if (fields == -1) {
- pseudo_diag("couldn't parse format string (%s).\n", format);
+ pseudo_error("couldn't parse format string (%s).\n", format);
return EXIT_FAILURE;
}
if (opt_D) {
if (pdb_delete(traits, fields)) {
- pseudo_diag("errors occurred trying to delete entries.\n");
+ pseudo_error("errors occurred trying to delete entries.\n");
}
} else {
history = pdb_history(traits, fields, opt_U);
@@ -653,7 +653,7 @@ main(int argc, char **argv) {
}
pdb_history_free(history);
} else {
- pseudo_diag("could not retrieve history.\n");
+ pseudo_error("could not retrieve history.\n");
return EXIT_FAILURE;
}
}
@@ -674,12 +674,12 @@ format_one(log_entry *e, char *format) {
char *s;
if (!e || !format) {
- pseudo_diag("invalid log entry or format specifier.\n");
+ pseudo_error("invalid log entry or format specifier.\n");
return 0;
}
real_len = snprintf(fmtbuf, sizeof(fmtbuf), "%.*s", (int) len + 1, format);
if (real_len >= sizeof(fmtbuf) - 1) {
- pseudo_diag("Format string way too long starting at %.10s",
+ pseudo_error("Format string way too long starting at %.10s",
format - 1);
return 0;
}
@@ -690,7 +690,7 @@ format_one(log_entry *e, char *format) {
* parameters -- this doesn't make sense here.
*/
if (strchr(fmtbuf, '*') || strchr(fmtbuf, 'l') || strchr(fmtbuf, 'h')) {
- pseudo_diag("Sorry, you can't use *, h, or l format modifiers.\n");
+ pseudo_error("Sorry, you can't use *, h, or l format modifiers.\n");
return 0;
}
@@ -830,7 +830,7 @@ format_scan(char *format) {
len = strcspn(s, "acdfgGimMoprRsStTuy");
s += len;
if (!*s) {
- pseudo_diag("Unknown format: '%.3s'\n",
+ pseudo_error("Unknown format: '%.3s'\n",
(s - len));
return -1;
}
@@ -865,7 +865,7 @@ format_scan(char *format) {
*/
break;
default:
- pseudo_diag("error: invalid format specifier %c (at %s)\n", *s, s);
+ pseudo_error("invalid format specifier %c (at %s)\n", *s, s);
return -1;
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 10/23] wrappers: Change pseudo_diag() calls to appropriate macros
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (8 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 09/23] pseudolog.c: " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 11/23] pseudo: Change pseudo_diag() name to pseudo_log() Mark Hatle
` (12 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
ports/darwin/pseudo_wrappers.c | 3 +--
ports/linux/guts/fcntl.c | 2 +-
ports/linux/guts/fcntl64.c | 2 +-
ports/linux/guts/getpw.c | 2 +-
ports/linux/guts/openat.c | 3 +--
ports/linux/openat2/guts/openat2.c | 3 +--
ports/linux/xattr/pseudo_wrappers.c | 3 +--
ports/unix/guts/getcwd.c | 6 +++---
ports/unix/guts/linkat.c | 2 +-
ports/unix/guts/nftw_wrapper_base.c | 6 +++---
ports/unix/guts/symlinkat.c | 2 +-
ports/unix/guts/tempnam.c | 2 +-
ports/unix/guts/tmpnam.c | 2 +-
ports/unix/guts/unlinkat.c | 2 +-
pseudo_ipc.c | 2 +-
pseudo_wrappers.c | 2 +-
16 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/ports/darwin/pseudo_wrappers.c b/ports/darwin/pseudo_wrappers.c
index 3f05936..a7a1341 100644
--- a/ports/darwin/pseudo_wrappers.c
+++ b/ports/darwin/pseudo_wrappers.c
@@ -73,9 +73,8 @@ static int
posix_permissions(const acl_header *header, int entries, int *extra, int *mode) {
int acl_seen = 0;
if (le32(header->version) != 2) {
- pseudo_diag("Fatal: ACL support no available for header version %d.\n",
+ pseudo_critical("ACL support no available for header version %d.\n",
le32(header->version));
- return 1;
}
*mode = 0;
*extra = 0;
diff --git a/ports/linux/guts/fcntl.c b/ports/linux/guts/fcntl.c
index ffb50be..d6babb5 100644
--- a/ports/linux/guts/fcntl.c
+++ b/ports/linux/guts/fcntl.c
@@ -89,7 +89,7 @@
break;
#endif
default:
- pseudo_diag("unknown fcntl argument %d, assuming long argument.\n",
+ pseudo_error("unknown fcntl argument %d, assuming long argument.\n",
cmd);
rc = real_fcntl(fd, cmd, arg);
break;
diff --git a/ports/linux/guts/fcntl64.c b/ports/linux/guts/fcntl64.c
index 99de43d..169fc6d 100644
--- a/ports/linux/guts/fcntl64.c
+++ b/ports/linux/guts/fcntl64.c
@@ -89,7 +89,7 @@
break;
#endif
default:
- pseudo_diag("unknown fcntl64 argument %d, assuming long argument.\n",
+ pseudo_error("unknown fcntl64 argument %d, assuming long argument.\n",
cmd);
rc = real_fcntl64(fd, cmd, arg);
break;
diff --git a/ports/linux/guts/getpw.c b/ports/linux/guts/getpw.c
index 5aa0bca..111799e 100644
--- a/ports/linux/guts/getpw.c
+++ b/ports/linux/guts/getpw.c
@@ -12,7 +12,7 @@
static char pwbuf[PSEUDO_PWD_MAX];
struct passwd *pwp;
- pseudo_diag("warning: unsafe getpw() called. hoping buf has at least %d chars.\n",
+ pseudo_warning("unsafe getpw() called. hoping buf has at least %d chars.\n",
PSEUDO_PWD_MAX);
rc = wrap_getpwuid_r(uid, &pwd, pwbuf, PSEUDO_PWD_MAX, &pwp);
/* different error return conventions */
diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c
index 656ac2b..0a44063 100644
--- a/ports/linux/guts/openat.c
+++ b/ports/linux/guts/openat.c
@@ -112,9 +112,8 @@
* stack to stuff that's going to try to drop the lock.
*/
if (pseudo_getlock()) {
- pseudo_diag("PANIC: after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n",
+ pseudo_critical("after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n",
path, rc, errno, save_errno);
- abort();
}
errno = save_errno;
}
diff --git a/ports/linux/openat2/guts/openat2.c b/ports/linux/openat2/guts/openat2.c
index a0acbe7..f1c523e 100644
--- a/ports/linux/openat2/guts/openat2.c
+++ b/ports/linux/openat2/guts/openat2.c
@@ -147,9 +147,8 @@
* stack to stuff that's going to try to drop the lock.
*/
if (pseudo_getlock()) {
- pseudo_diag("PANIC: after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n",
+ pseudo_critical("PANIC: after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n",
pseudo_path, rc, errno, save_errno);
- abort();
}
errno = save_errno;
}
diff --git a/ports/linux/xattr/pseudo_wrappers.c b/ports/linux/xattr/pseudo_wrappers.c
index 0b65920..896c84d 100644
--- a/ports/linux/xattr/pseudo_wrappers.c
+++ b/ports/linux/xattr/pseudo_wrappers.c
@@ -66,9 +66,8 @@ static int
posix_permissions(const acl_header *header, int entries, int *extra, int *mode) {
int acl_seen = 0;
if (le32(header->version) != 2) {
- pseudo_diag("Fatal: ACL support not available for header version %d.\n",
+ pseudo_critical("Fatal: ACL support not available for header version %d.\n",
le32(header->version));
- return -1;
}
*mode = 0;
*extra = 0;
diff --git a/ports/unix/guts/getcwd.c b/ports/unix/guts/getcwd.c
index a5bf2ef..f9d6bfc 100644
--- a/ports/unix/guts/getcwd.c
+++ b/ports/unix/guts/getcwd.c
@@ -11,7 +11,7 @@
pseudo_debug(PDBGF_CLIENT, "wrap_getcwd: %p, %lu\n",
(void *) buf, (unsigned long) size);
if (!pseudo_cwd) {
- pseudo_diag("Asked for CWD, but don't have it!\n");
+ pseudo_error("Asked for CWD, but don't have it!\n");
errno = EACCES;
return NULL;
}
@@ -33,13 +33,13 @@
if (size) {
buf = malloc(size);
} else {
- pseudo_diag("can't figure out CWD: length %ld + 1 - %ld => %ld\n",
+ pseudo_error("can't figure out CWD: length %ld + 1 - %ld => %ld\n",
(unsigned long) pseudo_cwd_len,
(unsigned long) pseudo_chroot_len,
(unsigned long) size);
}
if (!buf) {
- pseudo_diag("couldn't allocate requested CWD buffer - need %ld byes\n",
+ pseudo_error("couldn't allocate requested CWD buffer - need %ld byes\n",
(unsigned long) size);
errno = ENOMEM;
return NULL;
diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c
index 60fbf63..ff707c8 100644
--- a/ports/unix/guts/linkat.c
+++ b/ports/unix/guts/linkat.c
@@ -82,7 +82,7 @@
rc2 = base_lstat(oldpath, &buf);
}
if (rc2 == -1) {
- pseudo_diag("Fatal: Tried to stat '%s' after linking it, but failed: %s.\n",
+ pseudo_error("Fatal: Tried to stat '%s' after linking it, but failed: %s.\n",
oldpath, strerror(errno));
errno = ENOENT;
return rc2;
diff --git a/ports/unix/guts/nftw_wrapper_base.c b/ports/unix/guts/nftw_wrapper_base.c
index 000fa18..b9f761a 100644
--- a/ports/unix/guts/nftw_wrapper_base.c
+++ b/ports/unix/guts/nftw_wrapper_base.c
@@ -68,7 +68,7 @@ static void NFTW_DELETE_FN_NAME() {
NFTW_STORAGE_ARRAY_NAME = NULL;
--NFTW_STORAGE_ARRAY_SIZE;
} else {
- pseudo_diag("%s: Invalid callback storage content, can't find corresponding data", __func__);
+ pseudo_error("%s: Invalid callback storage content, can't find corresponding data", __func__);
}
return;
}
@@ -82,7 +82,7 @@ static void NFTW_DELETE_FN_NAME() {
}
if (found_idx == -1) {
- pseudo_diag("%s: Invalid callback storage content, can't find corresponding data", __func__);
+ pseudo_error("%s: Invalid callback storage content, can't find corresponding data", __func__);
return;
}
@@ -102,7 +102,7 @@ static int NFTW_CALLBACK_NAME(const char* fpath, const struct NFTW_STAT_STRUCT _
struct NFTW_STAT_STRUCT pseudo_sb;
if (!NFTW_FIND_FN_NAME(&saved_details)) {
- pseudo_diag("%s: Could not find corresponding callback!", __func__);
+ pseudo_error("%s: Could not find corresponding callback!", __func__);
return -1;
}
diff --git a/ports/unix/guts/symlinkat.c b/ports/unix/guts/symlinkat.c
index c96ff3e..5673912 100644
--- a/ports/unix/guts/symlinkat.c
+++ b/ports/unix/guts/symlinkat.c
@@ -38,7 +38,7 @@
#endif
if (rc == -1) {
int save_errno = errno;
- pseudo_diag("symlinkat: couldn't stat '%s' even though symlink creation succeeded (%s).\n",
+ pseudo_warning("symlinkat: couldn't stat '%s' even though symlink creation succeeded (%s).\n",
newpath, strerror(errno));
errno = save_errno;
free(roldname);
diff --git a/ports/unix/guts/tempnam.c b/ports/unix/guts/tempnam.c
index 26ae3e1..e2d2c75 100644
--- a/ports/unix/guts/tempnam.c
+++ b/ports/unix/guts/tempnam.c
@@ -11,7 +11,7 @@
/* let gcc know we ignored these on purpose */
(void) template;
(void) pfx;
- pseudo_diag("tempnam() is so ludicrously insecure as to defy implementation.");
+ pseudo_warning("tempnam() is so ludicrously insecure as to defy implementation.");
errno = ENOMEM;
rc = NULL;
diff --git a/ports/unix/guts/tmpnam.c b/ports/unix/guts/tmpnam.c
index 190d260..60b66e0 100644
--- a/ports/unix/guts/tmpnam.c
+++ b/ports/unix/guts/tmpnam.c
@@ -11,7 +11,7 @@
/* let gcc know we're ignoring this */
(void) s;
- pseudo_diag("tmpnam() is so ludicrously insecure as to defy implementation.");
+ pseudo_warning("tmpnam() is so ludicrously insecure as to defy implementation.");
errno = ENOMEM;
rc = NULL;
diff --git a/ports/unix/guts/unlinkat.c b/ports/unix/guts/unlinkat.c
index 7e4f87c..9889b2e 100644
--- a/ports/unix/guts/unlinkat.c
+++ b/ports/unix/guts/unlinkat.c
@@ -23,7 +23,7 @@
* with that flag unless the real AT functions exist, so
* something must have gone horribly wrong....
*/
- pseudo_diag("wrap_unlinkat called with flags (0x%x), path '%s'\n",
+ pseudo_info("wrap_unlinkat called with flags (0x%x), path '%s'\n",
rflags, path ? path : "<nil>");
errno = ENOSYS;
return -1;
diff --git a/pseudo_ipc.c b/pseudo_ipc.c
index 838eba2..e51fe0e 100644
--- a/pseudo_ipc.c
+++ b/pseudo_ipc.c
@@ -165,7 +165,7 @@ pseudo_msg_receive(int fd) {
if (!incoming || header.pathlen >= incoming_pathlen) {
newmsg = pseudo_msg_new(header.pathlen + 128, 0);
if (!newmsg) {
- pseudo_diag("Couldn't allocate header for path of %d bytes.\n",
+ pseudo_error("Couldn't allocate header for path of %d bytes.\n",
(int) header.pathlen);
return 0;
}
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 9ae1200..662c276 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -249,7 +249,7 @@ pseudo_magic() {
static void
pseudo_enosys(const char *func) {
- pseudo_diag("pseudo: ENOSYS for '%s'.\n", func ? func : "<nil>");
+ pseudo_info("pseudo: ENOSYS for '%s'.\n", func ? func : "<nil>");
char * value = pseudo_get_value("PSEUDO_ENOSYS_ABORT");
if (value)
abort();
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 11/23] pseudo: Change pseudo_diag() name to pseudo_log()
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (9 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 10/23] wrappers: " Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 12/23] pseudo_util: Add default log severity values Mark Hatle
` (11 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Implements [YOCTO #12141]
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo.h | 14 +++++++-------
pseudo_util.c | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/pseudo.h b/pseudo.h
index d214ba2..92ae71e 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -34,7 +34,7 @@ extern unsigned long pseudo_util_severity_flags;
extern int pseudo_util_debug_fd;
extern int pseudo_disabled;
extern int pseudo_allow_fsync;
-extern int pseudo_diag(char *, ...) __attribute__ ((format (printf, 1, 2)));
+extern int pseudo_log(char *, ...) __attribute__ ((format (printf, 1, 2)));
extern int pseudo_evlog_internal(char *, ...) __attribute__ ((format (printf, 1, 2)));
#define pseudo_evlog(x, ...) do { \
if (pseudo_util_evlog_flags & (x)) { pseudo_evlog_internal(__VA_ARGS__); } \
@@ -42,27 +42,27 @@ extern int pseudo_evlog_internal(char *, ...) __attribute__ ((format (printf, 1,
extern void pseudo_evlog_dump(void);
#ifndef NDEBUG
#define pseudo_critical(fmt, ...) do { \
- pseudo_diag("CRITICAL: " fmt, ##__VA_ARGS__); \
+ pseudo_log("CRITICAL: " fmt, ##__VA_ARGS__); \
abort(); \
} while (0)
#define pseudo_error(fmt, ...) do { \
- pseudo_diag("ERROR: " fmt, ##__VA_ARGS__); \
+ pseudo_log("ERROR: " fmt, ##__VA_ARGS__); \
} while (0)
#define pseudo_warning(fmt, ...) do { \
if (pseudo_util_severity_flags & SEVERITYF_WARN) { \
- pseudo_diag("WARNING: " fmt, ##__VA_ARGS__); \
+ pseudo_log("WARNING: " fmt, ##__VA_ARGS__); \
} \
} while (0)
#define pseudo_info(fmt, ...) do { \
if (pseudo_util_severity_flags & SEVERITYF_INFO) { \
- pseudo_diag("INFO: " fmt, ##__VA_ARGS__); \
+ pseudo_log("INFO: " fmt, ##__VA_ARGS__); \
} \
} while (0)
#define pseudo_debug(x, ...) do { \
if ((x) & PDBGF_VERBOSE) { \
- if ((pseudo_util_debug_flags & PDBGF_VERBOSE) && (pseudo_util_debug_flags & ((x) & ~PDBGF_VERBOSE))) { pseudo_diag(__VA_ARGS__); } \
+ if ((pseudo_util_debug_flags & PDBGF_VERBOSE) && (pseudo_util_debug_flags & ((x) & ~PDBGF_VERBOSE))) { pseudo_log(__VA_ARGS__); } \
} else { \
- if ((pseudo_util_debug_flags & (x)) || ((x) == 0)) { pseudo_diag(__VA_ARGS__); } \
+ if ((pseudo_util_debug_flags & (x)) || ((x) == 0)) { pseudo_log(__VA_ARGS__); } \
} \
} while (0)
#define pseudo_debug_call(x, fn, ...) do { \
diff --git a/pseudo_util.c b/pseudo_util.c
index dbd979e..893a25b 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -528,7 +528,7 @@ pseudo_debug_clear(char *s) {
}
int
-pseudo_diag(char *fmt, ...) {
+pseudo_log(char *fmt, ...) {
va_list ap;
char debuff[8192];
int len;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 12/23] pseudo_util: Add default log severity values
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (10 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 11/23] pseudo: Change pseudo_diag() name to pseudo_log() Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 10:43 ` [yocto-patches] " Paul Barker
2026-07-03 0:46 ` [pseudo][PATCH 13/23] pseudo_util.c: strchr now returns const char Mark Hatle
` (10 subsequent siblings)
22 siblings, 1 reply; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Dmitry Sakhonchik <frezidok1@gmail.com>
Default values are "show everything". If the user wants to see
only certain categories, they should explicitely set
PSEUDO_SEVERITY env var or use -k option.
Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo.h | 2 ++
pseudo_util.c | 7 ++++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/pseudo.h b/pseudo.h
index 92ae71e..66aa70e 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -130,6 +130,8 @@ extern char *pseudo_version;
#define PSEUDO_PIDFILE "pseudo.pid"
#define PSEUDO_SOCKET "pseudo.socket"
+#define PSEUDO_SEVERITY_DEFAULT "info,warn,error"
+
/* some systems might not have *at(). We like to define operations in
* terms of each other, and for instance, open(...) is the same as
* openat(AT_FDCWD, ...). If no AT_FDCWD is provided, any value that can't
diff --git a/pseudo_util.c b/pseudo_util.c
index 893a25b..4c05394 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -250,10 +250,11 @@ pseudo_init_util(void) {
}
free(env);
env = pseudo_get_value("PSEUDO_SEVERITY");
- if (env) {
- pseudo_severity_set(env);
- pseudo_severity_flags_finalize();
+ if (!env) {
+ env = strdup(PSEUDO_SEVERITY_DEFAULT);
}
+ pseudo_severity_set(env);
+ pseudo_severity_flags_finalize();
free(env);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [yocto-patches] [pseudo][PATCH 12/23] pseudo_util: Add default log severity values
2026-07-03 0:46 ` [pseudo][PATCH 12/23] pseudo_util: Add default log severity values Mark Hatle
@ 2026-07-03 10:43 ` Paul Barker
2026-07-03 12:44 ` Dmitry Sakhonchik
0 siblings, 1 reply; 28+ messages in thread
From: Paul Barker @ 2026-07-03 10:43 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
[-- Attachment #1: Type: text/plain, Size: 1452 bytes --]
On Thu, 2026-07-02 at 19:46 -0500, Mark Hatle wrote:
> From: Dmitry Sakhonchik <frezidok1@gmail.com>
>
> Default values are "show everything". If the user wants to see
> only certain categories, they should explicitely set
> PSEUDO_SEVERITY env var or use -k option.
>
> Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
> Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
> ---
> pseudo.h | 2 ++
> pseudo_util.c | 7 ++++---
> 2 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/pseudo.h b/pseudo.h
> index 92ae71e..66aa70e 100644
> --- a/pseudo.h
> +++ b/pseudo.h
> @@ -130,6 +130,8 @@ extern char *pseudo_version;
> #define PSEUDO_PIDFILE "pseudo.pid"
> #define PSEUDO_SOCKET "pseudo.socket"
>
> +#define PSEUDO_SEVERITY_DEFAULT "info,warn,error"
This default is confusing. pseudo_error() doesn't check
pseudo_util_severity_flags, so errors are always printed.
This also isn't "show everything" as pseudo_debug() messages are not
shown with this default severity level. They are instead controlled by
pseudo_util_debug_flags, and having two separate sets of flags is
another level of confusion to me.
If we're overhauling the logging for v2.0, I think it would be much
better to merge the log/debug handling into one ordered list of severity
levels and control what is printed by specifying the minimum severity
level to output.
Best regards,
--
Paul Barker
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [yocto-patches] [pseudo][PATCH 12/23] pseudo_util: Add default log severity values
2026-07-03 10:43 ` [yocto-patches] " Paul Barker
@ 2026-07-03 12:44 ` Dmitry Sakhonchik
0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Sakhonchik @ 2026-07-03 12:44 UTC (permalink / raw)
To: Paul Barker; +Cc: yocto-patches, richard.purdie
[-- Attachment #1: Type: text/plain, Size: 2751 bytes --]
They are designed like that on purpose.
As far as I know, pseudo_debug was originally created as
a debugging mechanism for pseudo developers,
so it lets you choose "which part of what pseudo is doing right now I want
to look at as deeply as possible"
and often used when something goes wrong and you want to debug it.
On the contrary, pseudo_severity is the new mechanism that allows people to
sort their original regular user's log (make it less verbose).
For example, "I don't care about regular log messages, write something only
if warning or error".
These changes are implementing bug 12141
<https://bugzilla.yoctoproject.org/show_bug.cgi?id=12141> where Seebs
suggested a new separate category.
In my opinion, these two separate mechanisms should not be merged because
they serve different categories
of people and solve different categories of problems.
As for the "errors are always printed", if it's really confusing, I can
remove "error" from default lists
as it doesn't do anything, but I included it because I wanted to explicitly
show that by default we always use these 3 categories.
Thanks for the review!
пт, 3 июл. 2026 г. в 13:43, Paul Barker <paul@pbarker.dev>:
> On Thu, 2026-07-02 at 19:46 -0500, Mark Hatle wrote:
> > From: Dmitry Sakhonchik <frezidok1@gmail.com>
> >
> > Default values are "show everything". If the user wants to see
> > only certain categories, they should explicitely set
> > PSEUDO_SEVERITY env var or use -k option.
> >
> > Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
> > Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
> > ---
> > pseudo.h | 2 ++
> > pseudo_util.c | 7 ++++---
> > 2 files changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/pseudo.h b/pseudo.h
> > index 92ae71e..66aa70e 100644
> > --- a/pseudo.h
> > +++ b/pseudo.h
> > @@ -130,6 +130,8 @@ extern char *pseudo_version;
> > #define PSEUDO_PIDFILE "pseudo.pid"
> > #define PSEUDO_SOCKET "pseudo.socket"
> >
> > +#define PSEUDO_SEVERITY_DEFAULT "info,warn,error"
>
> This default is confusing. pseudo_error() doesn't check
> pseudo_util_severity_flags, so errors are always printed.
>
> This also isn't "show everything" as pseudo_debug() messages are not
> shown with this default severity level. They are instead controlled by
> pseudo_util_debug_flags, and having two separate sets of flags is
> another level of confusion to me.
>
> If we're overhauling the logging for v2.0, I think it would be much
> better to merge the log/debug handling into one ordered list of severity
> levels and control what is printed by specifying the minimum severity
> level to output.
>
> Best regards,
>
> --
> Paul Barker
>
>
[-- Attachment #2: Type: text/html, Size: 3928 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* [pseudo][PATCH 13/23] pseudo_util.c: strchr now returns const char
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (11 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 12/23] pseudo_util: Add default log severity values Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 14/23] test/test-openat2-func.c: Remove unusuaed saved_errno Mark Hatle
` (9 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
Fix compile warning:
pseudo_util.c: In function ‘pseudo_append_elements’:
pseudo_util.c:896:30: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
896 | char *next = strchr(path, '/');
| ^~~~~~
pseudo_util.c:898:30: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
898 | next = strchr(path, '\0');
| ^
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index 4c05394..3eaa9e6 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -893,7 +893,7 @@ pseudo_append_elements(char *newpath, char *root, size_t allocated, char **curre
while (path < (start + elen) && *path) {
size_t this_elen;
int leave_this = 0;
- char *next = strchr(path, '/');
+ const char *next = strchr(path, '/');
if (!next) {
next = strchr(path, '\0');
leave_this = leave_last;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 14/23] test/test-openat2-func.c: Remove unusuaed saved_errno
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (12 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 13/23] pseudo_util.c: strchr now returns const char Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 10:44 ` [yocto-patches] " Paul Barker
2026-07-03 0:46 ` [pseudo][PATCH 15/23] pseudo.h: Avoid accessing unallocated memory Mark Hatle
` (8 subsequent siblings)
22 siblings, 1 reply; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
test/test-openat2-func.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/test/test-openat2-func.c b/test/test-openat2-func.c
index 00c3e12..619a656 100644
--- a/test/test-openat2-func.c
+++ b/test/test-openat2-func.c
@@ -109,7 +109,6 @@ int main(void) {
int dirfd = -1;
int fd = -1;
int rc = 1;
- int saved_errno;
struct open_how how;
char cwd_save[PATH_MAX];
int cwd_saved = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 15/23] pseudo.h: Avoid accessing unallocated memory
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (13 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 14/23] test/test-openat2-func.c: Remove unusuaed saved_errno Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 16/23] pseudo_util: Avoid accidental free calls for without_libpseudo() Mark Hatle
` (7 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
We can call STARTSWITH in cases where the item being searched for is longer
than the string itself. Switch from memcmp to strncmp to avoid accessing
unassigned memory.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-1-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pseudo.h b/pseudo.h
index 66aa70e..ae1fe0d 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -119,7 +119,7 @@ extern char *pseudo_version;
#define PSEUDO_LIBDIR "lib"
#endif
-#define STARTSWITH(x, y) (!memcmp((x), (y), sizeof(y) - 1))
+#define STARTSWITH(x, y) (strncmp(y, x, strlen(y)) == 0)
#ifndef PSEUDO_LOCALSTATEDIR
#define PSEUDO_LOCALSTATEDIR "var/pseudo"
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 16/23] pseudo_util: Avoid accidental free calls for without_libpseudo()
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (14 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 15/23] pseudo.h: Avoid accessing unallocated memory Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 17/23] pseudo_util: Ensure pseudo_setupenvp handles memory consistently Mark Hatle
` (6 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
We need to return list after the strdup otherwise the caller doesn't
know whether to free the return value or not.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-2-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index 3eaa9e6..66afe25 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -346,13 +346,13 @@ without_libpseudo(char *list) {
if (list[0] == '=' || list[0] == PSEUDO_LINKPATH_SEPARATOR[0])
skip_start = 1;
- if ((*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
- return list;
- }
list = strdup(list);
if (!list) {
pseudo_error("Couldn't allocate memory to remove libpseudo from environment.\n");
}
+ if ((*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
+ return list;
+ }
while (list && !(*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
char *start = list + pmatch[0].rm_so;
char *end = list + pmatch[0].rm_eo;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 17/23] pseudo_util: Ensure pseudo_setupenvp handles memory consistently
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (15 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 16/23] pseudo_util: Avoid accidental free calls for without_libpseudo() Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 18/23] pseudo_util: Avoid a memory leak in pseudo_dropenv() Mark Hatle
` (5 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Most of the new environment values added to the new environment array
returned by setupenvp are already freshly allocated memory. Ensure all
the returned values are so the data can be handled consistently and
correctly freed (for a later patch).
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-3-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_util.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index 66afe25..5095e5b 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1242,7 +1242,7 @@ pseudo_setupenvp(char * const *envp) {
}
} else {
/* keep old value */
- new_envp[j++] = ld_library_path;
+ new_envp[j++] = strdup(ld_library_path);
}
if (ld_preload) {
@@ -1273,7 +1273,7 @@ pseudo_setupenvp(char * const *envp) {
for (i = 0; envp && envp[i]; ++i) {
if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) continue;
if (STARTSWITH(envp[i], PRELINK_PATH "=")) continue;
- new_envp[j++] = envp[i];
+ new_envp[j++] = strdup(envp[i]);
}
for (i = 0; pseudo_env[i].key; i++) {
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 18/23] pseudo_util: Avoid a memory leak in pseudo_dropenv()
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (16 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 17/23] pseudo_util: Ensure pseudo_setupenvp handles memory consistently Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 19/23] pseudo_util: Clean up memory handling for setupenvp results Mark Hatle
` (4 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-4-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
pseudo_util.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/pseudo_util.c b/pseudo_util.c
index 5095e5b..10274b8 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1045,6 +1045,7 @@ void pseudo_dropenv() {
} else {
SETENV(PRELINK_LIBRARIES, "", 1);
}
+ free(ld_preload);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 19/23] pseudo_util: Clean up memory handling for setupenvp results
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (17 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 18/23] pseudo_util: Avoid a memory leak in pseudo_dropenv() Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 20/23] exec*: Replace bash workaround to avoid memory corruption Mark Hatle
` (3 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Currently, the environment array allocated by pseudo_setupenvp is never
freed. Fix this (and the copy created by dropenvp).
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-5-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
ports/common/guts/execve.c | 4 +++-
ports/common/guts/posix_spawn.c | 4 +++-
ports/common/guts/posix_spawnp.c | 4 +++-
pseudo.h | 2 +-
pseudo_util.c | 3 ++-
5 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c
index 1144f7c..c2be66e 100644
--- a/ports/common/guts/execve.c
+++ b/ports/common/guts/execve.c
@@ -8,7 +8,7 @@
* wrap_execve(const char *file, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -30,6 +30,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execve(file, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/posix_spawn.c b/ports/common/guts/posix_spawn.c
index e15e68f..5896893 100644
--- a/ports/common/guts/posix_spawn.c
+++ b/ports/common/guts/posix_spawn.c
@@ -7,7 +7,7 @@
* wrap_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -29,6 +29,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawn(pid, path, file_actions, attrp, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/posix_spawnp.c b/ports/common/guts/posix_spawnp.c
index b2e1fc8..f3dc16b 100644
--- a/ports/common/guts/posix_spawnp.c
+++ b/ports/common/guts/posix_spawnp.c
@@ -7,7 +7,7 @@
* wrap_posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -29,6 +29,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawnp(pid, file, file_actions, attrp, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/pseudo.h b/pseudo.h
index ae1fe0d..e1129fa 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -86,7 +86,7 @@ void pseudo_new_pid(void);
#define PSEUDO_MAX_LINK_RECURSION 16
extern char *pseudo_fix_path(const char *, const char *, size_t, size_t, size_t *, int);
extern void pseudo_dropenv(void);
-extern char **pseudo_dropenvp(char * const *);
+extern char **pseudo_dropenvp(char **);
extern void pseudo_setupenv(void);
extern char **pseudo_setupenvp(char * const *);
extern char *pseudo_prefix_path(char *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 10274b8..61d47e4 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1050,7 +1050,7 @@ void pseudo_dropenv() {
}
char **
-pseudo_dropenvp(char * const *envp) {
+pseudo_dropenvp(char **envp) {
char **new_envp;
int i, j;
@@ -1081,6 +1081,7 @@ pseudo_dropenvp(char * const *envp) {
}
}
new_envp[j++] = NULL;
+ free(envp);
return new_envp;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 20/23] exec*: Replace bash workaround to avoid memory corruption
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (18 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 19/23] pseudo_util: Clean up memory handling for setupenvp results Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 21/23] pseudo_util: Correctly free memory allocated by pseudo_setupenvp Mark Hatle
` (2 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Bash intercepts getenv/setenv/unsetenv and does magic with it internally.
The data pointed to by environ may not be allocated by glibc but by bash
and the glibc env functions have their own memory handling outside of malloc.
Unfortuantely bash doesn't keep environ and the result of setenv/getenv/unsetenv
in sync either. This means the current workaround badly corrupts memory and it
is just luck we're not breaking more often than the occasional opkg-build segfaults
we've been seeing.
Fixing this is tricky, the best we can probably do is to read through environ and
create our own copy of the it, modifying it how we need to keep the pseudo variables
correct.
We do already have a function which can copy and modify the environment, we can
therefore swap some setupenv calls for setupenvp and switch out environ around
the exec calls.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-6-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
ports/common/guts/execv.c | 19 ++++++++++++++-----
ports/common/guts/execvp.c | 15 ++++++++++++---
ports/unix/guts/popen.c | 16 +++++++++++++---
ports/unix/guts/system.c | 16 +++++++++++++---
pseudo_client.h | 3 ---
pseudo_util.c | 12 +++---------
pseudo_wrappers.c | 6 ------
7 files changed, 55 insertions(+), 32 deletions(-)
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index 7819911..eb328ed 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -8,6 +8,8 @@
* wrap_execv(const char *file, char *const *argv) {
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
+
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -19,17 +21,24 @@
pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
}
- pseudo_setupenv();
- if (pseudo_has_unload(NULL)) {
- /* and here we attach */
- pseudo_dropenv();
- }
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
+
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
*/
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execv(file, argv);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c
index acc9fdc..177e4ee 100644
--- a/ports/common/guts/execvp.c
+++ b/ports/common/guts/execvp.c
@@ -8,6 +8,7 @@
* wrap_execvp(const char *file, char *const *argv) {
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
@@ -20,9 +21,14 @@
pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
}
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
@@ -30,6 +36,9 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execvp(file, argv);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/unix/guts/popen.c b/ports/unix/guts/popen.c
index d19ec7e..1d48d04 100644
--- a/ports/unix/guts/popen.c
+++ b/ports/unix/guts/popen.c
@@ -7,15 +7,25 @@
* FILE *popen(const char *command, const char *mode)
* FILE *rc = NULL;
*/
+ char **new_environ, **orig_environ;
+
/* on at least some systems, popen() calls fork and exec
* in ways that avoid our usual enforcement of the environment.
*/
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
rc = real_popen(command, mode);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/unix/guts/system.c b/ports/unix/guts/system.c
index 1214314..4b374ec 100644
--- a/ports/unix/guts/system.c
+++ b/ports/unix/guts/system.c
@@ -7,15 +7,25 @@
* int system(const char *command)
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
+
if (!command)
return 1;
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
rc = real_system(command);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/pseudo_client.h b/pseudo_client.h
index a013f88..43bbc0a 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -52,9 +52,6 @@ extern FILE *pseudo_grp;
/* pseudo_wrappers will try to initialize these */
extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf);
-extern int (*pseudo_real_unsetenv)(const char *);
-extern char * (*pseudo_real_getenv)(const char *);
-extern int (*pseudo_real_setenv)(const char *, const char *, int);
extern int (*pseudo_real_fork)(void);
extern int (*pseudo_real_execv)(const char *, char * const *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 61d47e4..13c974f 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -73,15 +73,9 @@ typedef struct {
char *data;
} pseudo_evlog_entry;
-/* so bash overrides getenv/unsetenv/etcetera, preventing them from
- * actually modifying environ, so we have pseudo_wrappers try to dlsym
- * the right values. This could fail, in which case we'd get null
- * pointers, and we'll just call whatever the linker gives us and
- * hope for the best.
- */
-#define SETENV(x, y, z) (pseudo_real_setenv ? pseudo_real_setenv : setenv)(x, y, z)
-#define GETENV(x) (pseudo_real_getenv ? pseudo_real_getenv : getenv)(x)
-#define UNSETENV(x) (pseudo_real_unsetenv ? pseudo_real_unsetenv : unsetenv)(x)
+#define SETENV(x, y, z) setenv(x, y, z)
+#define GETENV(x) getenv(x)
+#define UNSETENV(x) unsetenv(x)
#define PSEUDO_EVLOG_ENTRIES 250
#define PSEUDO_EVLOG_LENGTH 256
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 662c276..6cd8e5d 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -173,12 +173,6 @@ pseudo_init_wrappers(void) {
pseudo_real_fsetxattr = real_fsetxattr;
#endif
pseudo_real_lstat = base_lstat;
- /* bash has its own local copies of these which it uses
- * instead of ours...
- */
- pseudo_real_unsetenv = dlsym(RTLD_NEXT, "unsetenv");
- pseudo_real_getenv = dlsym(RTLD_NEXT, "getenv");
- pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv");
/* and these are used so the client's server spawn can bypass
* wrappers.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 21/23] pseudo_util: Correctly free memory allocated by pseudo_setupenvp
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (19 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 20/23] exec*: Replace bash workaround to avoid memory corruption Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 22/23] test-bash-exec-env: Add bash env test case Mark Hatle
2026-07-03 0:46 ` [pseudo][PATCH 23/23] test: various: Move to makefile compilation Mark Hatle
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Add a function to properly clean up the environment array memory after use.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Message-ID: <20260701131336.3578279-7-richard.purdie@linuxfoundation.org>
Signed-off-by: Mark Hatle <mark.hatle@kernel.crashing.org>
---
ports/common/guts/execv.c | 2 +-
ports/common/guts/execve.c | 2 +-
ports/common/guts/execvp.c | 2 +-
ports/common/guts/posix_spawn.c | 2 +-
ports/common/guts/posix_spawnp.c | 2 +-
ports/unix/guts/popen.c | 2 +-
ports/unix/guts/system.c | 2 +-
pseudo.h | 1 +
pseudo_util.c | 11 +++++++++++
9 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index eb328ed..d4031b3 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -37,7 +37,7 @@
rc = real_execv(file, argv);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c
index c2be66e..de2f1d4 100644
--- a/ports/common/guts/execve.c
+++ b/ports/common/guts/execve.c
@@ -30,7 +30,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execve(file, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c
index 177e4ee..ffc94be 100644
--- a/ports/common/guts/execvp.c
+++ b/ports/common/guts/execvp.c
@@ -37,7 +37,7 @@
rc = real_execvp(file, argv);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/posix_spawn.c b/ports/common/guts/posix_spawn.c
index 5896893..46ebb0e 100644
--- a/ports/common/guts/posix_spawn.c
+++ b/ports/common/guts/posix_spawn.c
@@ -29,7 +29,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawn(pid, path, file_actions, attrp, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/posix_spawnp.c b/ports/common/guts/posix_spawnp.c
index f3dc16b..194bcb3 100644
--- a/ports/common/guts/posix_spawnp.c
+++ b/ports/common/guts/posix_spawnp.c
@@ -29,7 +29,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawnp(pid, file, file_actions, attrp, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/unix/guts/popen.c b/ports/unix/guts/popen.c
index 1d48d04..1ce083d 100644
--- a/ports/unix/guts/popen.c
+++ b/ports/unix/guts/popen.c
@@ -24,7 +24,7 @@
rc = real_popen(command, mode);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/unix/guts/system.c b/ports/unix/guts/system.c
index 4b374ec..12a3aff 100644
--- a/ports/unix/guts/system.c
+++ b/ports/unix/guts/system.c
@@ -24,7 +24,7 @@
rc = real_system(command);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/pseudo.h b/pseudo.h
index e1129fa..ecb1615 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -89,6 +89,7 @@ extern void pseudo_dropenv(void);
extern char **pseudo_dropenvp(char **);
extern void pseudo_setupenv(void);
extern char **pseudo_setupenvp(char * const *);
+extern void pseudo_free_envp(char **envp);
extern char *pseudo_prefix_path(char *);
extern char *pseudo_bindir_path(char *);
extern char *pseudo_libdir_path(char *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 13c974f..3a6c05c 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1295,6 +1295,17 @@ pseudo_setupenvp(char * const *envp) {
return new_envp;
}
+/* Free data allocated by pseudo_setupenvp() */
+void
+pseudo_free_envp(char **envp) {
+ int i;
+
+ for (i = 0; envp && envp[i]; ++i) {
+ free(envp[i]);
+ }
+ free(envp);
+}
+
/* Append the file value to the prefix value. */
char *
pseudo_append_path(const char * prefix, size_t prefix_len, char *file) {
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [pseudo][PATCH 22/23] test-bash-exec-env: Add bash env test case
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (20 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 21/23] pseudo_util: Correctly free memory allocated by pseudo_setupenvp Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
2026-07-03 11:13 ` [yocto-patches] " Paul Barker
2026-07-03 0:46 ` [pseudo][PATCH 23/23] test: various: Move to makefile compilation Mark Hatle
22 siblings, 1 reply; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Mark Hatle <mark.hatle@amd.com>
Add a test reproducing the bash/pseudo environment conflict
(https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078) where pseudo's
setenv workaround corrupted memory when pseudo ran under bash.
The helper binary exports its own getenv/setenv/unsetenv (as bash does),
maintaining a private variable table separate from environ. It strips the
derived PSEUDO_* variables and forks children, mirroring the opkg-build
pipeline that triggered the production crash. pseudo's fork wrapper runs
pseudo_setupenv() in each child, which re-adds those variables; the child
then checks whether they leaked back into the real environ:
Unfixed pseudo calls glibc's setenv via dlsym(RTLD_NEXT), writing the
variables straight into environ and desyncing it from bash's table.
Fixed pseudo calls the process's own setenv, leaving environ untouched.
The check is deterministic, so the test fails when the fixes are reverted
and passes when they are present. MALLOC_CHECK_=3 is kept as a secondary
safety net.
AI-Generated: Test constructed with GitHub Copilot (Claude Opus 4.8)
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
test/test-bash-exec-env.c | 667 +++++++++++++++++++++++++++++++++++++
test/test-bash-exec-env.sh | 34 ++
2 files changed, 701 insertions(+)
create mode 100644 test/test-bash-exec-env.c
create mode 100755 test/test-bash-exec-env.sh
diff --git a/test/test-bash-exec-env.c b/test/test-bash-exec-env.c
new file mode 100644
index 0000000..68ed42a
--- /dev/null
+++ b/test/test-bash-exec-env.c
@@ -0,0 +1,667 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * test-bash-exec-env.c
+ *
+ * Reproducer for https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078
+ *
+ * What this binary simulates
+ * --------------------------
+ * bash exports getenv(), setenv(), and unsetenv() as dynamic symbols.
+ * Because the main executable appears first in the dynamic-linker search
+ * order, every library loaded into the process (including libpseudo.so)
+ * resolves calls to those names to bash's own implementations.
+ *
+ * bash maintains a private variable hash table that is separate from the
+ * C-library 'environ' array. bash's setenv/getenv operate on this table;
+ * 'environ' is only rebuilt lazily by maybe_make_export_env().
+ *
+ * The old pseudo workaround (commit 80c6334a) used
+ * pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv")
+ * to bypass bash's override and call glibc's setenv directly.
+ * dlsym(RTLD_NEXT, …) from within an LD_PRELOAD library searches the
+ * shared-library chain *after* the LD_PRELOAD library, so it finds
+ * glibc's implementation — it does NOT find the main executable's
+ * (bash's) version.
+ *
+ * glibc's setenv modifies 'environ' directly, allocating a new heap
+ * block (block A) for the updated "LD_PRELOAD=libpseudo.so:…" entry.
+ * bash's internal variable table is NOT updated.
+ *
+ * When bash later calls maybe_make_export_env() (before exec-ing each
+ * pipeline stage), it calls strvec_flush() which frees every entry in
+ * the current 'environ' array — including block A — and rebuilds from
+ * the internal table (which still has the original LD_PRELOAD without
+ * libpseudo.so).
+ *
+ * The freed block A therefore remains live in the allocator's free list
+ * while pseudo's exec wrapper (pseudo_setupenvp) iterates 'environ'.
+ * Whether the access to freed memory produces a crash depends on whether
+ * the allocator happens to reuse that block and overwrite its contents
+ * before pseudo reads from it.
+ *
+ * This binary faithfully reproduces the bash conditions:
+ *
+ * 1. It exports its own setenv/getenv/unsetenv (like bash) that
+ * maintain a private internal table, separate from 'environ'.
+ * The regular setenv/getenv calls in pseudo therefore go to
+ * *our* functions; only dlsym(RTLD_NEXT, …) from inside
+ * libpseudo.so reaches glibc's implementations.
+ *
+ * 2. It implements strvec_flush() and maybe_make_export_env() that
+ * rebuild 'environ' from the internal table, freeing the old
+ * array (which contains glibc-setenv-allocated blocks).
+ *
+ * 3. It runs the pipeline pattern from opkg-build: fork N children
+ * in parallel (simulating find|sort|tar|gzip|ar), each child
+ * calling maybe_make_export_env() then execve(). This is the
+ * exact sequence that triggered the production crash.
+ *
+ * Detection
+ * ---------
+ * The bug is detected deterministically rather than by relying on the
+ * probabilistic heap corruption it causes. main() strips the derived
+ * PSEUDO_* variables (PSEUDO_BINDIR, PSEUDO_LIBDIR, …) from both the
+ * internal table and the real 'environ'. pseudo's fork wrapper then
+ * runs pseudo_setupenv() in every child, which re-adds them:
+ *
+ * Unfixed pseudo calls glibc's setenv (via dlsym(RTLD_NEXT, …)),
+ * which writes the variables straight back into the real 'environ'
+ * array — the very environ/allocator desync that corrupts bash's
+ * heap in production. The child observes the reappearing PSEUDO_*
+ * entries and reports the bug.
+ *
+ * Fixed pseudo calls the process's own setenv (ours/bash's), which
+ * updates only the internal table, and the exec/system/popen
+ * wrappers operate on a private pseudo_setupenvp() copy and restore
+ * environ afterwards. The real 'environ' is never mutated, so the
+ * PSEUDO_* variables do not reappear and the child exits cleanly.
+ *
+ * See pseudo_mutated_environ() below for the check. MALLOC_CHECK_=3 is
+ * still set by the shell wrapper as a secondary safety net so that any
+ * residual heap corruption also aborts the run.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* ------------------------------------------------------------------ */
+/* Internal variable table — analogous to bash's variable hash table. */
+/* setenv/getenv/unsetenv operate on this table; 'environ' is rebuilt */
+/* on demand by maybe_make_export_env(). */
+/* ------------------------------------------------------------------ */
+
+static char **internal_table = NULL; /* "KEY=VALUE" strings */
+static int internal_count = 0;
+static int internal_cap = 0;
+
+static int table_find(const char *name, size_t nlen)
+{
+ for (int i = 0; i < internal_count; i++) {
+ if (strncmp(internal_table[i], name, nlen) == 0 &&
+ internal_table[i][nlen] == '=')
+ return i;
+ }
+ return -1;
+}
+
+/* ------------------------------------------------------------------ */
+/* Exported env functions — these override glibc's versions for code */
+/* that resolves symbols via the normal dynamic-linker search order */
+/* (i.e., callers inside bash/this binary itself). */
+/* */
+/* dlsym(RTLD_NEXT, "setenv") from an LD_PRELOAD library searches */
+/* *after* the LD_PRELOAD library, finding glibc's implementation — */
+/* NOT these functions. That is the exact asymmetry that pseudo's old */
+/* workaround relied on and that caused the bug. */
+/* */
+/* The defensive NULL checks below intentionally mirror bash's own */
+/* env functions. glibc declares setenv/getenv/unsetenv with the */
+/* 'nonnull' attribute, so comparing the parameters to NULL trips */
+/* -Wnonnull-compare; suppress it for this block since keeping the */
+/* guards is deliberate. */
+/* ------------------------------------------------------------------ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+
+int setenv(const char *name, const char *value, int overwrite)
+{
+ if (!name || !value || strchr(name, '=')) { errno = EINVAL; return -1; }
+ size_t nlen = strlen(name);
+ size_t vlen = strlen(value);
+
+ /* Before main() initialises internal_table, update environ directly. */
+ if (!internal_table) {
+ /* Find and replace existing entry, or append if not found. */
+ if (environ) {
+ for (int i = 0; environ[i]; i++) {
+ if (strncmp(environ[i], name, nlen) == 0 &&
+ environ[i][nlen] == '=') {
+ if (!overwrite) return 0;
+ char *e = malloc(nlen + 1 + vlen + 1);
+ if (!e) return -1;
+ memcpy(e, name, nlen); e[nlen] = '=';
+ memcpy(e + nlen + 1, value, vlen + 1);
+ free(environ[i]); environ[i] = e;
+ return 0;
+ }
+ }
+ }
+ /* Entry not found: can't resize kernel-provided environ safely;
+ * just ignore (the entry will be added when main() starts). */
+ return 0;
+ }
+
+ int idx = table_find(name, nlen);
+ if (idx >= 0) {
+ if (!overwrite) return 0;
+ free(internal_table[idx]);
+ internal_table[idx] = NULL;
+ } else {
+ /* Grow table if needed (keep a NULL sentinel). */
+ if (internal_count + 1 >= internal_cap) {
+ internal_cap = (internal_cap < 8) ? 16 : internal_cap * 2;
+ char **t = realloc(internal_table,
+ (size_t)internal_cap * sizeof(char *));
+ if (!t) return -1;
+ internal_table = t;
+ }
+ idx = internal_count++;
+ internal_table[internal_count] = NULL; /* sentinel */
+ }
+
+ char *entry = malloc(nlen + 1 + vlen + 1);
+ if (!entry) return -1;
+ memcpy(entry, name, nlen);
+ entry[nlen] = '=';
+ memcpy(entry + nlen + 1, value, vlen + 1);
+ internal_table[idx] = entry;
+ return 0;
+}
+
+char *getenv(const char *name)
+{
+ if (!name) return NULL;
+ size_t nlen = strlen(name);
+ /*
+ * Before main() initialises internal_table, fall back to searching
+ * 'environ' directly. This is needed because pseudo's library
+ * constructor (which runs before main()) calls getenv() to read
+ * PSEUDO_PREFIX and similar variables.
+ */
+ if (!internal_table) {
+ for (int i = 0; environ && environ[i]; i++) {
+ if (strncmp(environ[i], name, nlen) == 0 &&
+ environ[i][nlen] == '=')
+ return environ[i] + nlen + 1;
+ }
+ return NULL;
+ }
+ int idx = table_find(name, nlen);
+ if (idx < 0) return NULL;
+ return internal_table[idx] + nlen + 1;
+}
+
+int unsetenv(const char *name)
+{
+ if (!name || !*name || strchr(name, '=')) { errno = EINVAL; return -1; }
+ size_t nlen = strlen(name);
+ /* Before internal_table is initialised, remove from environ directly. */
+ if (!internal_table) {
+ if (environ) {
+ for (int i = 0; environ[i]; i++) {
+ if (strncmp(environ[i], name, nlen) == 0 &&
+ environ[i][nlen] == '=') {
+ free(environ[i]);
+ int j = i;
+ while (environ[j]) { environ[j] = environ[j+1]; j++; }
+ break;
+ }
+ }
+ }
+ return 0;
+ }
+ int idx = table_find(name, nlen);
+ if (idx < 0) return 0;
+ free(internal_table[idx]);
+ memmove(&internal_table[idx], &internal_table[idx + 1],
+ (size_t)(internal_count - idx) * sizeof(char *));
+ internal_count--;
+ return 0;
+}
+
+#pragma GCC diagnostic pop
+
+/* ------------------------------------------------------------------ */
+/* strip_asan_from_preload — remove any libasan*.so entry from an */
+/* LD_PRELOAD value string (colon-separated list). */
+/* */
+/* The ASAN library must be first in LD_PRELOAD so that ASAN properly */
+/* intercepts malloc/free from all shared libraries (including */
+/* libpseudo.so). But the pseudo server-spawn grandchild must NOT */
+/* inherit it: the server is not ASAN-compiled and loading the ASAN */
+/* runtime into an uninstrumented binary causes SQLite lock failures. */
+/* */
+/* By stripping libasan from the rebuilt 'environ' (produced by */
+/* maybe_make_export_env), the server inherits clean LD_PRELOAD while */
+/* ASAN detection in the direct child (fork of our binary) remains */
+/* active — ASAN is compiled into the binary and its hooks are already */
+/* live from process startup. */
+/* ------------------------------------------------------------------ */
+static char *strip_asan_from_preload(const char *preload)
+{
+ if (!preload) return NULL;
+ char *buf = strdup(preload);
+ if (!buf) return NULL;
+
+ char *out = buf;
+ const char *in = preload;
+ while (*in) {
+ const char *sep = strchr(in, ':');
+ size_t len = sep ? (size_t)(sep - in) : strlen(in);
+
+ /* skip any entry that contains "libasan" */
+ int skip = 0;
+ for (size_t k = 0; k + 6 <= len; k++) {
+ if (strncmp(in + k, "libasan", 7) == 0) { skip = 1; break; }
+ }
+
+ if (!skip) {
+ memcpy(out, in, len);
+ out += len;
+ if (sep) *out++ = ':';
+ }
+
+ in += len;
+ if (*in == ':') in++;
+ }
+ /* trim a trailing colon */
+ if (out > buf && *(out - 1) == ':') out--;
+ *out = '\0';
+ return buf;
+}
+
+/* ------------------------------------------------------------------ */
+/* strvec_flush — free every string in v[] then free v itself. */
+/* Equivalent to bash's strvec_flush() in lib/sh/stringvec.c. */
+/* ------------------------------------------------------------------ */
+static void strvec_flush(char **v)
+{
+ if (!v) return;
+ for (int i = 0; v[i]; i++)
+ free(v[i]);
+ free(v);
+}
+
+/* ------------------------------------------------------------------ */
+/* maybe_make_export_env — rebuild 'environ' from the internal table. */
+/* */
+/* This is the function that triggers the use-after-free: */
+/* */
+/* 1. pseudo's fork wrapper called glibc's setenv (via */
+/* dlsym(RTLD_NEXT)) which allocated block A and stored it in */
+/* environ[LD_PRELOAD_idx]. */
+/* */
+/* 2. strvec_flush(old_environ) frees block A. */
+/* */
+/* 3. environ is updated to point to the freshly built array */
+/* (built from internal_table, which has the original LD_PRELOAD */
+/* without libpseudo.so). */
+/* */
+/* 4. When the exec wrapper runs pseudo_setupenvp(environ), the */
+/* allocator may have already reused block A, causing the freed */
+/* memory to be read with stale or garbage content. */
+/* ------------------------------------------------------------------ */
+static void maybe_make_export_env(void)
+{
+ char **old = environ;
+
+ /* Build fresh copy from internal_table. */
+ char **new_env = malloc((size_t)(internal_count + 1) * sizeof(char *));
+ if (!new_env) return;
+
+ for (int i = 0; i < internal_count; i++) {
+ new_env[i] = strdup(internal_table[i]);
+ if (!new_env[i]) {
+ for (int j = 0; j < i; j++) free(new_env[j]);
+ free(new_env);
+ return;
+ }
+ }
+ new_env[internal_count] = NULL;
+
+ /* Strip the ASAN runtime library from LD_PRELOAD in BOTH the rebuilt
+ * environ AND internal_table so that the pseudo server-spawn grandchild
+ * does not inherit it (via pseudo_setupenv reading internal_table).
+ *
+ * ASAN detection in the current process is unaffected: libasan.so is
+ * already mapped in the process address space (loaded at startup via the
+ * original LD_PRELOAD) and its malloc/free interception is active at the
+ * GOT/PLT level for all shared libraries including libpseudo.so.
+ * Removing it from environ/internal_table only affects exec'd children. */
+ const char *ldp = "LD_PRELOAD=";
+ size_t ldp_len = strlen(ldp);
+ for (int i = 0; i < internal_count; i++) {
+ if (strncmp(new_env[i], ldp, ldp_len) == 0) {
+ char *stripped = strip_asan_from_preload(new_env[i] + ldp_len);
+ if (stripped) {
+ char *new_entry = malloc(ldp_len + strlen(stripped) + 1);
+ if (new_entry) {
+ memcpy(new_entry, ldp, ldp_len);
+ strcpy(new_entry + ldp_len, stripped);
+ free(new_env[i]);
+ new_env[i] = new_entry;
+ }
+ free(stripped);
+ }
+ break;
+ }
+ }
+ /* Also strip from internal_table so pseudo_setupenv() doesn't
+ * re-inject libasan into environ via SETENV(). */
+ for (int i = 0; i < internal_count; i++) {
+ if (strncmp(internal_table[i], ldp, ldp_len) == 0) {
+ char *stripped = strip_asan_from_preload(internal_table[i] + ldp_len);
+ if (stripped) {
+ char *new_entry = malloc(ldp_len + strlen(stripped) + 1);
+ if (new_entry) {
+ memcpy(new_entry, ldp, ldp_len);
+ strcpy(new_entry + ldp_len, stripped);
+ free(internal_table[i]);
+ internal_table[i] = new_entry;
+ }
+ free(stripped);
+ }
+ break;
+ }
+ }
+
+ /*
+ * Free the old environ. This releases every entry including any
+ * block that glibc's setenv (called by pseudo_setupenv inside the
+ * fork wrapper) had allocated. After this, 'environ' briefly
+ * points to freed memory until the assignment below.
+ */
+ strvec_flush(old);
+
+ environ = new_env;
+}
+
+/* ------------------------------------------------------------------ */
+/* run_pipeline_iteration */
+/* */
+/* Simulate one opkg-build pipeline: */
+/* ( cd CTRL && find . | sort > list ) */
+/* ( cd PKG && find . | sort > list ) */
+/* ( cd PKG && tar … | gzip > data.tar.gz ) */
+/* ( cd CTRL && tar … | gzip > ctrl.tar.gz ) */
+/* ( cd TMP && ar … ) */
+/* */
+/* Each child simulates one pipeline stage: */
+/* fork → [pseudo fork wrapper runs pseudo_setupenv() in the child] */
+/* child: check whether pseudo mutated the real environ (bug), then */
+/* maybe_make_export_env() and execve("/bin/true") */
+/* ------------------------------------------------------------------ */
+#define PIPELINE_STAGES 5 /* find, sort, tar, gzip, ar */
+
+/* Distinct exit code a child uses to report that pseudo mutated the
+ * real 'environ' array (i.e. the unfixed glibc-setenv code path ran). */
+#define BUG_ENV_MUTATED 42
+
+/* ------------------------------------------------------------------ */
+/* pseudo_mutated_environ — deterministic detector for the bug fixed */
+/* by commits 9c6b4c1..5abd42c. */
+/* */
+/* pseudo's fork wrapper runs pseudo_setupenv() in every child before */
+/* fork() returns. pseudo_setupenv() re-adds the PSEUDO_* variables */
+/* (PSEUDO_BINDIR, PSEUDO_LIBDIR, …) that main() stripped from the */
+/* environment: */
+/* */
+/* Unfixed pseudo: SETENV -> pseudo_real_setenv (dlsym RTLD_NEXT) -> */
+/* glibc setenv, which writes directly into the real 'environ' */
+/* array. The stripped PSEUDO_* vars therefore REAPPEAR in the */
+/* real environ — exactly the environ/allocator desync that */
+/* corrupts bash's heap in production. */
+/* */
+/* Fixed pseudo: SETENV -> setenv -> our (bash's) setenv, which only */
+/* updates internal_table; the exec/system/popen wrappers build a */
+/* private copy with pseudo_setupenvp() and restore environ. The */
+/* real 'environ' is left untouched, so the stripped PSEUDO_* vars */
+/* do NOT reappear there. */
+/* */
+/* Returns 1 if a stripped PSEUDO_* var was found back in the real */
+/* environ (buggy code path), 0 otherwise. Must be called BEFORE */
+/* maybe_make_export_env(), which would otherwise rebuild environ from */
+/* internal_table and discard the injected entries. */
+/* ------------------------------------------------------------------ */
+static int pseudo_mutated_environ(void)
+{
+ for (int i = 0; environ && environ[i]; i++) {
+ if (strncmp(environ[i], "PSEUDO_BINDIR=", 14) == 0 ||
+ strncmp(environ[i], "PSEUDO_LIBDIR=", 14) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int run_pipeline_iteration(void)
+{
+ pid_t pids[PIPELINE_STAGES];
+ char *const args[] = { "/bin/true", NULL };
+
+ /*
+ * Fork all pipeline stages before waiting for any of them, just
+ * as bash does for a pipeline. pseudo's fork wrapper runs
+ * pseudo_setupenv() in each child before fork() returns.
+ */
+ for (int s = 0; s < PIPELINE_STAGES; s++) {
+ pid_t pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+ if (pid == 0) {
+ /*
+ * Child: pseudo's fork wrapper has already run
+ * pseudo_setupenv() at this point. Deterministically
+ * detect whether it mutated the real environ (the bug)
+ * before doing anything that would rebuild environ.
+ */
+ if (pseudo_mutated_environ())
+ _exit(BUG_ENV_MUTATED);
+ /*
+ * Otherwise behave like bash: rebuild environ from the
+ * internal table and exec the pipeline stage.
+ */
+ maybe_make_export_env();
+ execve("/bin/true", args, environ);
+ _exit(127);
+ }
+ pids[s] = pid;
+ }
+
+ /* Wait for all pipeline children. */
+ for (int s = 0; s < PIPELINE_STAGES; s++) {
+ int status;
+ if (waitpid(pids[s], &status, 0) < 0) {
+ perror("waitpid");
+ return -1;
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == BUG_ENV_MUTATED) {
+ fprintf(stderr,
+ "BUG: pseudo mutated the real environ in pipeline stage %d "
+ "(pseudo_setupenv used glibc setenv via dlsym instead of the "
+ "process's own setenv)\n", s);
+ return -1;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "pipeline stage %d failed: status=%d\n",
+ s, status);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int main(void)
+{
+ /* Initialise internal_table from the process's current environ. */
+ int count = 0;
+ while (environ[count]) count++;
+
+ internal_cap = count + 32;
+ internal_table = malloc((size_t)internal_cap * sizeof(char *));
+ if (!internal_table) { perror("malloc"); return 1; }
+
+ for (int i = 0; i < count; i++) {
+ internal_table[i] = strdup(environ[i]);
+ if (!internal_table[i]) { perror("strdup"); return 1; }
+ }
+ internal_table[count] = NULL;
+ internal_count = count;
+
+ /*
+ * Replace environ with a heap-allocated copy before any call to
+ * maybe_make_export_env(). The initial environ supplied by the
+ * kernel exec is in static memory, not the heap; calling free()
+ * on those strings (as strvec_flush does) would crash immediately.
+ * bash avoids this by building its own heap-allocated export_env
+ * during shell initialisation; we replicate that here.
+ */
+ {
+ char **heap_env = malloc((size_t)(count + 1) * sizeof(char *));
+ if (!heap_env) { perror("malloc"); return 1; }
+ for (int i = 0; i < count; i++) {
+ heap_env[i] = strdup(internal_table[i]);
+ if (!heap_env[i]) { perror("strdup"); return 1; }
+ }
+ heap_env[count] = NULL;
+ environ = heap_env; /* now environ is entirely heap-managed */
+ }
+
+ /*
+ * Run 20 pipeline iterations. With the unfixed pseudo code and
+ * MALLOC_CHECK_=3, the heap corruption introduced by pseudo_setupenv
+ * (glibc setenv) followed by strvec_flush causes an abort within
+ * the first few iterations on affected platforms.
+ */
+
+ /*
+ * Strip the ASAN runtime library from LD_PRELOAD and strip derived
+ * PSEUDO_* vars (PSEUDO_BINDIR, PSEUDO_LIBDIR, etc.) from both
+ * internal_table and heap environ BEFORE any pseudo-intercepted call.
+ *
+ * Reason for stripping ASAN from LD_PRELOAD:
+ * The pseudo server-spawn grandchild is not ASAN-compiled; loading the
+ * ASAN runtime into an uninstrumented binary causes SQLite lock failures.
+ *
+ * Reason for stripping derived PSEUDO_* vars:
+ * When the test runs inside the pseudo test framework, the outer pseudo's
+ * exec wrapper pre-populates all PSEUDO_* vars (PSEUDO_BINDIR etc.) in
+ * the binary's initial environ via pseudo_setupenvp(). If these are
+ * already present, pseudo_setupenv() treats them as existing (overwrite=0)
+ * and makes no change — no __add_to_environ() call, no heap-corruption
+ * opportunity, MALLOC_CHECK_=3 detects nothing.
+ * By stripping them here we force pseudo_setupenv() (in the fork wrapper
+ * of every child) to ADD them as NEW environ entries. The unfixed code
+ * (glibc setenv via dlsym RTLD_NEXT) calls __add_to_environ() which
+ * calls realloc(environ_array). strvec_flush() later frees that
+ * allocation, and MALLOC_CHECK_=3 aborts the server-spawn grandchild.
+ * The fixed code calls our binary's setenv() which updates internal_table
+ * only — no __add_to_environ(), no realloc, no corruption.
+ *
+ * We keep PSEUDO_PREFIX and PSEUDO_LOCALSTATEDIR so that pseudo can find
+ * the server binary and socket directory.
+ */
+ {
+ const char *ldp = "LD_PRELOAD=";
+ size_t ldp_len = strlen(ldp);
+
+ /* is_kept: return 1 if the env entry should NOT be stripped.
+ * Keep non-PSEUDO, non-LD_PRELOAD, PSEUDO_PREFIX, PSEUDO_LOCALSTATEDIR.
+ */
+ /* NOTE: GCC nested functions are used here for locality; the lambda
+ * captures ldp/ldp_len by enclosing scope (auto function). */
+ int is_kept(const char *entry) {
+ if (strncmp(entry, "PSEUDO_", 7) != 0 &&
+ strncmp(entry, ldp, ldp_len) != 0)
+ return 1;
+ if (strncmp(entry, "PSEUDO_PREFIX=", 14) == 0) return 1;
+ if (strncmp(entry, "PSEUDO_LOCALSTATEDIR=", 21) == 0) return 1;
+ return 0;
+ }
+
+ /* Process internal_table */
+ {
+ int w = 0;
+ for (int i = 0; i < internal_count; i++) {
+ if (strncmp(internal_table[i], ldp, ldp_len) == 0) {
+ /* LD_PRELOAD: strip ASAN lib, keep pseudo lib */
+ char *s = strip_asan_from_preload(
+ internal_table[i] + ldp_len);
+ char *e = s ? malloc(ldp_len + strlen(s) + 1) : NULL;
+ if (e) {
+ memcpy(e, ldp, ldp_len);
+ strcpy(e + ldp_len, s);
+ }
+ free(internal_table[i]);
+ free(s);
+ if (e) internal_table[w++] = e;
+ } else if (is_kept(internal_table[i])) {
+ internal_table[w++] = internal_table[i];
+ } else {
+ free(internal_table[i]); /* drop PSEUDO_BINDIR etc. */
+ }
+ }
+ internal_count = w;
+ internal_table[w] = NULL;
+ }
+
+ /* Process environ (the heap copy) */
+ {
+ int w = 0;
+ for (int i = 0; environ[i]; i++) {
+ if (strncmp(environ[i], ldp, ldp_len) == 0) {
+ char *s = strip_asan_from_preload(environ[i] + ldp_len);
+ char *e = s ? malloc(ldp_len + strlen(s) + 1) : NULL;
+ if (e) {
+ memcpy(e, ldp, ldp_len);
+ strcpy(e + ldp_len, s);
+ }
+ free(environ[i]);
+ free(s);
+ if (e) environ[w++] = e;
+ } else if (is_kept(environ[i])) {
+ environ[w++] = environ[i];
+ } else {
+ free(environ[i]); /* drop PSEUDO_BINDIR etc. */
+ }
+ }
+ environ[w] = NULL;
+ }
+ }
+
+ /*
+ * Force pseudo server startup in the parent before any children are
+ * forked. Without this, all PIPELINE_STAGES children may try to spawn
+ * the server simultaneously, causing a "lock_held" race condition on the
+ * first iteration.
+ */
+ access(".", F_OK);
+
+ int iterations = 20;
+ for (int i = 0; i < iterations; i++) {
+ if (run_pipeline_iteration() != 0) {
+ fprintf(stderr, "FAILED on pipeline iteration %d\n", i + 1);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/test/test-bash-exec-env.sh b/test/test-bash-exec-env.sh
new file mode 100755
index 0000000..d95a04d
--- /dev/null
+++ b/test/test-bash-exec-env.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Test for the bash/pseudo environment conflict:
+# https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078
+#
+# The compiled helper binary (test-bash-exec-env.c) exports its own
+# getenv/setenv/unsetenv (simulating bash) and calls maybe_make_export_env()
+# before each execve(), exactly reproducing the opkg-build crash pattern.
+#
+# Detection mechanism:
+# The binary strips all PSEUDO_* vars (except PSEUDO_PREFIX and
+# PSEUDO_LOCALSTATEDIR) from its internal table and environ before
+# starting. This forces pseudo_setupenv() — called by pseudo's fork
+# wrapper in each child — to ADD those vars back.
+#
+# The check is deterministic: each child inspects the real environ after
+# pseudo's fork wrapper has run.
+#
+# Unfixed pseudo: SETENV() -> dlsym(RTLD_NEXT) -> glibc setenv writes the
+# stripped PSEUDO_* vars straight back into the real environ array. The
+# child sees them reappear and reports the bug (exit 42); the test fails.
+#
+# Fixed pseudo: SETENV() -> our binary's setenv() -> internal_table only;
+# the real environ is left untouched, no PSEUDO_* vars reappear, the child
+# execs cleanly and the test passes.
+#
+# MALLOC_CHECK_=3 is kept as a secondary safety net so any residual heap
+# corruption from the unfixed code also aborts the run.
+
+MALLOC_CHECK_=3 $(dirname "$0")/test-bash-exec-env || { echo "FAILED: test-bash-exec-env returned $?" ; exit 1; }
+
+exit 0
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [yocto-patches] [pseudo][PATCH 22/23] test-bash-exec-env: Add bash env test case
2026-07-03 0:46 ` [pseudo][PATCH 22/23] test-bash-exec-env: Add bash env test case Mark Hatle
@ 2026-07-03 11:13 ` Paul Barker
0 siblings, 0 replies; 28+ messages in thread
From: Paul Barker @ 2026-07-03 11:13 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
[-- Attachment #1: Type: text/plain, Size: 36807 bytes --]
On Thu, 2026-07-02 at 19:46 -0500, Mark Hatle wrote:
> From: Mark Hatle <mark.hatle@amd.com>
>
> Add a test reproducing the bash/pseudo environment conflict
> (https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078) where pseudo's
> setenv workaround corrupted memory when pseudo ran under bash.
>
> The helper binary exports its own getenv/setenv/unsetenv (as bash does),
> maintaining a private variable table separate from environ. It strips the
> derived PSEUDO_* variables and forks children, mirroring the opkg-build
> pipeline that triggered the production crash. pseudo's fork wrapper runs
> pseudo_setupenv() in each child, which re-adds those variables; the child
> then checks whether they leaked back into the real environ:
>
> Unfixed pseudo calls glibc's setenv via dlsym(RTLD_NEXT), writing the
> variables straight into environ and desyncing it from bash's table.
>
> Fixed pseudo calls the process's own setenv, leaving environ untouched.
>
> The check is deterministic, so the test fails when the fixes are reverted
> and passes when they are present. MALLOC_CHECK_=3 is kept as a secondary
> safety net.
>
> AI-Generated: Test constructed with GitHub Copilot (Claude Opus 4.8)
>
> Signed-off-by: Mark Hatle <mark.hatle@amd.com>
Hi Mark,
I've done some initial review and added some comments below, though I
must admit I ran out of patience with the AI-generated code. It needs a
thorough tidy up, then another review.
> ---
> test/test-bash-exec-env.c | 667 +++++++++++++++++++++++++++++++++++++
> test/test-bash-exec-env.sh | 34 ++
> 2 files changed, 701 insertions(+)
> create mode 100644 test/test-bash-exec-env.c
> create mode 100755 test/test-bash-exec-env.sh
>
> diff --git a/test/test-bash-exec-env.c b/test/test-bash-exec-env.c
> new file mode 100644
> index 0000000..68ed42a
> --- /dev/null
> +++ b/test/test-bash-exec-env.c
> @@ -0,0 +1,667 @@
> +/*
> + * SPDX-License-Identifier: LGPL-2.1-only
> + *
> + * test-bash-exec-env.c
> + *
> + * Reproducer for https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078
> + *
> + * What this binary simulates
> + * --------------------------
> + * bash exports getenv(), setenv(), and unsetenv() as dynamic symbols.
> + * Because the main executable appears first in the dynamic-linker search
> + * order, every library loaded into the process (including libpseudo.so)
> + * resolves calls to those names to bash's own implementations.
> + *
> + * bash maintains a private variable hash table that is separate from the
> + * C-library 'environ' array. bash's setenv/getenv operate on this table;
> + * 'environ' is only rebuilt lazily by maybe_make_export_env().
> + *
> + * The old pseudo workaround (commit 80c6334a) used
> + * pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv")
> + * to bypass bash's override and call glibc's setenv directly.
> + * dlsym(RTLD_NEXT, …) from within an LD_PRELOAD library searches the
> + * shared-library chain *after* the LD_PRELOAD library, so it finds
> + * glibc's implementation — it does NOT find the main executable's
> + * (bash's) version.
> + *
> + * glibc's setenv modifies 'environ' directly, allocating a new heap
> + * block (block A) for the updated "LD_PRELOAD=libpseudo.so:…" entry.
> + * bash's internal variable table is NOT updated.
> + *
> + * When bash later calls maybe_make_export_env() (before exec-ing each
> + * pipeline stage), it calls strvec_flush() which frees every entry in
> + * the current 'environ' array — including block A — and rebuilds from
> + * the internal table (which still has the original LD_PRELOAD without
> + * libpseudo.so).
> + *
> + * The freed block A therefore remains live in the allocator's free list
> + * while pseudo's exec wrapper (pseudo_setupenvp) iterates 'environ'.
> + * Whether the access to freed memory produces a crash depends on whether
> + * the allocator happens to reuse that block and overwrite its contents
> + * before pseudo reads from it.
> + *
> + * This binary faithfully reproduces the bash conditions:
> + *
> + * 1. It exports its own setenv/getenv/unsetenv (like bash) that
> + * maintain a private internal table, separate from 'environ'.
> + * The regular setenv/getenv calls in pseudo therefore go to
> + * *our* functions; only dlsym(RTLD_NEXT, …) from inside
> + * libpseudo.so reaches glibc's implementations.
> + *
> + * 2. It implements strvec_flush() and maybe_make_export_env() that
> + * rebuild 'environ' from the internal table, freeing the old
> + * array (which contains glibc-setenv-allocated blocks).
> + *
> + * 3. It runs the pipeline pattern from opkg-build: fork N children
> + * in parallel (simulating find|sort|tar|gzip|ar), each child
> + * calling maybe_make_export_env() then execve(). This is the
> + * exact sequence that triggered the production crash.
> + *
> + * Detection
> + * ---------
> + * The bug is detected deterministically rather than by relying on the
> + * probabilistic heap corruption it causes. main() strips the derived
> + * PSEUDO_* variables (PSEUDO_BINDIR, PSEUDO_LIBDIR, …) from both the
> + * internal table and the real 'environ'. pseudo's fork wrapper then
> + * runs pseudo_setupenv() in every child, which re-adds them:
> + *
> + * Unfixed pseudo calls glibc's setenv (via dlsym(RTLD_NEXT, …)),
> + * which writes the variables straight back into the real 'environ'
> + * array — the very environ/allocator desync that corrupts bash's
> + * heap in production. The child observes the reappearing PSEUDO_*
> + * entries and reports the bug.
> + *
> + * Fixed pseudo calls the process's own setenv (ours/bash's), which
> + * updates only the internal table, and the exec/system/popen
> + * wrappers operate on a private pseudo_setupenvp() copy and restore
> + * environ afterwards. The real 'environ' is never mutated, so the
> + * PSEUDO_* variables do not reappear and the child exits cleanly.
> + *
> + * See pseudo_mutated_environ() below for the check. MALLOC_CHECK_=3 is
> + * still set by the shell wrapper as a secondary safety net so that any
> + * residual heap corruption also aborts the run.
> + */
> +
> +#define _GNU_SOURCE
> +#include <errno.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +
> +/* ------------------------------------------------------------------ */
> +/* Internal variable table — analogous to bash's variable hash table. */
> +/* setenv/getenv/unsetenv operate on this table; 'environ' is rebuilt */
> +/* on demand by maybe_make_export_env(). */
> +/* ------------------------------------------------------------------ */
> +
> +static char **internal_table = NULL; /* "KEY=VALUE" strings */
> +static int internal_count = 0;
> +static int internal_cap = 0;
The comment and code formatting is a complete mess. If we're going to
end comment lines with '*/' then they should be aligned, but we may as
well just use the simpler comment format used above. We should also
either align '=' or consistently use one space between a variable name
and '='.
> +
> +static int table_find(const char *name, size_t nlen)
> +{
> + for (int i = 0; i < internal_count; i++) {
> + if (strncmp(internal_table[i], name, nlen) == 0 &&
> + internal_table[i][nlen] == '=')
> + return i;
> + }
> + return -1;
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* Exported env functions — these override glibc's versions for code */
> +/* that resolves symbols via the normal dynamic-linker search order */
> +/* (i.e., callers inside bash/this binary itself). */
> +/* */
> +/* dlsym(RTLD_NEXT, "setenv") from an LD_PRELOAD library searches */
> +/* *after* the LD_PRELOAD library, finding glibc's implementation — */
> +/* NOT these functions. That is the exact asymmetry that pseudo's old */
> +/* workaround relied on and that caused the bug. */
> +/* */
> +/* The defensive NULL checks below intentionally mirror bash's own */
> +/* env functions. glibc declares setenv/getenv/unsetenv with the */
> +/* 'nonnull' attribute, so comparing the parameters to NULL trips */
> +/* -Wnonnull-compare; suppress it for this block since keeping the */
> +/* guards is deliberate. */
> +/* ------------------------------------------------------------------ */
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wnonnull-compare"
This further ties pseudo to building with GCC. It may be better to just
pass -Wno-nonnull-compare for the whole test file.
> +
> +int setenv(const char *name, const char *value, int overwrite)
> +{
> + if (!name || !value || strchr(name, '=')) { errno = EINVAL; return -1; }
This doesn't all need to be on one line.
> + size_t nlen = strlen(name);
> + size_t vlen = strlen(value);
> +
> + /* Before main() initialises internal_table, update environ directly. */
> + if (!internal_table) {
> + /* Find and replace existing entry, or append if not found. */
> + if (environ) {
> + for (int i = 0; environ[i]; i++) {
> + if (strncmp(environ[i], name, nlen) == 0 &&
> + environ[i][nlen] == '=') {
> + if (!overwrite) return 0;
> + char *e = malloc(nlen + 1 + vlen + 1);
> + if (!e) return -1;
> + memcpy(e, name, nlen); e[nlen] = '=';
> + memcpy(e + nlen + 1, value, vlen + 1);
> + free(environ[i]); environ[i] = e;
> + return 0;
This block is just unparsable by human eyeballs. The if condition
continues at the same level of indentation as the following block, and
we have single line if conditions that should be split across two lines
with proper indentation.
There are more instances of this below that need fixing.
> + }
> + }
> + }
> + /* Entry not found: can't resize kernel-provided environ safely;
> + * just ignore (the entry will be added when main() starts). */
> + return 0;
> + }
> +
> + int idx = table_find(name, nlen);
> + if (idx >= 0) {
> + if (!overwrite) return 0;
> + free(internal_table[idx]);
> + internal_table[idx] = NULL;
> + } else {
> + /* Grow table if needed (keep a NULL sentinel). */
> + if (internal_count + 1 >= internal_cap) {
> + internal_cap = (internal_cap < 8) ? 16 : internal_cap * 2;
> + char **t = realloc(internal_table,
> + (size_t)internal_cap * sizeof(char *));
> + if (!t) return -1;
> + internal_table = t;
> + }
> + idx = internal_count++;
> + internal_table[internal_count] = NULL; /* sentinel */
> + }
> +
> + char *entry = malloc(nlen + 1 + vlen + 1);
> + if (!entry) return -1;
> + memcpy(entry, name, nlen);
> + entry[nlen] = '=';
> + memcpy(entry + nlen + 1, value, vlen + 1);
> + internal_table[idx] = entry;
> + return 0;
> +}
> +
> +char *getenv(const char *name)
> +{
> + if (!name) return NULL;
> + size_t nlen = strlen(name);
> + /*
> + * Before main() initialises internal_table, fall back to searching
> + * 'environ' directly. This is needed because pseudo's library
> + * constructor (which runs before main()) calls getenv() to read
> + * PSEUDO_PREFIX and similar variables.
> + */
> + if (!internal_table) {
> + for (int i = 0; environ && environ[i]; i++) {
> + if (strncmp(environ[i], name, nlen) == 0 &&
> + environ[i][nlen] == '=')
> + return environ[i] + nlen + 1;
> + }
> + return NULL;
> + }
> + int idx = table_find(name, nlen);
> + if (idx < 0) return NULL;
> + return internal_table[idx] + nlen + 1;
> +}
> +
> +int unsetenv(const char *name)
> +{
> + if (!name || !*name || strchr(name, '=')) { errno = EINVAL; return -1; }
> + size_t nlen = strlen(name);
> + /* Before internal_table is initialised, remove from environ directly. */
> + if (!internal_table) {
> + if (environ) {
> + for (int i = 0; environ[i]; i++) {
> + if (strncmp(environ[i], name, nlen) == 0 &&
> + environ[i][nlen] == '=') {
> + free(environ[i]);
> + int j = i;
> + while (environ[j]) { environ[j] = environ[j+1]; j++; }
> + break;
> + }
> + }
> + }
> + return 0;
> + }
> + int idx = table_find(name, nlen);
> + if (idx < 0) return 0;
> + free(internal_table[idx]);
> + memmove(&internal_table[idx], &internal_table[idx + 1],
> + (size_t)(internal_count - idx) * sizeof(char *));
> + internal_count--;
> + return 0;
> +}
> +
> +#pragma GCC diagnostic pop
> +
> +/* ------------------------------------------------------------------ */
> +/* strip_asan_from_preload — remove any libasan*.so entry from an */
> +/* LD_PRELOAD value string (colon-separated list). */
> +/* */
> +/* The ASAN library must be first in LD_PRELOAD so that ASAN properly */
> +/* intercepts malloc/free from all shared libraries (including */
> +/* libpseudo.so). But the pseudo server-spawn grandchild must NOT */
> +/* inherit it: the server is not ASAN-compiled and loading the ASAN */
> +/* runtime into an uninstrumented binary causes SQLite lock failures. */
> +/* */
> +/* By stripping libasan from the rebuilt 'environ' (produced by */
> +/* maybe_make_export_env), the server inherits clean LD_PRELOAD while */
> +/* ASAN detection in the direct child (fork of our binary) remains */
> +/* active — ASAN is compiled into the binary and its hooks are already */
> +/* live from process startup. */
> +/* ------------------------------------------------------------------ */
> +static char *strip_asan_from_preload(const char *preload)
> +{
> + if (!preload) return NULL;
> + char *buf = strdup(preload);
> + if (!buf) return NULL;
> +
> + char *out = buf;
> + const char *in = preload;
> + while (*in) {
> + const char *sep = strchr(in, ':');
> + size_t len = sep ? (size_t)(sep - in) : strlen(in);
> +
> + /* skip any entry that contains "libasan" */
> + int skip = 0;
> + for (size_t k = 0; k + 6 <= len; k++) {
> + if (strncmp(in + k, "libasan", 7) == 0) { skip = 1; break; }
> + }
> +
> + if (!skip) {
> + memcpy(out, in, len);
> + out += len;
> + if (sep) *out++ = ':';
> + }
> +
> + in += len;
> + if (*in == ':') in++;
> + }
> + /* trim a trailing colon */
> + if (out > buf && *(out - 1) == ':') out--;
> + *out = '\0';
> + return buf;
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* strvec_flush — free every string in v[] then free v itself. */
> +/* Equivalent to bash's strvec_flush() in lib/sh/stringvec.c. */
> +/* ------------------------------------------------------------------ */
> +static void strvec_flush(char **v)
> +{
> + if (!v) return;
> + for (int i = 0; v[i]; i++)
> + free(v[i]);
> + free(v);
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* maybe_make_export_env — rebuild 'environ' from the internal table. */
> +/* */
> +/* This is the function that triggers the use-after-free: */
> +/* */
> +/* 1. pseudo's fork wrapper called glibc's setenv (via */
> +/* dlsym(RTLD_NEXT)) which allocated block A and stored it in */
> +/* environ[LD_PRELOAD_idx]. */
> +/* */
> +/* 2. strvec_flush(old_environ) frees block A. */
> +/* */
> +/* 3. environ is updated to point to the freshly built array */
> +/* (built from internal_table, which has the original LD_PRELOAD */
> +/* without libpseudo.so). */
> +/* */
> +/* 4. When the exec wrapper runs pseudo_setupenvp(environ), the */
> +/* allocator may have already reused block A, causing the freed */
> +/* memory to be read with stale or garbage content. */
> +/* ------------------------------------------------------------------ */
> +static void maybe_make_export_env(void)
> +{
> + char **old = environ;
> +
> + /* Build fresh copy from internal_table. */
> + char **new_env = malloc((size_t)(internal_count + 1) * sizeof(char *));
> + if (!new_env) return;
> +
> + for (int i = 0; i < internal_count; i++) {
> + new_env[i] = strdup(internal_table[i]);
> + if (!new_env[i]) {
> + for (int j = 0; j < i; j++) free(new_env[j]);
> + free(new_env);
> + return;
> + }
> + }
> + new_env[internal_count] = NULL;
> +
> + /* Strip the ASAN runtime library from LD_PRELOAD in BOTH the rebuilt
> + * environ AND internal_table so that the pseudo server-spawn grandchild
> + * does not inherit it (via pseudo_setupenv reading internal_table).
> + *
> + * ASAN detection in the current process is unaffected: libasan.so is
> + * already mapped in the process address space (loaded at startup via the
> + * original LD_PRELOAD) and its malloc/free interception is active at the
> + * GOT/PLT level for all shared libraries including libpseudo.so.
> + * Removing it from environ/internal_table only affects exec'd children. */
> + const char *ldp = "LD_PRELOAD=";
> + size_t ldp_len = strlen(ldp);
> + for (int i = 0; i < internal_count; i++) {
> + if (strncmp(new_env[i], ldp, ldp_len) == 0) {
> + char *stripped = strip_asan_from_preload(new_env[i] + ldp_len);
> + if (stripped) {
> + char *new_entry = malloc(ldp_len + strlen(stripped) + 1);
> + if (new_entry) {
> + memcpy(new_entry, ldp, ldp_len);
> + strcpy(new_entry + ldp_len, stripped);
> + free(new_env[i]);
> + new_env[i] = new_entry;
> + }
> + free(stripped);
> + }
> + break;
> + }
> + }
> + /* Also strip from internal_table so pseudo_setupenv() doesn't
> + * re-inject libasan into environ via SETENV(). */
> + for (int i = 0; i < internal_count; i++) {
> + if (strncmp(internal_table[i], ldp, ldp_len) == 0) {
> + char *stripped = strip_asan_from_preload(internal_table[i] + ldp_len);
> + if (stripped) {
> + char *new_entry = malloc(ldp_len + strlen(stripped) + 1);
> + if (new_entry) {
> + memcpy(new_entry, ldp, ldp_len);
> + strcpy(new_entry + ldp_len, stripped);
> + free(internal_table[i]);
> + internal_table[i] = new_entry;
> + }
> + free(stripped);
> + }
> + break;
> + }
> + }
> +
> + /*
> + * Free the old environ. This releases every entry including any
> + * block that glibc's setenv (called by pseudo_setupenv inside the
> + * fork wrapper) had allocated. After this, 'environ' briefly
> + * points to freed memory until the assignment below.
> + */
> + strvec_flush(old);
> +
> + environ = new_env;
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* run_pipeline_iteration */
> +/* */
> +/* Simulate one opkg-build pipeline: */
> +/* ( cd CTRL && find . | sort > list ) */
> +/* ( cd PKG && find . | sort > list ) */
> +/* ( cd PKG && tar … | gzip > data.tar.gz ) */
> +/* ( cd CTRL && tar … | gzip > ctrl.tar.gz ) */
> +/* ( cd TMP && ar … ) */
> +/* */
> +/* Each child simulates one pipeline stage: */
> +/* fork → [pseudo fork wrapper runs pseudo_setupenv() in the child] */
> +/* child: check whether pseudo mutated the real environ (bug), then */
> +/* maybe_make_export_env() and execve("/bin/true") */
> +/* ------------------------------------------------------------------ */
> +#define PIPELINE_STAGES 5 /* find, sort, tar, gzip, ar */
This is not "one pipeline". It's five separate shell statements, with at
most two commands in a pipeline. But the function below seems to
simulate a single pipeline of five commands.
> +
> +/* Distinct exit code a child uses to report that pseudo mutated the
> + * real 'environ' array (i.e. the unfixed glibc-setenv code path ran). */
> +#define BUG_ENV_MUTATED 42
> +
> +/* ------------------------------------------------------------------ */
> +/* pseudo_mutated_environ — deterministic detector for the bug fixed */
> +/* by commits 9c6b4c1..5abd42c. */
> +/* */
> +/* pseudo's fork wrapper runs pseudo_setupenv() in every child before */
> +/* fork() returns. pseudo_setupenv() re-adds the PSEUDO_* variables */
> +/* (PSEUDO_BINDIR, PSEUDO_LIBDIR, …) that main() stripped from the */
> +/* environment: */
> +/* */
> +/* Unfixed pseudo: SETENV -> pseudo_real_setenv (dlsym RTLD_NEXT) -> */
> +/* glibc setenv, which writes directly into the real 'environ' */
> +/* array. The stripped PSEUDO_* vars therefore REAPPEAR in the */
> +/* real environ — exactly the environ/allocator desync that */
> +/* corrupts bash's heap in production. */
> +/* */
> +/* Fixed pseudo: SETENV -> setenv -> our (bash's) setenv, which only */
> +/* updates internal_table; the exec/system/popen wrappers build a */
> +/* private copy with pseudo_setupenvp() and restore environ. The */
> +/* real 'environ' is left untouched, so the stripped PSEUDO_* vars */
> +/* do NOT reappear there. */
> +/* */
> +/* Returns 1 if a stripped PSEUDO_* var was found back in the real */
> +/* environ (buggy code path), 0 otherwise. Must be called BEFORE */
> +/* maybe_make_export_env(), which would otherwise rebuild environ from */
> +/* internal_table and discard the injected entries. */
> +/* ------------------------------------------------------------------ */
> +static int pseudo_mutated_environ(void)
> +{
> + for (int i = 0; environ && environ[i]; i++) {
> + if (strncmp(environ[i], "PSEUDO_BINDIR=", 14) == 0 ||
> + strncmp(environ[i], "PSEUDO_LIBDIR=", 14) == 0)
> + return 1;
> + }
> + return 0;
> +}
> +
> +static int run_pipeline_iteration(void)
> +{
> + pid_t pids[PIPELINE_STAGES];
> + char *const args[] = { "/bin/true", NULL };
> +
> + /*
> + * Fork all pipeline stages before waiting for any of them, just
> + * as bash does for a pipeline. pseudo's fork wrapper runs
> + * pseudo_setupenv() in each child before fork() returns.
> + */
> + for (int s = 0; s < PIPELINE_STAGES; s++) {
> + pid_t pid = fork();
> + if (pid < 0) {
> + perror("fork");
> + return -1;
> + }
> + if (pid == 0) {
> + /*
> + * Child: pseudo's fork wrapper has already run
> + * pseudo_setupenv() at this point. Deterministically
> + * detect whether it mutated the real environ (the bug)
> + * before doing anything that would rebuild environ.
> + */
> + if (pseudo_mutated_environ())
> + _exit(BUG_ENV_MUTATED);
> + /*
> + * Otherwise behave like bash: rebuild environ from the
> + * internal table and exec the pipeline stage.
> + */
> + maybe_make_export_env();
> + execve("/bin/true", args, environ);
> + _exit(127);
> + }
> + pids[s] = pid;
> + }
> +
> + /* Wait for all pipeline children. */
> + for (int s = 0; s < PIPELINE_STAGES; s++) {
> + int status;
> + if (waitpid(pids[s], &status, 0) < 0) {
> + perror("waitpid");
> + return -1;
> + }
> + if (WIFEXITED(status) && WEXITSTATUS(status) == BUG_ENV_MUTATED) {
> + fprintf(stderr,
> + "BUG: pseudo mutated the real environ in pipeline stage %d "
> + "(pseudo_setupenv used glibc setenv via dlsym instead of the "
> + "process's own setenv)\n", s);
> + return -1;
> + }
> + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
> + fprintf(stderr, "pipeline stage %d failed: status=%d\n",
> + s, status);
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> +int main(void)
> +{
> + /* Initialise internal_table from the process's current environ. */
> + int count = 0;
> + while (environ[count]) count++;
> +
> + internal_cap = count + 32;
> + internal_table = malloc((size_t)internal_cap * sizeof(char *));
> + if (!internal_table) { perror("malloc"); return 1; }
> +
> + for (int i = 0; i < count; i++) {
> + internal_table[i] = strdup(environ[i]);
> + if (!internal_table[i]) { perror("strdup"); return 1; }
> + }
> + internal_table[count] = NULL;
> + internal_count = count;
> +
> + /*
> + * Replace environ with a heap-allocated copy before any call to
> + * maybe_make_export_env(). The initial environ supplied by the
> + * kernel exec is in static memory, not the heap; calling free()
> + * on those strings (as strvec_flush does) would crash immediately.
> + * bash avoids this by building its own heap-allocated export_env
> + * during shell initialisation; we replicate that here.
> + */
> + {
> + char **heap_env = malloc((size_t)(count + 1) * sizeof(char *));
> + if (!heap_env) { perror("malloc"); return 1; }
> + for (int i = 0; i < count; i++) {
> + heap_env[i] = strdup(internal_table[i]);
> + if (!heap_env[i]) { perror("strdup"); return 1; }
> + }
> + heap_env[count] = NULL;
> + environ = heap_env; /* now environ is entirely heap-managed */
> + }
This would be clearer as a separate function that gets called rather
than a nested scope.
> +
> + /*
> + * Run 20 pipeline iterations. With the unfixed pseudo code and
> + * MALLOC_CHECK_=3, the heap corruption introduced by pseudo_setupenv
> + * (glibc setenv) followed by strvec_flush causes an abort within
> + * the first few iterations on affected platforms.
> + */
This comment belongs with the for loop at the end of the function.
> +
> + /*
> + * Strip the ASAN runtime library from LD_PRELOAD and strip derived
> + * PSEUDO_* vars (PSEUDO_BINDIR, PSEUDO_LIBDIR, etc.) from both
> + * internal_table and heap environ BEFORE any pseudo-intercepted call.
> + *
> + * Reason for stripping ASAN from LD_PRELOAD:
> + * The pseudo server-spawn grandchild is not ASAN-compiled; loading the
> + * ASAN runtime into an uninstrumented binary causes SQLite lock failures.
This duplicates (badly) the explanation already given in the comment for
strip_asan_from_preload().
> + *
> + * Reason for stripping derived PSEUDO_* vars:
> + * When the test runs inside the pseudo test framework, the outer pseudo's
> + * exec wrapper pre-populates all PSEUDO_* vars (PSEUDO_BINDIR etc.) in
> + * the binary's initial environ via pseudo_setupenvp(). If these are
> + * already present, pseudo_setupenv() treats them as existing (overwrite=0)
> + * and makes no change — no __add_to_environ() call, no heap-corruption
> + * opportunity, MALLOC_CHECK_=3 detects nothing.
> + * By stripping them here we force pseudo_setupenv() (in the fork wrapper
> + * of every child) to ADD them as NEW environ entries. The unfixed code
> + * (glibc setenv via dlsym RTLD_NEXT) calls __add_to_environ() which
> + * calls realloc(environ_array). strvec_flush() later frees that
> + * allocation, and MALLOC_CHECK_=3 aborts the server-spawn grandchild.
> + * The fixed code calls our binary's setenv() which updates internal_table
> + * only — no __add_to_environ(), no realloc, no corruption.
> + *
> + * We keep PSEUDO_PREFIX and PSEUDO_LOCALSTATEDIR so that pseudo can find
> + * the server binary and socket directory.
> + */
> + {
> + const char *ldp = "LD_PRELOAD=";
> + size_t ldp_len = strlen(ldp);
> +
> + /* is_kept: return 1 if the env entry should NOT be stripped.
> + * Keep non-PSEUDO, non-LD_PRELOAD, PSEUDO_PREFIX, PSEUDO_LOCALSTATEDIR.
> + */
> + /* NOTE: GCC nested functions are used here for locality; the lambda
> + * captures ldp/ldp_len by enclosing scope (auto function). */
> + int is_kept(const char *entry) {
> + if (strncmp(entry, "PSEUDO_", 7) != 0 &&
> + strncmp(entry, ldp, ldp_len) != 0)
> + return 1;
> + if (strncmp(entry, "PSEUDO_PREFIX=", 14) == 0) return 1;
> + if (strncmp(entry, "PSEUDO_LOCALSTATEDIR=", 21) == 0) return 1;
> + return 0;
> + }
This is nonsense - ldp & ldp_len are constants, they don't need to be
captured into a nested function for "locality". Better to define them as
global constants and move is_kept() to the top level.
> +
> + /* Process internal_table */
> + {
> + int w = 0;
> + for (int i = 0; i < internal_count; i++) {
> + if (strncmp(internal_table[i], ldp, ldp_len) == 0) {
> + /* LD_PRELOAD: strip ASAN lib, keep pseudo lib */
> + char *s = strip_asan_from_preload(
> + internal_table[i] + ldp_len);
> + char *e = s ? malloc(ldp_len + strlen(s) + 1) : NULL;
> + if (e) {
> + memcpy(e, ldp, ldp_len);
> + strcpy(e + ldp_len, s);
> + }
> + free(internal_table[i]);
> + free(s);
> + if (e) internal_table[w++] = e;
> + } else if (is_kept(internal_table[i])) {
> + internal_table[w++] = internal_table[i];
> + } else {
> + free(internal_table[i]); /* drop PSEUDO_BINDIR etc. */
> + }
> + }
> + internal_count = w;
> + internal_table[w] = NULL;
> + }
> +
> + /* Process environ (the heap copy) */
> + {
> + int w = 0;
> + for (int i = 0; environ[i]; i++) {
> + if (strncmp(environ[i], ldp, ldp_len) == 0) {
> + char *s = strip_asan_from_preload(environ[i] + ldp_len);
> + char *e = s ? malloc(ldp_len + strlen(s) + 1) : NULL;
> + if (e) {
> + memcpy(e, ldp, ldp_len);
> + strcpy(e + ldp_len, s);
> + }
> + free(environ[i]);
> + free(s);
> + if (e) environ[w++] = e;
> + } else if (is_kept(environ[i])) {
> + environ[w++] = environ[i];
> + } else {
> + free(environ[i]); /* drop PSEUDO_BINDIR etc. */
> + }
> + }
> + environ[w] = NULL;
> + }
These nested scopes and reuse of a 'w' variable are just confusing.
It looks like there is a lot of duplicated code which can probably be
refactored into a function that gets called twice, once with
internal_table and once with environ.
> + }
> +
> + /*
> + * Force pseudo server startup in the parent before any children are
> + * forked. Without this, all PIPELINE_STAGES children may try to spawn
> + * the server simultaneously, causing a "lock_held" race condition on the
> + * first iteration.
> + */
> + access(".", F_OK);
> +
> + int iterations = 20;
> + for (int i = 0; i < iterations; i++) {
> + if (run_pipeline_iteration() != 0) {
> + fprintf(stderr, "FAILED on pipeline iteration %d\n", i + 1);
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> diff --git a/test/test-bash-exec-env.sh b/test/test-bash-exec-env.sh
> new file mode 100755
> index 0000000..d95a04d
> --- /dev/null
> +++ b/test/test-bash-exec-env.sh
> @@ -0,0 +1,34 @@
> +#!/bin/bash
> +#
> +# SPDX-License-Identifier: LGPL-2.1-only
> +#
> +# Test for the bash/pseudo environment conflict:
> +# https://bugzilla.yoctoproject.org/show_bug.cgi?id=16078
> +#
> +# The compiled helper binary (test-bash-exec-env.c) exports its own
> +# getenv/setenv/unsetenv (simulating bash) and calls maybe_make_export_env()
> +# before each execve(), exactly reproducing the opkg-build crash pattern.
> +#
> +# Detection mechanism:
> +# The binary strips all PSEUDO_* vars (except PSEUDO_PREFIX and
> +# PSEUDO_LOCALSTATEDIR) from its internal table and environ before
> +# starting. This forces pseudo_setupenv() — called by pseudo's fork
> +# wrapper in each child — to ADD those vars back.
> +#
> +# The check is deterministic: each child inspects the real environ after
> +# pseudo's fork wrapper has run.
> +#
> +# Unfixed pseudo: SETENV() -> dlsym(RTLD_NEXT) -> glibc setenv writes the
> +# stripped PSEUDO_* vars straight back into the real environ array. The
> +# child sees them reappear and reports the bug (exit 42); the test fails.
> +#
> +# Fixed pseudo: SETENV() -> our binary's setenv() -> internal_table only;
> +# the real environ is left untouched, no PSEUDO_* vars reappear, the child
> +# execs cleanly and the test passes.
> +#
> +# MALLOC_CHECK_=3 is kept as a secondary safety net so any residual heap
> +# corruption from the unfixed code also aborts the run.
> +
> +MALLOC_CHECK_=3 $(dirname "$0")/test-bash-exec-env || { echo "FAILED: test-bash-exec-env returned $?" ; exit 1; }
> +
> +exit 0
Best regards,
--
Paul Barker
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* [pseudo][PATCH 23/23] test: various: Move to makefile compilation
2026-07-03 0:45 [pseudo][PATCH 00/23] Create new pseudo 1.99.0 version Mark Hatle
` (21 preceding siblings ...)
2026-07-03 0:46 ` [pseudo][PATCH 22/23] test-bash-exec-env: Add bash env test case Mark Hatle
@ 2026-07-03 0:46 ` Mark Hatle
22 siblings, 0 replies; 28+ messages in thread
From: Mark Hatle @ 2026-07-03 0:46 UTC (permalink / raw)
To: yocto-patches; +Cc: richard.purdie, frezidok1
From: Mark Hatle <mark.hatle@amd.com>
Removal local gcc call from test environment, the makefile is more suited
to building the tests. This ensures they can be built properly in a cross
compile environment.
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
test/test-chroot.c | 10 ++++++++++
test/test-chroot.sh | 14 +-------------
test/test-execl.c | 4 ++++
test/test-execl.sh | 13 +------------
test/test-linkat-chroot.sh | 4 +---
test/test-reexec-chroot.c | 10 ++++++++++
test/test-reexec-chroot.sh | 14 +-------------
7 files changed, 28 insertions(+), 41 deletions(-)
create mode 100644 test/test-chroot.c
create mode 100644 test/test-execl.c
create mode 100644 test/test-reexec-chroot.c
diff --git a/test/test-chroot.c b/test/test-chroot.c
new file mode 100644
index 0000000..7b18946
--- /dev/null
+++ b/test/test-chroot.c
@@ -0,0 +1,10 @@
+/* Return vals: 2 - invalid arg list
+ * 1 - chroot failed
+ * 0 - chroot succeeded
+ */
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ return 2;
+ return (chroot(argv[1]) == -1);
+}
diff --git a/test/test-chroot.sh b/test/test-chroot.sh
index faa4ffe..a7778ba 100755
--- a/test/test-chroot.sh
+++ b/test/test-chroot.sh
@@ -6,25 +6,13 @@
# Return vals: 2 - invalid arg list
# 1 - chroot failed
# 0 - chroot succeeded
-cat > chroot_test.c << EOF
-#include <unistd.h>
-int main(int argc, char *argv[]) {
- if (argc != 2)
- return 2;
- return (chroot(argv[1]) == -1);
-}
-EOF
-gcc -o chroot_test chroot_test.c
-
-./chroot_test `pwd`
+$(dirname "$0")/test-chroot `pwd`
if [ "$?" = "0" ]
then
#echo "Passed."
- rm -f chroot_test chroot_test.c
exit 0
fi
#echo "Failed"
-rm -f chroot_test chroot_test.c
exit 1
diff --git a/test/test-execl.c b/test/test-execl.c
new file mode 100644
index 0000000..31b803c
--- /dev/null
+++ b/test/test-execl.c
@@ -0,0 +1,4 @@
+#include <unistd.h>
+int main() {
+ return execl("/usr/bin/env", "/usr/bin/env", "A=A", "B=B", "C=C", NULL);
+}
diff --git a/test/test-execl.sh b/test/test-execl.sh
index 134055b..8715822 100755
--- a/test/test-execl.sh
+++ b/test/test-execl.sh
@@ -2,23 +2,12 @@
#
# SPDX-License-Identifier: LGPL-2.1-only
#
-cat > execl_test.c << EOF
-#include <unistd.h>
-int main() {
- return execl("/usr/bin/env", "/usr/bin/env", "A=A", "B=B", "C=C", NULL);
-}
-EOF
-
-gcc -o execl_test execl_test.c
-
-./execl_test | grep -q "C=C"
+$(dirname "$0")/test-execl | grep -q "C=C"
if [ "$?" = "0" ]
then
#echo "Passed."
- rm -f execl_test execl_test.c
exit 0
fi
#echo "Failed"
-rm -f execl_test execl_test.c
exit 1
diff --git a/test/test-linkat-chroot.sh b/test/test-linkat-chroot.sh
index 247a6d7..4f990c7 100755
--- a/test/test-linkat-chroot.sh
+++ b/test/test-linkat-chroot.sh
@@ -14,6 +14,4 @@ mkdir -p "$CHROOTDIR"
touch "$CHROOTDIR/a"
trap "rm -rf $(pwd)/linkat_chroot_test test-linkat-chroot" 0
-gcc -o test-linkat-chroot test/test-linkat-chroot.c
-
-./test-linkat-chroot "$CHROOTDIR"
+$(dirname "$0")/test-linkat-chroot "$CHROOTDIR"
diff --git a/test/test-reexec-chroot.c b/test/test-reexec-chroot.c
new file mode 100644
index 0000000..7b18946
--- /dev/null
+++ b/test/test-reexec-chroot.c
@@ -0,0 +1,10 @@
+/* Return vals: 2 - invalid arg list
+ * 1 - chroot failed
+ * 0 - chroot succeeded
+ */
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ return 2;
+ return (chroot(argv[1]) == -1);
+}
diff --git a/test/test-reexec-chroot.sh b/test/test-reexec-chroot.sh
index f6412bc..0666caf 100755
--- a/test/test-reexec-chroot.sh
+++ b/test/test-reexec-chroot.sh
@@ -8,26 +8,14 @@
# Return vals: 2 - invalid arg list
# 1 - chroot failed
# 0 - chroot succeeded
-cat > chroot_test.c << EOF
-#include <unistd.h>
-int main(int argc, char *argv[]) {
- if (argc != 2)
- return 2;
- return (chroot(argv[1]) == -1);
-}
-EOF
-
-gcc -o chroot_test chroot_test.c
# The following should just run chroot_test since pseudo is already loaded
-./bin/pseudo ./chroot_test `pwd`
+./bin/pseudo $(dirname "$0")/test-reexec-chroot `pwd`
if [ "$?" = "0" ]
then
#echo "Passed."
- rm -f chroot_test chroot_test.c
exit 0
fi
#echo "Failed"
-rm -f chroot_test chroot_test.c
exit 1
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread