ibara / oksh

Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
362 stars 38 forks source link

AIX support #16

Closed NattyNarwhal closed 6 years ago

NattyNarwhal commented 6 years ago

God help me.

diff of portable.h

diff --git a/portable.h b/portable.h
index 7781376..5806de4 100644
--- a/portable.h
+++ b/portable.h
@@ -123,6 +123,13 @@
         } while (0)
 #endif /* !__OpenBSD__ */

+#ifdef _AIX
+typedef       void (*sig_t)(int);
+
+#define VWERASE VWERSE
+#define VDISCARD VDISCRD
+#endif
+
 /*
  * Prototypes
  */

current error

$ gmake
gcc -DEMACS -DVI -w   -c -o edit.o edit.c
gcc -DEMACS -DVI -w   -c -o emacs.o emacs.c
emacs.c:78:27: error: invalid initializer
 struct kb_list   kblist = TAILQ_HEAD_INITIALIZER(kblist);
                           ^~~~~~~~~~~~~~~~~~~~~~
emacs.c: In function 'x_emacs':
emacs.c:332:30: error: 'entry' undeclared (first use in this function)
    TAILQ_FOREACH(k, &kblist, entry) {
                              ^~~~~
emacs.c:332:30: note: each undeclared identifier is reported only once for each function it appears in
emacs.c:332:37: error: expected ';' before '{' token
    TAILQ_FOREACH(k, &kblist, entry) {
                                     ^
emacs.c: In function 'kb_find_hist_func':
emacs.c:867:28: error: 'entry' undeclared (first use in this function)
  TAILQ_FOREACH(k, &kblist, entry)
                            ^~~~~
emacs.c:868:3: error: expected ';' before 'if'
   if (!strcmp(k->seq, line))
   ^~
emacs.c: In function 'kb_match':
emacs.c:1275:28: error: 'entry' undeclared (first use in this function)
  TAILQ_FOREACH(k, &kblist, entry) {
                            ^~~~~
emacs.c:1275:35: error: expected ';' before '{' token
  TAILQ_FOREACH(k, &kblist, entry) {
                                   ^
emacs.c: In function 'x_bind':
emacs.c:1390:29: error: 'entry' undeclared (first use in this function)
   TAILQ_FOREACH(k, &kblist, entry)
                             ^~~~~
emacs.c:1391:4: error: expected ';' before 'kb_print'
    kb_print(k);
    ^~~~~~~~
emacs.c:1399:4: error: expected ';' before 'if'
    if (!strcmp(k->seq, in)) {
    ^~
emacs.c:1410:4: error: expected ';' before 'if'
    if (!strcmp(k->seq, in)) {
    ^~
emacs.c:1421:4: error: expected ';' before 'if'
    if (!strcmp(k->seq, in)) {
    ^~
emacs.c:1436:5: error: expected ';' before 'if'
     if (!strcmp(k->seq, in)) {
     ^~
gmake: *** [<builtin>: emacs.o] Error 1

system

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/opt/freeware/libexec/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/lto-wrapper
Target: powerpc-ibm-aix6.1.0.0
Configured with: ../gcc-6.4.0/configure --prefix=/opt/freeware --mandir=/opt/freeware/man --infodir=/opt/freeware/info --with-local-prefix=/opt/freeware --with-as=/usr/bin/as --with-ld=/usr/bin/ld --enable-languages=c,c++,fortran,objc,obj-c++ --enable-version-specific-runtime-libs --disable-nls --enable-decimal-float=dpd --with-cloog=no --with-ppl=no --disable-libstdcxx-pch --enable-__cxa_atexit --host=powerpc-ibm-aix6.1.0.0
Thread model: aix
gcc version 6.4.0 (GCC)
$ uname -rvs
AIX 1 6
ibara commented 6 years ago

Looks like AIX needs BSD queuing? Try changing:

#if defined(__linux__)

to

#if defined(__linux__) || defined(_AIX)

in portable.h line 182.

NattyNarwhal commented 6 years ago

Yes, that was obvious in retrospect, silly me :)

now:

gcc -DEMACS -DVI -w   -c -o expr.o expr.c
In file included from portable.h:21:0,
                 from config.h:28,
                 from sh.h:9,
                 from expr.c:14:
expr.c:42:17: error: expected identifier before '(' token
  VAR, LIT, END, BAD
                 ^
gmake: *** [<builtin>: expr.o] Error 1

those tokens are so simple looking something's bound to be conflicting...

NattyNarwhal commented 6 years ago

warmer...

gcc -DEMACS -DVI -w   -c -o history.o history.c
history.c: In function 'histsave':
history.c:667:16: error: 'LOCK_EX' undeclared (first use in this function)
   history_lock(LOCK_EX);
                ^~~~~~~
history.c:667:16: note: each undeclared identifier is reported only once for each function it appears in
In file included from config.h:28:0,
                 from sh.h:9,
                 from history.c:25:
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:111:12: note: in definition of macro 'timespeccmp'
         (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
            ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:111:29: note: in definition of macro 'timespeccmp'
         (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
                             ^~~
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:112:15: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
               ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:112:34: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
                                  ^~~
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:113:15: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_sec cmp (usp)->tv_sec))
               ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:113:33: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_sec cmp (usp)->tv_sec))
                                 ^~~
history.c:702:16: error: 'LOCK_UN' undeclared (first use in this function)
   history_lock(LOCK_UN);
                ^~~~~~~
history.c: In function 'hist_init':
history.c:822:15: error: 'LOCK_UN' undeclared (first use in this function)
  history_lock(LOCK_UN);
               ^~~~~~~
gmake: *** [<builtin>: history.o] Error 1
NattyNarwhal commented 6 years ago

So it looks like

  1. flock issue is simple; flock lives in sys/file.c instead

  2. AIX struct stat doesn't have a timespec which complicates a function in history.c? Looks like -DSMALL can make it something we don't need to deal with, but is that wise?

NattyNarwhal commented 6 years ago

if I do set that, it'll work, but then

gcc -DSMALL -DEMACS -DVI -w   -c -o io.o io.c
io.c: In function 'savefd':
io.c:262:19: error: 'F_DUPFD_CLOEXEC' undeclared (first use in this function)
   nfd = fcntl(fd, F_DUPFD_CLOEXEC, FDBASE);
                   ^~~~~~~~~~~~~~~
io.c:262:19: note: each undeclared identifier is reported only once for each function it appears in

are the semantics on OpenBSD at least, close enough that it could be aliased to F_DUPFD?

NattyNarwhal commented 6 years ago

Looking at the OpenBSD diff.... yes, but with small surgery to io.c. I don't think that'd be acceptable though?

NattyNarwhal commented 6 years ago

Now it compiles, with some hacks later:

diff --git a/configure b/configure
index 592ca6e..1efd2e6 100755
--- a/configure
+++ b/configure
@@ -409,6 +409,10 @@ if [ "x$os" = "xLinux" ] ; then
 elif [ "x$os" = "xNetBSD" ] ; then
   tflags="-D_OPENBSD_SOURCE"
   cflags="$cflags $tflags"
+elif [ "x$os" = "xAIX" ] ; then
+# AIX doesn't have timespec in stat, but SMALL lets us not do that
+  cflags="$cflags -DSMALL"
+  ldflags="$ldflags -lbsd"
 else
   tflags=""
 fi
diff --git a/io.c b/io.c
index 5d8f156..3902451 100644
--- a/io.c
+++ b/io.c
@@ -259,7 +259,7 @@ savefd(int fd)
        int nfd;

        if (fd < FDBASE) {
-               nfd = fcntl(fd, F_DUPFD_CLOEXEC, FDBASE);
+               nfd = fcntl(fd, F_DUPFD, FDBASE);
                if (nfd < 0) {
                        if (errno == EBADF)
                                return -1;
@@ -270,6 +270,7 @@ savefd(int fd)
                nfd = fd;
                fcntl(nfd, F_SETFD, FD_CLOEXEC);
        }
+       fcntl(nfd, F_SETFD, FD_CLOEXEC);
        return nfd;
 }

diff --git a/portable.h b/portable.h
index 7781376..be77fff 100644
--- a/portable.h
+++ b/portable.h
@@ -123,6 +123,54 @@
         } while (0)
 #endif /* !__OpenBSD__ */

+#ifdef _AIX
+/* AIX doesn't have this */
+typedef       void (*sig_t)(int);
+
+/* IBM cheaped out on vowels */
+#define VWERASE VWERSE
+#define VDISCARD VDISCRD
+
+/* what the hell defines this? */
+#undef BAD
+
+/* flock isn't where you expect */
+#include <sys/file.h>
+
+/* AIX doesn't have this either */
+#define MAXLOGNAME LOGIN_NAME_MAX
+
+/* or this, but we can approximate it? */
+#define _PATH_DEFPATH "/usr/bin:/etc:/usr/sbin:/usr/ucb:/usr/bin/X11:/sbin"
+
+/* terrible idea */
+#define asprintf sprintf
+
+/* copy OpenBSD's WCOREDUMP def here */
+#define WCOREFLAG       0200
+#define WCOREDUMP(x)    ((x) & WCOREFLAG)
+
+/* import timeadd/sub funcs from OpenBSD sys/time.h */
+#define        timeradd(tvp, uvp, vvp)                                         \
+       do {                                                            \
+               (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
+               (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
+               if ((vvp)->tv_usec >= 1000000) {                        \
+                       (vvp)->tv_sec++;                                \
+                       (vvp)->tv_usec -= 1000000;                      \
+               }                                                       \
+       } while (0)
+#define        timersub(tvp, uvp, vvp)                                         \
+       do {                                                            \
+               (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;          \
+               (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;       \
+               if ((vvp)->tv_usec < 0) {                               \
+                       (vvp)->tv_sec--;                                \
+                       (vvp)->tv_usec += 1000000;                      \
+               }                                                       \
+       } while (0)
+#endif
+
 /*
  * Prototypes
  */
@@ -179,7 +227,7 @@ extern const char *const sys_signame[NSIG];

 /* The following should only be necessary on non-BSD systems.  */

-#if defined(__linux__)
+#if defined(__linux__) || defined(_AIX)

 /*     $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $        */
 /*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
diff --git a/tty.c b/tty.c
index 648bdb7..89be883 100644
--- a/tty.c
+++ b/tty.c
@@ -49,9 +49,14 @@ tty_init(int init_ttystate)
                        return;
                }
        }
-       if ((tty_fd = fcntl(tfd, F_DUPFD_CLOEXEC, FDBASE)) < 0) {
+       if ((tty_fd = fcntl(tfd, F_DUPFD, FDBASE)) < 0) {
                warningf(false, "j_ttyinit: dup of tty fd failed: %s",
                    strerror(errno));
+       } else if (fcntl(tty_fd, F_SETFD, FD_CLOEXEC) < 0) {
+               warningf(false, "j_ttyinit: can't set close-on-exec flag: %s",
+                   strerror(errno));
+               close(tty_fd);
+               tty_fd = -1;
        } else if (init_ttystate)
                tcgetattr(tty_fd, &tty_state);
        if (do_close)
NattyNarwhal commented 6 years ago

well, it's not entirely stable:

(gdb) run
Starting program: /home/calvin/oksh/oksh
aix$ cat CO<tab>
Program received signal SIGSEGV, Segmentation fault.
0x10025f00 in skip_varname ()
(gdb) bt
#0  0x10025f00 in skip_varname ()
#1  0x10023be0 in array_index_calc ()
#2  0x10023da8 in global ()
#3  0x1003a3c4 in x_try_array ()
#4  0x1003a758 in x_cf_glob ()
#5  0x10036dfc in do_complete ()
#6  0x10036b88 in x_comp_list ()
#7  0x10031e10 in x_emacs ()
#8  0x10038580 in x_read ()
#9  0x1001e7f8 in getsc_line ()
#10 0x1001e2d8 in getsc__ ()
#11 0x10020768 in getsc_bn ()
#12 0x1001ade0 in yylex ()
#13 0x10045908 in get_command ()
#14 0x10045064 in pipeline ()
#15 0x100451d0 in andor ()
#16 0x10045304 in c_list ()
#17 0x10044f5c in yyparse ()
#18 0x10047a2c in compile ()
#19 0x10001b18 in shell ()
#20 0x100013ec in main ()
ibara commented 6 years ago

Definitely don't set -DSMALL for the final diff. That won't do what you want. Let me look this over. I have some ideas.

NattyNarwhal commented 6 years ago

FWIW, a better gdb session output with -g -O0:

(gdb) run
Starting program: /home/calvin/oksh/oksh
aix$ cat CO
Program received signal SIGSEGV, Segmentation fault.
0x10025f00 in skip_varname (
    s=0x636f6d70 <error: Cannot access memory at address 0x636f6d70>, aok=0)
    at var.c:775
775             if (s && letter(*s)) {
(gdb) info locals
alen = 274877907
(gdb) bt
#0  0x10025f00 in skip_varname (
    s=0x636f6d70 <error: Cannot access memory at address 0x636f6d70>, aok=0)
    at var.c:775
#1  0x10023be0 in array_index_calc (
    n=0x636f6d70 <error: Cannot access memory at address 0x636f6d70>,
    arrayp=0x2ff20f4c, valp=0x2ff20f50) at var.c:136
#2  0x10023da8 in global (
    n=0x636f6d70 <error: Cannot access memory at address 0x636f6d70>)
    at var.c:171
#3  0x1003a3c4 in x_try_array (buf=0x2000f910 "cat CO", buflen=6,
    want=0x2000f914 "CO", wantlen=2, nwords=0x2ff2102c, words=0x2ff21030)
    at edit.c:620
#4  0x1003a758 in x_cf_glob (flags=3, buf=0x2000f910 "cat CO", buflen=6,
    pos=6, startp=0x2ff2109c, endp=0x2ff210a0, wordsp=0x2ff21098,
    is_commandp=0x2ff210a4) at edit.c:677
#5  0x10036dfc in do_complete (flags=3, type=CT_COMPLIST) at emacs.c:1721
#6  0x10036b88 in x_comp_list (c=9) at emacs.c:1676
#7  0x10031e10 in x_emacs (buf=0x2000f910 "cat CO", len=4096) at emacs.c:356
#8  0x10038580 in x_read (buf=0x2000f910 "cat CO", len=4096) at edit.c:102
#9  0x1001e7f8 in getsc_line (s=0x2000e010) at lex.c:1099
#10 0x1001e2d8 in getsc__ () at lex.c:988
#11 0x10020768 in getsc_bn () at lex.c:1633
#12 0x1001ade0 in yylex (cf=44) at lex.c:167
#13 0x10045908 in get_command (cf=0) at syn.c:206
#14 0x10045064 in pipeline (cf=0) at syn.c:77
#15 0x100451d0 in andor () at syn.c:98
#16 0x10045304 in c_list (multi=0) at syn.c:118
#17 0x10044f5c in yyparse () at syn.c:64
#18 0x10047a2c in compile (s=0x2000e010) at syn.c:763
#19 0x10001b18 in shell (s=0x2000e010, toplevel=1) at main.c:607
#20 0x100013ec in main (argc=1, argv=0x2ff22c60) at main.c:434
edelsohn commented 6 years ago

/usr/include/sys/param.h: #define BAD (-1)

tssva commented 6 years ago

@NattyNarwhal I took some of the changes you made for this porting effort and spun them out because they will apply to multiple potential port targets. See PR #18. I have an AIX branch on my fork, https://github.com/tssva/oksh, which then also integrates the more AIX specific changes you made. There are a couple of differences to what you tried earlier. The first is that I brought in an implementation of asprintf as part of PR #18 so it is no longer defined as sprintf. Also the AIX version of <sys/time.h> does have an implementation of timespec, but _XOPEN_SOURCE must be set >= 500 for it to be used. I have set -D_XOPEN_SOURCE=500 as a CFLAG in the configure script, so setting -DSMALL should hopefully not be necessary.

The thing is I don't actually have access to an AIX machine. If you could give it a go and see if it fairs any better I would appreciate it.

NattyNarwhal commented 6 years ago

@tssva I tried your repo's AIX branch; can't compile as I get a really long string of errors with gcc6:

checking for C compiler... gcc
checking for -w compiler flag... yes
checking for OS... AIX
checking for __dead... no
checking for __dead2... no
checking for asprintf... no
checking for confstr... yes
checking for pledge... no
checking for reallocarray... no
checking for setresgid... no
checking for setresuid... no
checking for sig_t... no
checking for srand_deterministic... no
checking for stravis... no
checking for strlcat... no
checking for strlcpy... no
checking for strtonum... no
checking for strunvis... no
checking for sys_siglist... no
checking for sys_signame... no
checking for timeradd... no
checking for timersub... no
creating Makefile... done
gcc -DEMACS -DVI -w -D_BSD=44 -D_XOPEN_SOURCE=500   -c -o alloc.o alloc.c
In file included from config.h:28:0,
                 from sh.h:9,
                 from alloc.c:12:
portable.h: In function 'asprintf':
portable.h:210:26: error: storage class specified for parameter 'sys_siglist'
 extern const char *const sys_siglist[NSIG];
                          ^~~~~~~~~~~
portable.h:213:26: error: storage class specified for parameter 'sys_signame'
 extern const char *const sys_signame[NSIG];
                          ^~~~~~~~~~~
portable.h:222:16: error: storage class specified for parameter 'sig_t'
 typedef void (*sig_t)(int);
                ^~~~~
In file included from sh.h:14:0,
                 from alloc.c:12:
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:64:17: error: storage class specified for parameter 'jmp_buf'
 typedef __MTYPE jmp_buf[_JBLEN];
                 ^~~~~~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:82:30: error: expected ')' before 'int'
 extern void longjmp(jmp_buf, int);
                              ^~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:83:12: error: storage class specified for parameter 'setjmp'
 extern int setjmp(jmp_buf);
            ^~~~~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:97:17: error: storage class specified for parameter 'sigjmp_buf'
 typedef __MTYPE sigjmp_buf[_JBLEN];
                 ^~~~~~~~~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:107:34: error: expected ')' before 'int'
 extern int sigsetjmp(sigjmp_buf, int);
                                  ^~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:108:36: error: expected ')' before 'int'
 extern void siglongjmp(sigjmp_buf, int);
                                    ^~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:110:12: error: storage class specified for parameter '_setjmp'
 extern int _setjmp(jmp_buf);
            ^~~~~~~
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include-fixed/setjmp.h:111:31: error: expected ')' before 'int'
 extern void _longjmp(jmp_buf, int);
                               ^~~
In file included from sh.h:15:0,
                 from alloc.c:12:
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include/stdarg.h:40:27: error: storage class specified for parameter '__gnuc_va_list'
 typedef __builtin_va_list __gnuc_va_list;
                           ^~~~~~~~~~~~~~
In file included from sh.h:15:0,
                 from alloc.c:12:
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include/stdarg.h:99:24: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'va_list'
 typedef __gnuc_va_list va_list;
                        ^~~~~~~
In file included from sh.h:16:0,
                 from alloc.c:12:
/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/6.4.0/include/stddef.h:429:3: error: storage class specified for parameter 'max_align_t'
 } max_align_t;
   ^~~~~~~~~~~
In file included from alloc.c:12:0:
sh.h:39:20: error: storage class specified for parameter 'kshname'
 extern const char *kshname; /* $0 */
                    ^~~~~~~
sh.h:40:14: error: storage class specified for parameter 'kshpid'
 extern pid_t kshpid;  /* $$, shell pid */
              ^~~~~~
sh.h:41:14: error: storage class specified for parameter 'procpid'
 extern pid_t procpid; /* pid of executing process */
              ^~~~~~~
sh.h:42:14: error: storage class specified for parameter 'ksheuid'
 extern uid_t ksheuid; /* effective uid of shell */
              ^~~~~~~
sh.h:43:12: error: storage class specified for parameter 'exstat'
 extern int exstat;  /* exit status */
            ^~~~~~
sh.h:44:12: error: storage class specified for parameter 'subst_exstat'
 extern int subst_exstat; /* exit status of last $(..)/`..` */
            ^~~~~~~~~~~~
sh.h:45:20: error: storage class specified for parameter 'safe_prompt'
 extern const char *safe_prompt; /* safe prompt if PS1 substitution fails */
                    ^~~~~~~~~~~
sh.h:46:13: error: storage class specified for parameter 'username'
 extern char username[]; /* username for \u prompt expansion */
             ^~~~~~~~
sh.h:53:3: error: storage class specified for parameter 'Area'
 } Area;
   ^~~~
sh.h:55:13: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'aperm'
 extern Area aperm;  /* permanent object space */
             ^~~~~
sh.h:75:2: error: expected specifier-qualifier-list before 'Area'
  Area area;   /* temporary allocation area */
  ^~~~
sh.h:82:20: error: storage class specified for parameter 'genv'
 extern struct env *genv;
                    ^~~~
sh.h:128:28: error: storage class specified for parameter 'sh_options'
 extern const struct option sh_options[];
                            ^~~~~~~~~~
sh.h:181:13: error: storage class specified for parameter 'shell_flags'
 extern char shell_flags[FNFLAGS];
             ^~~~~~~~~~~
sh.h:183:13: error: storage class specified for parameter 'null'
 extern char null[]; /* null value for variable */
             ^~~~
sh.h:189:24: error: storage class specified for parameter 'Temp_type'
 typedef enum temp_type Temp_type;
                        ^~~~~~~~~
sh.h:195:2: error: expected specifier-qualifier-list before 'Temp_type'
  Temp_type type;
  ^~~~~~~~~
sh.h:206:12: error: storage class specified for parameter 'shl_stdout_ok'
 extern int shl_stdout_ok;
            ^~~~~~~~~~~~~
sh.h:218:2: error: expected specifier-qualifier-list before 'sig_t'
  sig_t cursig;  /* current handler (valid if TF_ORIG_* set) */
  ^~~~~
sh.h:220:3: error: storage class specified for parameter 'Trap'
 } Trap;
   ^~~~
sh.h:247:30: error: storage class specified for parameter 'trap'
 extern volatile sig_atomic_t trap; /* traps pending? */
                              ^~~~
sh.h:248:30: error: storage class specified for parameter 'intrsig'
 extern volatile sig_atomic_t intrsig; /* pending trap interrupts command */
                              ^~~~~~~
sh.h:249:30: error: storage class specified for parameter 'fatal_trap'
 extern volatile sig_atomic_t fatal_trap; /* received a fatal signal */
                              ^~~~~~~~~~
sh.h:250:30: error: storage class specified for parameter 'got_sigwinch'
 extern volatile sig_atomic_t got_sigwinch;
                              ^~~~~~~~~~~~
sh.h:251:13: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'sigtraps'
 extern Trap sigtraps[NSIG+1];
             ^~~~~~~~
sh.h:262:21: error: storage class specified for parameter 'ksh_tmout'
 extern unsigned int ksh_tmout;
                     ^~~~~~~~~
sh.h:263:24: error: storage class specified for parameter 'ksh_tmout_state'
 extern enum tmout_enum ksh_tmout_state;
                        ^~~~~~~~~~~~~~~
sh.h:266:12: error: storage class specified for parameter 'really_exit'
 extern int really_exit;
            ^~~~~~~~~~~
sh.h:281:14: error: storage class specified for parameter 'ctypes'
 extern short ctypes [];
              ^~~~~~
sh.h:288:12: error: storage class specified for parameter 'ifs0'
 extern int ifs0; /* for "$*" */
            ^~~~
sh.h:310:3: error: storage class specified for parameter 'Getopt'
 } Getopt;
   ^~~~~~
sh.h:312:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'builtin_opt'
 extern Getopt builtin_opt; /* for shell builtin commands */
               ^~~~~~~~~~~
sh.h:313:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'user_opt'
 extern Getopt user_opt;  /* parsing state for getopts builtin command */
               ^~~~~~~~
sh.h:317:13: error: storage class specified for parameter 'Coproc_id'
 typedef int Coproc_id; /* something that won't (realistically) wrap */
             ^~~~~~~~~
sh.h:322:2: error: expected specifier-qualifier-list before 'Coproc_id'
  Coproc_id id;  /* id of current output pipe */
  ^~~~~~~~~
sh.h:326:22: error: storage class specified for parameter 'coproc'
 extern struct coproc coproc;
                      ^~~~~~
sh.h:329:18: error: storage class specified for parameter 'sm_default'
 extern sigset_t  sm_default, sm_sigchld;
                  ^~~~~~~~~~
sh.h:329:30: error: storage class specified for parameter 'sm_sigchld'
 extern sigset_t  sm_default, sm_sigchld;
                              ^~~~~~~~~~
sh.h:331:19: error: storage class specified for parameter 'ksh_version'
 extern const char ksh_version[];
                   ^~~~~~~~~~~
sh.h:334:14: error: storage class specified for parameter 'builtin_argv0'
 extern char *builtin_argv0;
              ^~~~~~~~~~~~~
sh.h:335:12: error: storage class specified for parameter 'builtin_flag'
 extern int builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
            ^~~~~~~~~~~~
sh.h:338:14: error: storage class specified for parameter 'current_wd'
 extern char *current_wd;
              ^~~~~~~~~~
sh.h:339:12: error: storage class specified for parameter 'current_wd_size'
 extern int current_wd_size;
            ^~~~~~~~~~~~~~~
sh.h:348:12: error: storage class specified for parameter 'x_cols'
 extern int x_cols; /* tty columns */
            ^~~~~~
In file included from sh.h:366:0,
                 from alloc.c:12:
shf.h:54:2: error: expected specifier-qualifier-list before 'Area'
  Area *areap;  /* area shf/buf were allocated in */
  ^~~~
shf.h:57:19: error: storage class specified for parameter 'shf_iob'
 extern struct shf shf_iob[];
                   ^~~~~~~
shf.h:77:50: error: unknown type name 'va_list'
 int     shf_vfprintf(struct shf *, const char *, va_list);
                                                  ^~~~~~~
In file included from sh.h:367:0,
                 from alloc.c:12:
table.h:10:2: error: expected specifier-qualifier-list before 'Area'
  Area   *areap;  /* area to allocate entries */
  ^~~~
table.h:19:2: error: expected specifier-qualifier-list before 'Area'
  Area *areap;  /* area to allocate from */
  ^~~~
table.h:111:2: error: expected specifier-qualifier-list before 'Area'
  Area area;  /* area to allocate things */
  ^~~~
table.h:139:21: error: storage class specified for parameter 'taliases'
 extern struct table taliases; /* tracked aliases */
                     ^~~~~~~~
table.h:140:21: error: storage class specified for parameter 'builtins'
 extern struct table builtins; /* built-in commands */
                     ^~~~~~~~
table.h:141:21: error: storage class specified for parameter 'aliases'
 extern struct table aliases; /* aliases */
                     ^~~~~~~
table.h:142:21: error: storage class specified for parameter 'keywords'
 extern struct table keywords; /* keywords */
                     ^~~~~~~~
table.h:143:21: error: storage class specified for parameter 'homedirs'
 extern struct table homedirs; /* homedir() cache */
                     ^~~~~~~~
table.h:151:29: error: storage class specified for parameter 'shbuiltins'
 extern const struct builtin shbuiltins [], kshbuiltins [];
                             ^~~~~~~~~~
table.h:151:44: error: storage class specified for parameter 'kshbuiltins'
 extern const struct builtin shbuiltins [], kshbuiltins [];
                                            ^~~~~~~~~~~
table.h:178:14: error: storage class specified for parameter 'search_path'
 extern char *search_path; /* copy of either PATH or def_path */
              ^~~~~~~~~~~
table.h:179:20: error: storage class specified for parameter 'def_path'
 extern const char *def_path; /* path to use if PATH not set */
                    ^~~~~~~~
table.h:180:14: error: storage class specified for parameter 'tmpdir'
 extern char *tmpdir;  /* TMPDIR value */
              ^~~~~~
table.h:181:20: error: storage class specified for parameter 'prompt'
 extern const char *prompt;
                    ^~~~~~
table.h:182:12: error: storage class specified for parameter 'cur_prompt'
 extern int cur_prompt;  /* PS1 or PS2 */
            ^~~~~~~~~~
table.h:183:12: error: storage class specified for parameter 'current_lineno'
 extern int current_lineno; /* LINENO value */
            ^~~~~~~~~~~~~~
table.h:186:30: error: expected declaration specifiers or '...' before 'Area'
 void  ktinit(struct table *, Area *, int);
                              ^~~~
In file included from sh.h:368:0,
                 from alloc.c:12:
tree.h:141:32: error: expected declaration specifiers or '...' before 'Area'
 struct op * tcopy(struct op *, Area *);
                                ^~~~
tree.h:142:29: error: expected declaration specifiers or '...' before 'Area'
 char * wdcopy(const char *, Area *);
                             ^~~~
tree.h:145:25: error: expected declaration specifiers or '...' before 'Area'
 void tfree(struct op *, Area *);
                         ^~~~
In file included from sh.h:369:0,
                 from alloc.c:12:
expand.h:30:2: error: expected specifier-qualifier-list before 'Area'
  Area *areap;  /* area to allocate/free from */
  ^~~~
expand.h:31:3: error: storage class specified for parameter 'XString'
 } XString;
   ^~~~~~~
expand.h:33:16: error: storage class specified for parameter 'XStringP'
 typedef char * XStringP;
                ^~~~~~~~
expand.h:71:21: error: expected declaration specifiers or '...' before 'XString'
 char * Xcheck_grow_(XString *xsp, char *xp, size_t more);
                     ^~~~~~~
expand.h:80:3: error: storage class specified for parameter 'XPtrV'
 } XPtrV;
   ^~~~~
In file included from sh.h:370:0,
                 from alloc.c:12:
lex.h:11:23: error: storage class specified for parameter 'Source'
 typedef struct source Source;
                       ^~~~~~
lex.h:29:2: error: expected specifier-qualifier-list before 'Area'
  Area *areap;
  ^~~~
lex.h:57:3: error: storage class specified for parameter 'YYSTYPE'
 } YYSTYPE;
   ^~~~~~~
lex.h:103:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
 extern Source  *source;  /* yyparse/yylex source */
                ^
lex.h:104:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'yylval'
 extern YYSTYPE yylval;  /* result from yylex */
                ^~~~~~
lex.h:105:23: error: storage class specified for parameter 'heres'
 extern struct ioword *heres[HERES], **herep;
                       ^~~~~
lex.h:105:39: error: storage class specified for parameter 'herep'
 extern struct ioword *heres[HERES], **herep;
                                       ^~~~~
lex.h:106:13: error: storage class specified for parameter 'ident'
 extern char ident[IDENT+1];
             ^~~~~
lex.h:110:17: error: storage class specified for parameter 'history'
 extern char   **history; /* saved commands */
                 ^~~~~~~
lex.h:111:17: error: storage class specified for parameter 'histptr'
 extern char   **histptr; /* last history item */
                 ^~~~~~~
lex.h:112:17: error: storage class specified for parameter 'histsize'
 extern uint32_t histsize; /* history size */
                 ^~~~~~~~
lex.h:117:1: error: expected declaration specifiers before 'Source'
 Source * pushs(int, Area *);
 ^~~~~~
In file included from alloc.c:12:0:
sh.h:373:1: error: expected declaration specifiers before 'Area'
 Area * ainit(Area *);
 ^~~~
sh.h:374:15: error: expected declaration specifiers or '...' before 'Area'
 void afreeall(Area *);
               ^~~~
sh.h:375:22: error: expected declaration specifiers or '...' before 'Area'
 void * alloc(size_t, Area *);
                      ^~~~
sh.h:376:46: error: expected declaration specifiers or '...' before 'Area'
 void * areallocarray(void *, size_t, size_t, Area *);
                                              ^~~~
sh.h:377:32: error: expected declaration specifiers or '...' before 'Area'
 void * aresize(void *, size_t, Area *);
                                ^~~~
sh.h:378:20: error: expected declaration specifiers or '...' before 'Area'
 void afree(void *, Area *);
                    ^~~~
sh.h:429:21: error: expected declaration specifiers or '...' before 'XPtrV'
 void expand(char *, XPtrV *, int);
                     ^~~~~
sh.h:430:22: error: expected declaration specifiers or '...' before 'XPtrV'
 int glob_str(char *, XPtrV *, int);
                      ^~~~~
sh.h:448:16: error: expected declaration specifiers or '...' before 'Source'
 void hist_init(Source *);
                ^~~~~~
sh.h:497:23: error: expected declaration specifiers or '...' before 'Area'
 struct temp *maketemp(Area *, Temp_type, struct temp **);
                       ^~~~
sh.h:497:31: error: expected declaration specifiers or '...' before 'Temp_type'
 struct temp *maketemp(Area *, Temp_type, struct temp **);
                               ^~~~~~~~~
sh.h:522:11: error: expected declaration specifiers or '...' before 'Source'
 int shell(Source *volatile, int volatile);
           ^~~~~~
sh.h:532:31: error: expected declaration specifiers or '...' before 'Area'
 char * str_save(const char *, Area *);
                               ^~~~
sh.h:533:37: error: expected declaration specifiers or '...' before 'Area'
 char * str_nsave(const char *, int, Area *);
                                     ^~~~
sh.h:546:23: error: expected declaration specifiers or '...' before 'Getopt'
 void ksh_getopt_reset(Getopt *, int);
                       ^~~~~~
sh.h:547:25: error: expected declaration specifiers or '...' before 'Getopt'
 int ksh_getopt(char **, Getopt *, const char *);
                         ^~~~~~
sh.h:556:52: error: expected declaration specifiers or '...' before 'XString'
 int make_path(const char *, const char *, char **, XString *, int *);
                                                    ^~~~~~~
sh.h:562:21: error: expected declaration specifiers or '...' before 'Source'
 struct op * compile(Source *);
                     ^~~~~~
sh.h:566:1: error: expected declaration specifiers before 'Trap'
 Trap * gettrap(const char *, int);
 ^~~~
sh.h:572:14: error: expected declaration specifiers or '...' before 'Trap'
 void runtrap(Trap *);
              ^~~~
sh.h:575:14: error: expected declaration specifiers or '...' before 'Trap'
 void settrap(Trap *, char *);
              ^~~~
sh.h:578:12: error: expected declaration specifiers or '...' before 'Trap'
 int setsig(Trap *, sig_t, int);
            ^~~~
sh.h:578:20: error: expected declaration specifiers or '...' before 'sig_t'
 int setsig(Trap *, sig_t, int);
                    ^~~~~
sh.h:579:17: error: expected declaration specifiers or '...' before 'Trap'
 void setexecsig(Trap *, int);
                 ^~~~
alloc.c:19:1: error: expected declaration specifiers before 'Area'
 Area *
 ^~~~
alloc.c:27:10: error: expected declaration specifiers or '...' before 'Area'
 afreeall(Area *ap)
          ^~~~
alloc.c:42:20: error: expected declaration specifiers or '...' before 'Area'
 alloc(size_t size, Area *ap)
                    ^~~~
alloc.c:71:53: error: expected declaration specifiers or '...' before 'Area'
 areallocarray(void *ptr, size_t nmemb, size_t size, Area *ap)
                                                     ^~~~
alloc.c:83:33: error: expected declaration specifiers or '...' before 'Area'
 aresize(void *ptr, size_t size, Area *ap)
                                 ^~~~
alloc.c:112:18: error: expected declaration specifiers or '...' before 'Area'
 afree(void *ptr, Area *ap)
                  ^~~~
In file included from config.h:28:0,
                 from sh.h:9,
                 from alloc.c:12:
portable.h:168:5: error: old-style parameter declarations in prototyped function definition
 int asprintf(char **str, const char *fmt, ...)
     ^~~~~~~~
alloc.c:128:1: error: expected '{' at end of input
 }
 ^
gmake: *** [<builtin>: alloc.o] Error 1

That seems really fucky; if I apply gcc Kremlinology, I think this section of portable.c may be to blame? The declaration doesn't look right to me....

/*
 * Externs
 */

#if !defined(HAVE_SIGLIST) || !defined(HAVE_SIGNAME)
#ifdef NSIG
#undef NSIG
#endif /* NSIG */
#define NSIG 33
#ifndef HAVE_SIGLIST
extern const char *const sys_siglist[NSIG];
#endif /* !HAVE_SIGLIST */
#ifndef HAVE_SIGNAME
extern const char *const sys_signame[NSIG];
#endif /* !HAVE_SIGNAME */
#endif /* !HAVE_SIGLIST || !HAVE_SIGNAME */
tssva commented 6 years ago

I seem to have committed an off by one character cut & paste error earlier in the file. I have corrected it. Hopefully you will get a little farther this time.

NattyNarwhal commented 6 years ago

@tssva Re-cloned, works better after changing the configure flags for AIX to -D_ALL_SOURCE, until I get to:

gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o alloc.o alloc.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o asprintf.o asprintf.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o c_ksh.o c_ksh.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o c_sh.o c_sh.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o c_test.o c_test.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o c_ulimit.o c_ulimit.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o edit.o edit.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o emacs.o emacs.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o eval.o eval.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o exec.o exec.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o expr.o expr.c
gcc -DEMACS -DVI -w -D_ALL_SOURCE   -c -o history.o history.c
In file included from config.h:28:0,
                 from sh.h:9,
                 from history.c:25:
history.c: In function 'histsave':
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:148:12: note: in definition of macro 'timespeccmp'
         (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
            ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:148:29: note: in definition of macro 'timespeccmp'
         (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
                             ^~~
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:149:15: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
               ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:149:34: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
                                  ^~~
history.c:669:23: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                       ^
portable.h:150:15: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_sec cmp (usp)->tv_sec))
               ^~~
history.c:669:41: error: 'struct stat' has no member named 'st_mtim'; did you mean 'st_mtime'?
    if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
                                         ^
portable.h:150:33: note: in definition of macro 'timespeccmp'
             ((tsp)->tv_sec cmp (usp)->tv_sec))
                                 ^~~
gmake: *** [<builtin>: history.o] Error 1

This is the same thing I had to use -DSMALL to bypass.

NattyNarwhal commented 6 years ago

(There's also a typo on io.c:278; SETD -> SETFD.)

NattyNarwhal commented 6 years ago

Also a typo on your tty.c:66; missing semicolon.

Also had to add to configure a flag for -lbsd for flock. After that, it seems to work! I'll let you know about stability.

diff --git a/configure b/configure
index d474b1f..faf32ce 100755
--- a/configure
+++ b/configure
@@ -473,8 +473,9 @@ case "x$os" in
     cflags="$cflags $tflags"
     ;;
   "xAIX")
-    tflags="-D_BSD=44 -D_XOPEN_SOURCE=500"
+    tflags="-D_ALL_SOURCE -DSMALL"
     cflags="$cflags $tflags"
+    ldflags="$ldflags -lbsd"
     ;;
 esac

diff --git a/io.c b/io.c
index 62d242b..0011e8f 100644
--- a/io.c
+++ b/io.c
@@ -275,7 +275,7 @@ savefd(int fd)
                        else
                                errorf("too many files open in shell");
                }
-               fcntl(nfd, F_SETD, FD_CLOEXEC);
+               fcntl(nfd, F_SETFD, FD_CLOEXEC);
 #endif
        } else {
                nfd = fd;
diff --git a/tty.c b/tty.c
index 9aa3650..04d9b5c 100644
--- a/tty.c
+++ b/tty.c
@@ -61,7 +61,7 @@ tty_init(int init_ttystate)
                warningf(false, "%s: set tty fd close-on-exec flag failed: %s",
                    __func__, strerror(errno));
                close(tty_fd);
-               tty_fd = -1
+               tty_fd = -1;
 #endif
        } else if (init_ttystate)
                tcgetattr(tty_fd, &tty_state);
ibara commented 6 years ago

There's a NetBSD compat flock: http://bxr.su/NetBSD/tools/compat/flock.c Should we add it in?

NattyNarwhal commented 6 years ago

Maybe if someone runs into a platform without it. AIX does have it, but it's in the included "BSD" (it's a SysV, so its idea of BSD is oooollllldddddd) compat library. Just a simple -lbsd.

ibara commented 6 years ago

Oh I thought you meant you had to download the freedesktop.org libbsd.

tssva commented 6 years ago

Did some research based upon your last results and determined the "timespec" issue. timespec is defined but until AIX 7.1 the stat struct didn't include st_mtim, the last modification time as a timespec. st_mtim was added as a requirement in POSIX.1-2008.

There are many other legacy versions of unix systems for which this could be an issue. Looking around there are 4 ways systems seem to have handled this prior to POSIX.1-2008.

  1. In addition to st_mtime they already included the st_mtim field and will work as is.
  2. In addition to the st_mtime they reported the modification time as a timespec but the field is not st_mtim.
  3. They didn't report the modification time as a timespec but did report the number of nanoseconds in another field. AIX prior to 7.1 falls into this camp. It includes a st_mtime_n field which along with st_mtime could be used to recreate the timespec. The name of this field varies from system to system.
  4. They just report st_mtime which was the requirement of earlier POSIX standards.

Based upon this there are 3 potential courses of action:

  1. Implement a check for st_mtim and if it fails fallback to using st_mtime.
  2. Implement the check for st_mtim, implement checks for others ways the additional time resolution might be being reported and if they all fail fall back to st_mtime.
  3. Require systems that don't support st_mtim to use -DSMALL

The potential downside with option 2 is that you eventually end up with a tangle of ifdefs and checks. I'm not sure how much of a risk that is in reality.

ibara commented 6 years ago

-DSMALL should never be used; it's really for the RAMDISK kernels.

tssva commented 6 years ago

Ok, I updated my branch. It now checks for st_mtim and st_mtimespec (used by macOS). If st_mtimespec is found but st_mtim is not it defines st_mtim as st_mtimespec. If neither is found it falls back to using st_mtime by defining st_mtim as st_mtime and timespeccmp as timespeccmp(tsp, usp, cmp) (tsp) cmp (usp).

If I delete HAVE_ST_MTIMESPEC from pconfig.h on my macbook it properly falls back to using st_mtime. That is as close as I can get to testing it here before you get a crack at it.

NattyNarwhal commented 6 years ago

Yes, it seems to work fine out of the box now. I'd recommend you submit it as a PR!

ibara commented 6 years ago

Guess we should close this. Reopen if anything blows up on AIX.