Skip to content

Commit

Permalink
Restore build on old systems without openat(2) (re: 3d7b7e1)
Browse files Browse the repository at this point in the history
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 <ast.h> 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: f58153d)
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: 2ad0f54)

Resolves: ksh93#816
  • Loading branch information
McDutchie committed Jan 4, 2025
1 parent d663b7c commit b711e5d
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/cmd/INIT/include/link_ar.mam
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 0 additions & 2 deletions src/cmd/INIT/mamake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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+) */
Expand Down
23 changes: 21 additions & 2 deletions src/cmd/ksh93/bltins/cd_pwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
*/
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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 '..'
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down
8 changes: 5 additions & 3 deletions src/cmd/ksh93/include/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*);
Expand Down Expand Up @@ -142,15 +141,18 @@ 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*);
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 */
Expand Down
2 changes: 2 additions & 0 deletions src/cmd/ksh93/include/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/cmd/ksh93/sh/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/cmd/ksh93/sh/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
60 changes: 60 additions & 0 deletions src/cmd/ksh93/sh/subshell.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -468,6 +473,8 @@ int sh_validate_subpwdfd(void)
return sp->pwdfd > 0;
}

#endif /* _lib_openat */

/*
* Run command tree <t> in a virtual subshell
* If comsub is not null, then output will be placed in temp file (or buffer)
Expand Down Expand Up @@ -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);
Expand All @@ -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 */
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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)
{
/*
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/libast/features/lib
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b711e5d

Please sign in to comment.