From 1c463a688c7edcfc78d19f2bbf4926f2a8bdb6bd Mon Sep 17 00:00:00 2001 From: Ryan Mack Date: Wed, 22 Oct 2025 09:29:38 -0400 Subject: [PATCH] Fix AIX dialect to work with context refactor The AIX driver no longer compiled after the major refactor that moved global variables into a context structure passed to functions. This commit updates the AIX dialect to work with the new architecture. This has been tested in AIX 7.2 and AIX 7.3. Changes: - Add dialect-specific fields to struct lsof_context_dialect in dlsof.h: - kd, km: kernel memory file descriptors - lvfs: local vfs structure table - mtab: local mount table - clone, clone_maj, clone_ptc: clone device information (AIX >= 4.1.4) - afs_vfsp: AFS vfs kernel pointer (when HAS_AFS is defined) - Add convenience macros (Kd, Km, Lvfs, Mtab, Clone, CloneMaj, ClonePtc, AFSVfsp) to access dialect context fields, allowing existing code to work with minimal changes - Remove global variable declarations from dlsof.h and definitions from dstore.c for variables now in context - Update initialize() in dproc.c to initialize all dialect context fields - Update kreadx() function signature to take context parameter and update all call sites in dproc.c - The isglocked() function returns enum lsof_lock_mode, not char. Update the prototype in dproto.h to match the implementation. - Fix signal handler lowpgsp() to not take context parameter Signal handlers can only take signal number, so use static context pointer - Work around GCC time() header conflict - Fix machine.h include order issue causing incorrect kernel struct sizes - Add dnode2.c symlink to .gitignore All other AIX source files (ddev.c, dfile.c, dnode.c, dnode1.c, dnode2.c, dsock.c) should work without changes due to the convenience macros that transparently access ctx->dialect fields. This allows the AIX driver to compile with the refactored codebase while maintaining compatibility with the existing code structure. --- .gitignore | 1 + lib/common.h | 2 +- lib/dialects/aix/ddev.c | 4 +- lib/dialects/aix/dlsof.h | 43 ++++++++++++++----- lib/dialects/aix/dnode.c | 2 +- lib/dialects/aix/dproc.c | 85 +++++++++++++++++++++++++++++--------- lib/dialects/aix/dproto.h | 2 +- lib/dialects/aix/dstore.c | 23 ----------- lib/dialects/aix/machine.h | 18 +++++++- 9 files changed, 120 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 372c43d4..deda7f20 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,7 @@ lib/dialects/netbsd/include /dmnt.c /dnode.c /dnode1.c +/dnode2.c /dproc.c /dproto.h /dsock.c diff --git a/lib/common.h b/lib/common.h index 6014510d..1e6c67ee 100644 --- a/lib/common.h +++ b/lib/common.h @@ -35,11 +35,11 @@ #if !defined(COMMON_H) # define COMMON_H 1 -# include "lsof.h" # if defined(AUTOTOOLS) # include "autotools.h" # endif # include "machine.h" +# include "lsof.h" # if !defined(FSV_DEFAULT) # define FSV_DEFAULT 0 diff --git a/lib/dialects/aix/ddev.c b/lib/dialects/aix/ddev.c index e110d6d2..f9e3e50c 100644 --- a/lib/dialects/aix/ddev.c +++ b/lib/dialects/aix/ddev.c @@ -634,7 +634,7 @@ int rw_clone_sect(struct lsof_context *ctx, /* context */ for (c = Clone, n = 0; c; c = c->next, n++) ; (void)snpf(buf, sizeof(buf), "clone section: %d\n", n); - if (wr2DCfd(buf, &DCcksum)) + if (wr2DCfd(ctx, buf, &DCcksum)) return (1); /* * Write the clone section lines. @@ -642,7 +642,7 @@ int rw_clone_sect(struct lsof_context *ctx, /* context */ for (c = Clone; c; c = c->next) { (void)snpf(buf, sizeof(buf), "%x %ld %s\n", c->cd.rdev, (long)c->cd.inode, c->cd.name); - if (wr2DCfd(buf, &DCcksum)) + if (wr2DCfd(ctx, buf, &DCcksum)) return (1); } return (0); diff --git a/lib/dialects/aix/dlsof.h b/lib/dialects/aix/dlsof.h index b7a5affd..5f937b22 100644 --- a/lib/dialects/aix/dlsof.h +++ b/lib/dialects/aix/dlsof.h @@ -306,9 +306,6 @@ struct clone { struct l_dev cd; /* device, inode, name, verify status */ struct clone *next; /* next entry */ }; -extern struct clone *Clone; -extern int CloneMaj; -extern int ClonePtc; # endif /* AIXV>=4140 */ /* @@ -339,7 +336,6 @@ struct l_vfs { int vmt_gfstype; /* vmount gfs type */ struct l_vfs *next; /* forward link */ }; -extern struct l_vfs *Lvfs; /* * Local mount information @@ -363,7 +359,6 @@ struct mounts { struct mounts *next; /* forward link */ }; -extern struct mounts *Mtab; /* * Search file information @@ -396,13 +391,8 @@ extern struct nlist AFSnl[]; /* AFS kernel symbol name list table */ extern char *AFSApath; /* alternate AFS name list path (from -a) */ # endif /* defined(HASAOPT) */ -extern KA_T AFSVfsp; /* AFS struct vfs kernel pointer */ # endif /* defined(HAS_AFS) */ -extern int Kd; -extern int Km; -extern struct nlist Nl[]; - # if defined(TCPSTATES) && AIXV <= 3250 /* * For AIX 3.2.5 and below, there is no header file with the definition @@ -427,6 +417,37 @@ static char *tcpstates[] = {"CLOSED", "LISTEN", "SYN_SENT", * in libc.so */ # endif /* AIXA>1 */ -struct lsof_context_dialect {}; +struct lsof_context_dialect { + int kd; /* /dev/kmem file descriptor */ + int km; /* /dev/mem file descriptor */ + struct l_vfs *lvfs; /* local vfs structure table */ + struct mounts *mtab; /* local mount table */ + +#if AIXV >= 4140 + struct clone *clone; /* local clone information */ + int clone_maj; /* clone major device number */ + int clone_ptc; /* /dev/ptc minor device number */ +#endif /* AIXV>=4140 */ + +#if defined(HAS_AFS) + KA_T afs_vfsp; /* AFS vfs struct kernel pointer */ +#endif /* defined(HAS_AFS) */ +}; + +/* Convenience macros to access dialect-specific context */ +#define Kd (ctx->dialect.kd) +#define Km (ctx->dialect.km) +#define Lvfs (ctx->dialect.lvfs) +#define Mtab (ctx->dialect.mtab) + +#if AIXV >= 4140 +#define Clone (ctx->dialect.clone) +#define CloneMaj (ctx->dialect.clone_maj) +#define ClonePtc (ctx->dialect.clone_ptc) +#endif /* AIXV>=4140 */ + +#if defined(HAS_AFS) +#define AFSVfsp (ctx->dialect.afs_vfsp) +#endif /* defined(HAS_AFS) */ #endif /* AIX_LSOF_H */ diff --git a/lib/dialects/aix/dnode.c b/lib/dialects/aix/dnode.c index c220cfc0..0e33d079 100644 --- a/lib/dialects/aix/dnode.c +++ b/lib/dialects/aix/dnode.c @@ -495,7 +495,7 @@ void process_node(struct lsof_context *ctx, /* context */ */ Namech[0] = '\0'; Lf->inp_ty = 0; - (void)process_socket(ka); + (void)process_socket(ctx, ka); return; } /* diff --git a/lib/dialects/aix/dproc.c b/lib/dialects/aix/dproc.c index 81949ad9..df83c8b5 100644 --- a/lib/dialects/aix/dproc.c +++ b/lib/dialects/aix/dproc.c @@ -34,6 +34,12 @@ static char copyright[] = #endif #include "common.h" +#include + +#if defined(SIGDANGER) +/* Static context pointer for signal handler */ +static struct lsof_context *signal_ctx = NULL; +#endif static void get_kernel_access(struct lsof_context *ctx); @@ -45,7 +51,7 @@ static struct le *getle(struct lsof_context *ctx, KA_T a, KA_T sid, char **err); static void getlenm(struct lsof_context *ctx, struct le *le, KA_T sid); #endif /* AIXV>=4110 */ -static int kreadx(KA_T addr, char *buf, int len, KA_T sid); +static int kreadx(struct lsof_context *ctx, KA_T addr, char *buf, int len, KA_T sid); #if AIXA < 2 static void process_text(struct lsof_context *ctx, KA_T sid); @@ -56,9 +62,9 @@ static void process_text(struct lsof_context *ctx, pid_t pid); #if defined(SIGDANGER) # if defined(HASINTSIGNAL) -static int lowpgsp(struct lsof_context *ctx, int sig); +static int lowpgsp(int sig); # else /* !defined(HASINTSIGNAL) */ -static void lowpgsp(struct lsof_context *ctx, int sig); +static void lowpgsp(int sig); # endif /* defined(HASINTSIGNAL) */ #endif /* defined(SIGDANGER) */ @@ -487,7 +493,7 @@ void gather_proc_info(struct lsof_context *ctx) { */ # if AIXV >= 4110 - if (Fxopt && kreadx(Uo, (char *)Up, U_SIZE, (KA_T)p->pi_adspace) == 0) + if (Fxopt && kreadx(ctx, Uo, (char *)Up, U_SIZE, (KA_T)p->pi_adspace) == 0) i = 1; else i = 0; @@ -574,7 +580,7 @@ void gather_proc_info(struct lsof_context *ctx) { /* * Read the AIX 4.3.3 U_loader pointers. */ - if (kreadx((KA_T)((char *)Uo + offsetof(struct user, U_loader) + + if (kreadx(ctx, (KA_T)((char *)Uo + offsetof(struct user, U_loader) + uo), (char *)&Up->U_loader, sizeof(struct la), (KA_T)p->pi_adspace)) @@ -594,7 +600,7 @@ void gather_proc_info(struct lsof_context *ctx) { * user structs, so the U_loader offset should be the same as * the U_maxofile offset. */ - if (!kreadx((KA_T)((char *)Uo + + if (!kreadx(ctx, (KA_T)((char *)Uo + offsetof(struct user, U_maxofile) + uo), (char *)&mxof, sizeof(mxof), (KA_T)p->pi_adspace) && (mxof == p->pi_maxofile)) { @@ -619,7 +625,7 @@ void gather_proc_info(struct lsof_context *ctx) { } # else /* AIXV!=4330 */ if (Fxopt && - kreadx((KA_T)((char *)Uo + offsetof(struct user, U_loader)), + kreadx(ctx, (KA_T)((char *)Uo + offsetof(struct user, U_loader)), (char *)&Up->U_loader, sizeof(struct la), (KA_T)p->pi_adspace) == 0) hl = 1; @@ -864,7 +870,7 @@ static void get_kernel_access(struct lsof_context *ctx) { if (nlist(N_UNIX, ll) == 0 && ll[0].n_value != (long)0 && ll[1].n_value != (long)0 && - kreadx((KA_T)(ll[1].n_value & RDXMASK), (char *)&Soff, sizeof(Soff), + kreadx(ctx, (KA_T)(ll[1].n_value & RDXMASK), (char *)&Soff, sizeof(Soff), (KA_T)0) == 0) Soff_stat++; # endif /* AIXA<2 */ @@ -882,7 +888,9 @@ static void get_kernel_access(struct lsof_context *ctx) { #if defined(SIGDANGER) /* * If SIGDANGER is defined, enable its handler. + * Store context in static variable for signal handler to use. */ + signal_ctx = ctx; (void)signal(SIGDANGER, lowpgsp); #endif /* defined(SIGDANGER) */ } @@ -918,11 +926,11 @@ static struct le *getle(struct lsof_context *ctx, /* context */ if (!kread(ctx, a, (char *)&le, sizeof(le))) return (&le); } else { - if (!kreadx((KA_T)(a & RDXMASK), (char *)&le, sizeof(le), (KA_T)sid)) + if (!kreadx(ctx, (KA_T)(a & RDXMASK), (char *)&le, sizeof(le), (KA_T)sid)) return (&le); } # else /* AIXV<4110 */ - if (!kreadx((KA_T)a, (char *)&le, sizeof(le), (KA_T)sid)) + if (!kreadx(ctx, (KA_T)a, (char *)&le, sizeof(le), (KA_T)sid)) return (&le); # endif /* AIXV>=4110 */ @@ -955,7 +963,7 @@ static void getlenm(struct lsof_context *ctx, /* context */ return; } else { if (!Soff_stat || !le->nm || - kreadx((KA_T)le->nm & (KA_T)RDXMASK, buf, LIBNMLN, (KA_T)Soff)) + kreadx(ctx, (KA_T)le->nm & (KA_T)RDXMASK, buf, LIBNMLN, (KA_T)Soff)) return; } buf[LIBNMLN - 1] = '\0'; @@ -1091,6 +1099,35 @@ static void getsoinfo() { */ void initialize(struct lsof_context *ctx) { + /* Initialize name list for knlist() */ + static struct nlist nl[] = { +#if AIXV < 4100 + {"u", 0, 0, 0, 0, 0}, +#else /* AIXV>=4100 */ + {"__ublock", 0, 0, 0, 0, 0}, +#endif /* AIXV<4100 */ + {NULL, 0, 0, 0, 0, 0} /* Terminator */ + }; + + ctx->name_list = nl; + ctx->name_list_size = sizeof(nl) / sizeof(nl[0]) - 1; /* Exclude terminator */ + + /* Initialize dialect-specific context fields */ + ctx->dialect.kd = -1; + ctx->dialect.km = -1; + ctx->dialect.lvfs = NULL; + ctx->dialect.mtab = NULL; + +#if AIXV >= 4140 + ctx->dialect.clone = NULL; + ctx->dialect.clone_maj = -1; + ctx->dialect.clone_ptc = -1; +#endif /* AIXV>=4140 */ + +#if defined(HAS_AFS) + ctx->dialect.afs_vfsp = (KA_T)NULL; +#endif /* defined(HAS_AFS) */ + get_kernel_access(ctx); #if AIXA > 1 @@ -1124,10 +1161,11 @@ int kread(struct lsof_context *ctx, /* context */ * kreadx() - read kernel segmented memory */ -int kreadx(KA_T addr, /* kernel address */ - char *buf, /* destination buffer */ - int len, /* length */ - KA_T sid) /* segment ID */ +int kreadx(struct lsof_context *ctx, /* context */ + KA_T addr, /* kernel address */ + char *buf, /* destination buffer */ + int len, /* length */ + KA_T sid) /* segment ID */ { int br; @@ -1144,7 +1182,10 @@ int kreadx(KA_T addr, /* kernel address */ #if defined(SIGDANGER) /* - * lowpgsp() - hangle a SIGDANGER signal about low paging space + * lowpgsp() - handle a SIGDANGER signal about low paging space + * + * Note: Signal handlers cannot take a context parameter, so we use a + * static pointer set in get_kernel_access(). */ # if defined(HASINTSIGNAL) @@ -1153,9 +1194,15 @@ static int static void # endif /* defined(HASINTSIGNAL) */ -lowpgsp(struct lsof_context *ctx, int sig) { - (void)fprintf(stderr, "%s: FATAL: system paging space is low.\n", Pn); - Error(ctx); +lowpgsp(int sig) { + if (signal_ctx && signal_ctx->err) { + (void)fprintf(signal_ctx->err, "%s: FATAL: system paging space is low.\n", + signal_ctx->program_name ? signal_ctx->program_name : "lsof"); + } + if (signal_ctx) { + Error(signal_ctx); + } + exit(LSOF_EXIT_ERROR); } #endif /* defined(SIGDANGER) */ diff --git a/lib/dialects/aix/dproto.h b/lib/dialects/aix/dproto.h index 70b15685..b4d57784 100644 --- a/lib/dialects/aix/dproto.h +++ b/lib/dialects/aix/dproto.h @@ -50,7 +50,7 @@ extern int readj2lino(struct lsof_context *ctx, struct gnode *ga, struct l_ino * extern int getchan(char *p); extern int is_file_named(struct lsof_context *ctx, char *p, enum vtype ty, chan_t ch, int ic); -extern char isglocked(struct lsof_context *ctx, struct gnode *ga); +extern enum lsof_lock_mode isglocked(struct lsof_context *ctx, struct gnode *ga); extern int readlino(struct lsof_context *ctx, struct gnode *ga, struct l_ino *li); extern struct l_vfs *readvfs(struct lsof_context *ctx, struct vnode *vn); diff --git a/lib/dialects/aix/dstore.c b/lib/dialects/aix/dstore.c index 11d6ff06..f9bb2514 100644 --- a/lib/dialects/aix/dstore.c +++ b/lib/dialects/aix/dstore.c @@ -49,31 +49,8 @@ struct nlist AFSnl[] = { char *AFSApath = (char *)NULL; /* alternate AFS name list path * (from -a) */ # endif /* defined(HASAOPT) */ - -KA_T AFSVfsp = (KA_T)NULL; /* AFS vfs struct kernel address */ #endif /* defined(HAS_AFS) */ -#if AIXV >= 4140 -struct clone *Clone = (struct clone *)NULL; -/* local clone information */ -int CloneMaj = -1; /* clone major device number */ -int ClonePtc = -1; /* /dev/ptc minor device number */ -#endif /* AIXV>=4140 */ - -int Kd = -1; /* /dev/kmem file descriptor */ -struct l_vfs *Lvfs = NULL; /* local vfs structure table */ -int Km = -1; /* /dev/mem file descriptor */ - -struct nlist Nl[] = { - -#if AIXV < 4100 - {"u", 0, 0, 0, 0, 0}, -#else /* AIXV>=4100 */ - {"__ublock", 0, 0, 0, 0, 0}, -#endif /* AIXV<4100 */ - -}; - #if defined(HASFSTRUCT) /* * Pff_tab[] - table for printing file flags diff --git a/lib/dialects/aix/machine.h b/lib/dialects/aix/machine.h index 75434da0..7a5b7f88 100644 --- a/lib/dialects/aix/machine.h +++ b/lib/dialects/aix/machine.h @@ -65,7 +65,19 @@ # include # if AIXA > 0 +/* + * Work around conflict between GCC fixed headers and AIX system headers. + * The global 'time' variable in sys/time.h conflicts with the time() + * function. We rename it during inclusion. + */ +# if defined(__GNUC__) +# include +# define time aix_global_time_variable +# endif # include +# if defined(__GNUC__) +# undef time +# endif # endif /* AIXA>0 */ # if defined(__GNUC__) @@ -292,10 +304,12 @@ typedef long long aligned_offset_t __attribute__((aligned(8))); /* * HASNLIST is defined for those dialects that use nlist() to access - * kernel symbols. (AIX lsof doesn't use nlist, it uses knlist.) + * kernel symbols. AIX uses knlist() which is similar. */ -/* #define HASNLIST 1 */ +#define HASNLIST 1 +#define NLIST_TYPE nlist +#define NL_NAME n_name /* * HASPIPEFN is defined for those dialects that have a special function to