From b711e5d84188ac372d1abf724a20c02da9428893 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sat, 4 Jan 2025 19:40:14 +0000 Subject: [PATCH] Restore build on old systems without openat(2) (re: 3d7b7e19) The openat system call was standardised by POSIX in 2008, which is still too recent for it to be portable on systems older than a decade or so. I have two old systems that it breaks on. src/lib/libast/features/lib: - Add simple lib test for openat(2), defining _lib_openat if found. This will be available wherever is included. src/cmd/ksh93/*/*.[ch]: - Restore the tried-and-tested cd_pwd.c and subshell.c code from before the referenced commit as a fallback for systems that don't have openat(2), i.e.: it is used #if !_lib_openat. - However, the even older pre-fchdir(2) code is not restored. Additionally, a couple of build system workarounds for old systems: src/cmd/INIT/mamake.c: - Do not set fictional future _POSIX_SOURCE and _X_OPEN_SOURCE version macros. The system headers on (at least) QNX 6.5.0 and Solaris 10.1 don't like them. (re: f58153d4) src/cmd/INIT/include/link_ar.mam: - Compensate for the lack of 'ar -s' by falling back to pre-POSIX 'ranlib'. Solaris 10.1 needs this. (re: 2ad0f545) Resolves: https://github.com/ksh93/ksh/issues/816 --- src/cmd/INIT/include/link_ar.mam | 2 +- src/cmd/INIT/mamake.c | 2 -- src/cmd/ksh93/bltins/cd_pwd.c | 23 ++++++++++-- src/cmd/ksh93/include/defs.h | 8 +++-- src/cmd/ksh93/include/shell.h | 2 ++ src/cmd/ksh93/sh/fault.c | 2 ++ src/cmd/ksh93/sh/path.c | 2 ++ src/cmd/ksh93/sh/subshell.c | 60 ++++++++++++++++++++++++++++++++ src/lib/libast/features/lib | 2 +- 9 files changed, 94 insertions(+), 9 deletions(-) diff --git a/src/cmd/INIT/include/link_ar.mam b/src/cmd/INIT/include/link_ar.mam index d10254c23372..c92155d23e59 100644 --- a/src/cmd/INIT/include/link_ar.mam +++ b/src/cmd/INIT/include/link_ar.mam @@ -42,4 +42,4 @@ exec - esac note * Some old systems do not automatically update the symbol table upon ad note * adding or deleting object files (contra POSIX), so update it manually -exec - %{AR} -s %{@} +exec - %{AR} -s %{@} 2>/dev/null || ranlib %{@} 2>/dev/null || true diff --git a/src/cmd/INIT/mamake.c b/src/cmd/INIT/mamake.c index 4b09831977d8..f8c2e997191e 100644 --- a/src/cmd/INIT/mamake.c +++ b/src/cmd/INIT/mamake.c @@ -112,8 +112,6 @@ static const char usage[] = * must be enabled to prevent the build from failing at the very start. */ -#define _POSIX_C_SOURCE 21000101L /* generic */ -#define _XOPEN_SOURCE 9900 /* generic */ #define _DARWIN_C_SOURCE 1 /* macOS */ #define _GNU_SOURCE 1 /* GNU/Linux, Cygwin */ #define _FILE_OFFSET_BITS 64 /* 32-bit Linux 5.6+ (glibc 2.32+) */ diff --git a/src/cmd/ksh93/bltins/cd_pwd.c b/src/cmd/ksh93/bltins/cd_pwd.c index ac4011cf4dfe..f8cd566e6b7a 100644 --- a/src/cmd/ksh93/bltins/cd_pwd.c +++ b/src/cmd/ksh93/bltins/cd_pwd.c @@ -46,6 +46,7 @@ static void rehash(Namval_t *np,void *data) nv_rehash(np,data); } +#if _lib_openat /* * Obtain a file handle to the directory "path" relative to directory "dir" */ @@ -62,6 +63,7 @@ int sh_diropenat(int dir, const char *path) close(fd); return shfd; } +#endif /* _lib_openat */ int b_cd(int argc, char *argv[],Shbltin_t *context) { @@ -70,9 +72,11 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) const char *dp; int saverrno=0; int rval,pflag=0,eflag=0,ret=1; - int newdirfd; char *oldpwd, *cp; Namval_t *opwdnod, *pwdnod; +#if _lib_openat + int newdirfd; +#endif /* _lib_openat */ NOT_USED(context); while((rval = optget(argv,sh_optcd))) switch(rval) { @@ -136,8 +140,13 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) * If sh_subshell() in subshell.c cannot use fchdir(2) to restore the PWD using a saved file descriptor, * we must fork any virtual subshell now to avoid the possibility of ending up in the wrong PWD on exit. */ +#if _lib_openat if(sh.subshell && !sh.subshare && (!sh_validate_subpwdfd() || !test_inode(sh.pwd,e_dot))) sh_subfork(); +#else + if(sh.subshell && !sh.subshare && !test_inode(sh.pwd,e_dot)) + sh_subfork(); +#endif /* _lib_openat */ /* * Do $CDPATH processing, except if the path is absolute or the first component is '.' or '..' */ @@ -157,7 +166,6 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) if(*dir!='/') { /* check for leading .. */ - char *cp; sfprintf(sh.strbuf,"%s",dir); cp = sfstruse(sh.strbuf); pathcanon(cp, 0); @@ -199,6 +207,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) if(!pathcanon(cp,PATH_DOTDOT)) continue; } +#if _lib_openat cp = path_relative(stkptr(sh.stk,PATH_OFFSET)); rval = newdirfd = sh_diropenat((sh.pwdfd>0)?sh.pwdfd:AT_FDCWD,cp); if(newdirfd>0) @@ -217,10 +226,17 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) #endif if(saverrno==0) saverrno=errno; +#else + if((rval=chdir(path_relative(stkptr(sh.stk,PATH_OFFSET)))) >= 0) + goto success; + if(errno!=ENOENT && saverrno==0) + saverrno=errno; +#endif /* _lib_openat */ } while(cdpath); if(rval<0 && *dir=='/' && *(path_relative(stkptr(sh.stk,PATH_OFFSET)))!='/') { +#if _lib_openat rval = newdirfd = sh_diropenat((sh.pwdfd>0)?sh.pwdfd:AT_FDCWD,dir); if(newdirfd>0) { @@ -236,6 +252,9 @@ int b_cd(int argc, char *argv[],Shbltin_t *context) else if((rval=chdir(dir)) >= 0) sh_pwdupdate(sh_diropenat(AT_FDCWD,dir)); #endif +#else + rval = chdir(dir); +#endif /* _lib_openat */ } if(rval<0) { diff --git a/src/cmd/ksh93/include/defs.h b/src/cmd/ksh93/include/defs.h index fa77e71b0937..7e36c885b07e 100644 --- a/src/cmd/ksh93/include/defs.h +++ b/src/cmd/ksh93/include/defs.h @@ -114,7 +114,6 @@ extern char *sh_checkid(char*,char*); extern void sh_chktrap(void); extern void sh_deparse(Sfio_t*,const Shnode_t*,int,int); extern int sh_debug(const char*,const char*,const char*,char *const[],int); -extern int sh_diropenat(int,const char *); extern char **sh_envgen(void); extern Sfdouble_t sh_arith(const char*); extern void *sh_arithcomp(char*); @@ -142,8 +141,6 @@ extern Dt_t *sh_subfuntree(int); extern void sh_subjobcheck(pid_t); extern int sh_subsavefd(int); extern void sh_subtmpfile(void); -extern void sh_pwdupdate(int); -extern int sh_validate_subpwdfd(void); extern char *sh_substitute(const char*,const char*,char*); extern void sh_timetraps(void); extern const char *_sh_translate(const char*); @@ -151,6 +148,11 @@ extern int sh_trace(char*[],int); extern void sh_trim(char*); extern int sh_type(const char*); extern void sh_unscope(void); +#if _lib_openat + extern int sh_diropenat(int,const char *); + extern void sh_pwdupdate(int); + extern int sh_validate_subpwdfd(void); +#endif /* _lib_openat */ #if SHOPT_NAMESPACE extern Namval_t *sh_fsearch(const char *,int); #endif /* SHOPT_NAMESPACE */ diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h index cf642fc244f8..1d87a36c6528 100644 --- a/src/cmd/ksh93/include/shell.h +++ b/src/cmd/ksh93/include/shell.h @@ -372,7 +372,9 @@ struct Shell_s Sfio_t **sftable; unsigned char *fdstatus; char *pwd; +#if _lib_openat int pwdfd; /* file descriptor for pwd */ +#endif /* _lib_openat */ void *jmpbuffer; void *mktype; Sfio_t *strbuf; diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 0de0cd9ebfba..d20df0577cfe 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -687,8 +687,10 @@ noreturn void sh_done(int sig) if(sh_isoption(SH_NOEXEC)) kiaclose((Lex_t*)sh.lex_context); #endif /* SHOPT_KIA */ +#if _lib_openat if(sh.pwdfd > 0) close(sh.pwdfd); +#endif /* _lib_openat */ /* Exit with portable 8-bit status (128 + signum) if last child process exits due to signal */ if(sh.chldexitsig) savxit = savxit & ~SH_EXITSIG | 0200; diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c index 70c0d284e542..9c2bd83a1fa3 100644 --- a/src/cmd/ksh93/sh/path.c +++ b/src/cmd/ksh93/sh/path.c @@ -249,8 +249,10 @@ char *path_pwd(void) if(!tofree) cp = sh_strdup(cp); sh.pwd = cp; +#if _lib_openat /* Set sh.pwdfd */ sh_pwdupdate(sh_diropenat(AT_FDCWD,cp)); +#endif /* _lib_openat */ return sh.pwd; } diff --git a/src/cmd/ksh93/sh/subshell.c b/src/cmd/ksh93/sh/subshell.c index aaf998b0d03c..0137abfeabc0 100644 --- a/src/cmd/ksh93/sh/subshell.c +++ b/src/cmd/ksh93/sh/subshell.c @@ -85,6 +85,9 @@ static struct subshell char rand_state; /* 0 means sp->rand_seed hasn't been set, 1 is the opposite */ uint32_t srand_upper_bound; /* parent shell's upper bound for $SRANDOM */ int pwdfd; /* parent shell's file descriptor for PWD */ +#if !_lib_openat + char pwdclose; +#endif /* !_lib_openat */ } *subshell_data; static unsigned int subenv; @@ -446,6 +449,8 @@ void sh_subjobcheck(pid_t pid) } } +#if _lib_openat + /* * Set the file descriptor for the current shell's PWD without wiping * out the stored file descriptor for the parent shell's PWD. @@ -468,6 +473,8 @@ int sh_validate_subpwdfd(void) return sp->pwdfd > 0; } +#endif /* _lib_openat */ + /* * Run command tree in a virtual subshell * If comsub is not null, then output will be placed in temp file (or buffer) @@ -516,6 +523,10 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) path_get(e_dot); sh.pathinit = 0; } +#if !_lib_openat + if(!sh.pwd) + path_pwd(); +#endif /* !_lib_openat */ sp->bckpid = sh.bckpid; if(comsub) sh_stats(STAT_COMSUB); @@ -531,8 +542,40 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) if(!sh.subshare) { char *save_debugtrap = 0; +#if _lib_openat sp->pwd = sh_strdup(sh.pwd); sp->pwdfd = sh.pwdfd; +#else + struct subshell *xp; + sp->pwdfd = -1; + for(xp=sp->prev; xp; xp=xp->prev) + { + if(xp->pwdfd>0 && xp->pwd && strcmp(xp->pwd,sh.pwd)==0) + { + sp->pwdfd = xp->pwdfd; + break; + } + } + if(sp->pwdfd<0) + { + int n = open(e_dot,O_SEARCH); + if(n>=0) + { + sp->pwdfd = n; + if(n<10) + { + sp->pwdfd = sh_fcntl(n,F_DUPFD,10); + close(n); + } + if(sp->pwdfd>0) + { + fcntl(sp->pwdfd,F_SETFD,FD_CLOEXEC); + sp->pwdclose = 1; + } + } + } + sp->pwd = (sh.pwd?sh_strdup(sh.pwd):0); +#endif /* _lib_openat */ sp->mask = sh.mask; sh_stats(STAT_SUBSHELL); /* save trap table */ @@ -606,6 +649,10 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) if(sh.savesig < 0) { sh.savesig = 0; +#if !_lib_openat + if(sp->pwdfd < 0 && !sh.subshare) /* if we couldn't get a file descriptor to our PWD ... */ + sh_subfork(); /* ...we have to fork, as we cannot fchdir back to it. */ +#endif /* !_lib_openat */ /* Virtual subshells are not safe to suspend (^Z, SIGTSTP) in the interactive main shell. */ if(sh_isstate(SH_INTERACTIVE)) { @@ -789,6 +836,7 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) free(savsig); } sh.options = sp->options; +#if _lib_openat if(sh.pwdfd != sp->pwdfd) { /* @@ -810,6 +858,18 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) if(fatalerror != 2) sh_pwdupdate(sp->pwdfd); } +#else + /* restore the present working directory */ + if(sp->pwdfd > 0 && fchdir(sp->pwdfd) < 0) + { + saveerrno = errno; + fatalerror = 2; + } + else if(sp->pwd && strcmp(sp->pwd,sh.pwd)) + path_newdir(sh.pathlist); + if(sp->pwdclose) + close(sp->pwdfd); +#endif /* _lib_openat */ free(sh.pwd); sh.pwd = sp->pwd; if(sp->mask!=sh.mask) diff --git a/src/lib/libast/features/lib b/src/lib/libast/features/lib index d11a460713a0..c3cdb61a1894 100644 --- a/src/lib/libast/features/lib +++ b/src/lib/libast/features/lib @@ -31,7 +31,7 @@ lib gethostname,getpagesize,getrlimit,getuniverse lib glob,iswblank,iswctype,killpg,link,localeconv,madvise lib mbtowc,mbrtowc,memalign,memdup lib mkdir,mkfifo,mktemp,mktime -lib mount,opendir,pathconf +lib mount,opendir,openat,pathconf lib readlink,remove,rename,rewinddir,rmdir,setlocale lib setpgrp,setpgrp2,setreuid,setuid lib socketpair