summaryrefslogtreecommitdiff
path: root/src/lib/libcoshell
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libcoshell
downloadksh-3950ffe2a485479f6561c27364d3d7df5a21d124.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libcoshell')
-rw-r--r--src/lib/libcoshell/Makefile20
-rw-r--r--src/lib/libcoshell/Mamfile464
-rw-r--r--src/lib/libcoshell/RELEASE49
-rw-r--r--src/lib/libcoshell/coclose.c113
-rw-r--r--src/lib/libcoshell/codata.c169
-rw-r--r--src/lib/libcoshell/coexec.c449
-rw-r--r--src/lib/libcoshell/coexport.c80
-rw-r--r--src/lib/libcoshell/coinit.c431
-rw-r--r--src/lib/libcoshell/cokill.c134
-rw-r--r--src/lib/libcoshell/colib.h137
-rw-r--r--src/lib/libcoshell/coopen.c411
-rw-r--r--src/lib/libcoshell/coquote.c60
-rw-r--r--src/lib/libcoshell/coshell.3396
-rw-r--r--src/lib/libcoshell/coshell.h143
-rw-r--r--src/lib/libcoshell/costash.c40
-rw-r--r--src/lib/libcoshell/cosync.c127
-rw-r--r--src/lib/libcoshell/cowait.c411
-rw-r--r--src/lib/libcoshell/ignore.sh45
-rw-r--r--src/lib/libcoshell/procrun.c56
-rw-r--r--src/lib/libcoshell/silent.sh44
-rw-r--r--src/lib/libcoshell/system.c57
21 files changed, 3836 insertions, 0 deletions
diff --git a/src/lib/libcoshell/Makefile b/src/lib/libcoshell/Makefile
new file mode 100644
index 0000000..8fe9beb
--- /dev/null
+++ b/src/lib/libcoshell/Makefile
@@ -0,0 +1,20 @@
+/*
+ * coshell library
+ */
+
+:PACKAGE: ast
+
+CCFLAGS = $(CC.OPTIMIZE) $(CC.PIC) /* pic allows archive to be pulled into other dlls */
+
+LICENSE = since=1990,author=gsf
+
+coshell 1.0 :LIBRARY: RELEASE coshell.3 coshell.h colib.h \
+ coopen.c coclose.c coinit.c coexec.c costash.c \
+ cowait.c cokill.c cosync.c coquote.c codata.c \
+ coexport.c procrun.c system.c
+
+ignore :: ignore.sh
+
+silent :: silent.sh
+
+$(INCLUDEDIR) :INSTALLPROTO: coshell.h
diff --git a/src/lib/libcoshell/Mamfile b/src/lib/libcoshell/Mamfile
new file mode 100644
index 0000000..6f67e24
--- /dev/null
+++ b/src/lib/libcoshell/Mamfile
@@ -0,0 +1,464 @@
+info mam static 00000 1994-07-17 make (AT&T Research) 5.7 2012-02-29
+setv INSTALLROOT ../../..
+setv PACKAGE_ast_INCLUDE ${INSTALLROOT}/include/ast
+setv PACKAGE_ast_LIB ${INSTALLROOT}/lib
+setv PACKAGEROOT ../../../../..
+setv AR ${mam_cc_AR} ${mam_cc_AR_ARFLAGS}
+setv ARFLAGS rc
+setv AS as
+setv ASFLAGS
+setv CC cc
+setv mam_cc_FLAGS ${mam_cc_PIC}
+setv CCFLAGS ${-debug-symbols?1?${mam_cc_DEBUG} -D_BLD_DEBUG?${mam_cc_OPTIMIZE}?}
+setv CCLDFLAGS ${-strip-symbols?1?${mam_cc_LD_STRIP}??}
+setv COTEMP $$
+setv CPIO cpio
+setv CPIOFLAGS
+setv CPP "${CC} -E"
+setv F77 f77
+setv HOSTCC ${CC}
+setv IGNORE
+setv LD ld
+setv LDFLAGS
+setv LEX lex
+setv LEXFLAGS
+setv LPR lpr
+setv LPRFLAGS
+setv M4FLAGS
+setv NMAKE nmake
+setv NMAKEFLAGS
+setv PR pr
+setv PRFLAGS
+setv SHELL /bin/sh
+setv SILENT
+setv TAR tar
+setv YACC yacc
+setv YACCFLAGS -d
+make ${PACKAGEROOT}/lib/package/ast.lic
+done ${PACKAGEROOT}/lib/package/ast.lic
+make install
+make coshell
+make libcoshell.a archive
+make coshell.req
+exec - set -
+exec - echo 'int main(){return 0;}' > 1.${COTEMP}.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -c 1.${COTEMP}.c &&
+exec - x=`${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} -o 1.${COTEMP}.x 1.${COTEMP}.o -l'*' 2>&1 | sed -e 's/[][()+@?]/#/g' || :` &&
+exec - {
+exec - case "" in
+exec - *?) echo " " ;;
+exec - esac
+exec - for i in coshell ast
+exec - do case $i in
+exec - "coshell"|coshell)
+exec - ;;
+exec - *) if test -f ${INSTALLROOT}/lib/lib/$i
+exec - then y=`cat ${INSTALLROOT}/lib/lib/$i`
+exec - case $y in
+exec - *-?*) echo "" $y ;;
+exec - esac
+exec - continue
+exec - elif test ! -f ${INSTALLROOT}/lib/lib$i.a
+exec - then case `{ ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -L${INSTALLROOT}/lib ${LDFLAGS} -o 1.${COTEMP}.x 1.${COTEMP}.o -l$i 2>&1 || echo '' $x ;} | sed -e 's/[][()+@?]/#/g' || :` in
+exec - *$x*) case `{ ${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} -o 1.${COTEMP}.x 1.${COTEMP}.o -l$i 2>&1 || echo '' $x ;} | sed -e 's/[][()+@?]/#/g' || :` in
+exec - *$x*) continue ;;
+exec - esac
+exec - ;;
+exec - esac
+exec - fi
+exec - ;;
+exec - esac
+exec - echo " -l$i"
+exec - done
+exec - } > coshell.req
+exec - rm -f 1.${COTEMP}.*
+done coshell.req generated
+make coopen.o
+make coopen.c
+make ${PACKAGE_ast_INCLUDE}/tok.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_api.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_api.h dontcare
+make ${PACKAGE_ast_INCLUDE}/vmalloc.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_map.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_map.h dontcare
+make ${PACKAGE_ast_INCLUDE}/endian.h implicit
+make ${PACKAGE_ast_INCLUDE}/bytesex.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+done ${PACKAGE_ast_INCLUDE}/bytesex.h dontcare
+done ${PACKAGE_ast_INCLUDE}/endian.h dontcare
+done ${PACKAGE_ast_INCLUDE}/ast_common.h dontcare
+make ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+make ${PACKAGE_ast_INCLUDE}/regex.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_wchar.h implicit
+make ${PACKAGE_ast_INCLUDE}/wctype.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_wctype.h implicit
+prev ${PACKAGE_ast_INCLUDE}/endian.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_wctype.h dontcare
+done ${PACKAGE_ast_INCLUDE}/wctype.h dontcare
+make ${PACKAGE_ast_INCLUDE}/stdio.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_stdio.h implicit
+make ${PACKAGE_ast_INCLUDE}/sfio_s.h implicit
+done ${PACKAGE_ast_INCLUDE}/sfio_s.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_stdio.h dontcare
+done ${PACKAGE_ast_INCLUDE}/stdio.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/stdio.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_wchar.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+make ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+make ${INSTALLROOT}/include/prototyped.h implicit
+done ${INSTALLROOT}/include/prototyped.h dontcare
+done ${PACKAGE_ast_INCLUDE}/prototyped.h dontcare
+done ${PACKAGE_ast_INCLUDE}/regex.h dontcare
+make ${PACKAGE_ast_INCLUDE}/getopt.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_getopt.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_getopt.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/getopt.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_map.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_botch.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_botch.h dontcare
+make ${PACKAGE_ast_INCLUDE}/ast_limits.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_limits.h dontcare
+make ${PACKAGE_ast_INCLUDE}/ast_fcntl.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_fs.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_fs.h dontcare
+done ${PACKAGE_ast_INCLUDE}/ast_fcntl.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_getopt.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_sys.h implicit
+prev ${PACKAGE_ast_INCLUDE}/getopt.h implicit
+prev ${PACKAGE_ast_INCLUDE}/endian.h implicit
+prev ${PACKAGE_ast_INCLUDE}/endian.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_sys.h dontcare
+make ${PACKAGE_ast_INCLUDE}/ast_lib.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_lib.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_std.h dontcare
+done ${PACKAGE_ast_INCLUDE}/vmalloc.h dontcare
+make ${PACKAGE_ast_INCLUDE}/sfio.h implicit
+prev ${PACKAGE_ast_INCLUDE}/sfio_s.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+done ${PACKAGE_ast_INCLUDE}/sfio.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/tok.h
+make ${PACKAGE_ast_INCLUDE}/sfdisc.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/sfdisc.h
+make ${PACKAGE_ast_INCLUDE}/proc.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/proc.h
+make ${PACKAGE_ast_INCLUDE}/namval.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/namval.h
+make colib.h implicit
+make ${PACKAGE_ast_INCLUDE}/wait.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_wait.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_wait.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/wait.h dontcare
+make ${PACKAGE_ast_INCLUDE}/sig.h implicit
+done ${PACKAGE_ast_INCLUDE}/sig.h dontcare
+make ${PACKAGE_ast_INCLUDE}/error.h implicit
+make ${PACKAGE_ast_INCLUDE}/option.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/option.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/error.h dontcare
+make coshell.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+done coshell.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/vmalloc.h implicit
+make ${PACKAGE_ast_INCLUDE}/dt.h implicit
+prev ${PACKAGE_ast_INCLUDE}/vmalloc.h implicit
+make ${PACKAGE_ast_INCLUDE}/cdt.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_common.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+done ${PACKAGE_ast_INCLUDE}/cdt.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/dt.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+done colib.h
+done coopen.c
+meta coopen.o %.c>%.o coopen.c coopen
+prev coopen.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coopen.c
+done coopen.o generated
+make coclose.o
+make coclose.c
+prev colib.h implicit
+done coclose.c
+meta coclose.o %.c>%.o coclose.c coclose
+prev coclose.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coclose.c
+done coclose.o generated
+make coinit.o
+make coinit.c
+make ${PACKAGE_ast_INCLUDE}/ls.h implicit
+make ${PACKAGE_ast_INCLUDE}/ast_mode.h implicit
+done ${PACKAGE_ast_INCLUDE}/ast_mode.h dontcare
+prev ${PACKAGE_ast_INCLUDE}/ast_fs.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_std.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/ls.h
+make ${PACKAGE_ast_INCLUDE}/fs3d.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast_fs.h implicit
+prev ${PACKAGE_ast_INCLUDE}/prototyped.h implicit
+done ${PACKAGE_ast_INCLUDE}/fs3d.h
+prev ${PACKAGE_ast_INCLUDE}/endian.h implicit
+prev colib.h implicit
+done coinit.c
+meta coinit.o %.c>%.o coinit.c coinit
+prev coinit.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coinit.c
+done coinit.o generated
+make coexec.o
+make coexec.c
+prev ${PACKAGE_ast_INCLUDE}/ls.h implicit
+prev ${PACKAGE_ast_INCLUDE}/proc.h implicit
+prev colib.h implicit
+done coexec.c
+meta coexec.o %.c>%.o coexec.c coexec
+prev coexec.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coexec.c
+done coexec.o generated
+make costash.o
+make costash.c
+prev colib.h implicit
+done costash.c
+meta costash.o %.c>%.o costash.c costash
+prev costash.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c costash.c
+done costash.o generated
+make cowait.o
+make cowait.c
+prev colib.h implicit
+done cowait.c
+meta cowait.o %.c>%.o cowait.c cowait
+prev cowait.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c cowait.c
+done cowait.o generated
+make cokill.o
+make cokill.c
+prev colib.h implicit
+done cokill.c
+meta cokill.o %.c>%.o cokill.c cokill
+prev cokill.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c cokill.c
+done cokill.o generated
+make cosync.o
+make cosync.c
+make FEATURE/nfsd implicit
+meta FEATURE/nfsd >FEATURE/% nfsd
+bind -last
+exec - iffe -v -c '${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ' ref ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libast} : def nfsd
+done FEATURE/nfsd generated
+prev ${PACKAGE_ast_INCLUDE}/ls.h implicit
+prev colib.h implicit
+done cosync.c
+meta cosync.o %.c>%.o cosync.c cosync
+prev cosync.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c cosync.c
+done cosync.o generated
+make coquote.o
+make coquote.c
+prev colib.h implicit
+done coquote.c
+meta coquote.o %.c>%.o coquote.c coquote
+prev coquote.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coquote.c
+done coquote.o generated
+make codata.o
+make codata.c
+prev colib.h implicit
+done codata.c
+meta codata.o %.c>%.o codata.c codata
+prev codata.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c codata.c
+done codata.o generated
+make coexport.o
+make coexport.c
+prev colib.h implicit
+done coexport.c
+meta coexport.o %.c>%.o coexport.c coexport
+prev coexport.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c coexport.c
+done coexport.o generated
+make procrun.o
+make procrun.c
+prev ${PACKAGE_ast_INCLUDE}/proc.h implicit
+prev colib.h implicit
+done procrun.c
+meta procrun.o %.c>%.o procrun.c procrun
+prev procrun.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c procrun.c
+done procrun.o generated
+make system.o
+make system.c
+prev colib.h implicit
+done system.c
+meta system.o %.c>%.o system.c system
+prev system.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -I${PACKAGE_ast_INCLUDE} -D_PACKAGE_ast -D_BLD_coshell -c system.c
+done system.o generated
+exec - ${AR} rc libcoshell.a coopen.o coclose.o coinit.o coexec.o costash.o cowait.o cokill.o cosync.o coquote.o codata.o coexport.o procrun.o system.o
+exec - (ranlib libcoshell.a) >/dev/null 2>&1 || true
+done libcoshell.a generated
+done coshell virtual
+prev libcoshell.a archive
+make ignore
+make ignore.sh
+done ignore.sh
+meta ignore %.sh>% ignore.sh ignore
+prev ignore.sh
+exec - case static,port:$OPTIND:$RANDOM in
+exec - ?*:*:*|*::*|*:*:$RANDOM)
+exec - ;;
+exec - *) if ENV= LC_ALL=C x= $SHELL -nc '[[ a || b ]] && : ${list[level]} !(pattern)' 2>/dev/null
+exec - then if grep -q '### .*archaic.* ###'
+exec - then : ignore contains archaic constructs :
+exec - else ENV= LC_ALL=C $SHELL -n ignore.sh
+exec - fi
+exec - fi
+exec - ;;
+exec - esac
+exec - case '${mam_cc_SHELLMAGIC}' in
+exec - "") case 0 in
+exec - 0) cp ignore.sh ignore
+exec - ;;
+exec - *) {
+exec - i=`(read x; echo $x) < ignore.sh`
+exec - case $i in
+exec - '#!'*|*'||'*|':'*|'":"'*|"':'"*) echo "$i" ;;
+exec - esac
+exec - cat - ignore.sh <<'!'
+exec -
+exec - !
+exec - } > ignore
+exec - ;;
+exec - esac
+exec - ;;
+exec - *) cat - ignore.sh > ignore <<'!'
+exec - ${mam_cc_SHELLMAGIC}
+exec -
+exec - !
+exec - ;;
+exec - esac
+exec - silent test -w ignore -a -x ignore || chmod u+w,+x ignore
+done ignore generated
+make silent
+make silent.sh
+done silent.sh
+meta silent %.sh>% silent.sh silent
+prev silent.sh
+exec - case static,port:$OPTIND:$RANDOM in
+exec - ?*:*:*|*::*|*:*:$RANDOM)
+exec - ;;
+exec - *) if ENV= LC_ALL=C x= $SHELL -nc '[[ a || b ]] && : ${list[level]} !(pattern)' 2>/dev/null
+exec - then if grep -q '### .*archaic.* ###'
+exec - then : silent contains archaic constructs :
+exec - else ENV= LC_ALL=C $SHELL -n silent.sh
+exec - fi
+exec - fi
+exec - ;;
+exec - esac
+exec - case '${mam_cc_SHELLMAGIC}' in
+exec - "") case 0 in
+exec - 0) cp silent.sh silent
+exec - ;;
+exec - *) {
+exec - i=`(read x; echo $x) < silent.sh`
+exec - case $i in
+exec - '#!'*|*'||'*|':'*|'":"'*|"':'"*) echo "$i" ;;
+exec - esac
+exec - cat - silent.sh <<'!'
+exec -
+exec - !
+exec - } > silent
+exec - ;;
+exec - esac
+exec - ;;
+exec - *) cat - silent.sh > silent <<'!'
+exec - ${mam_cc_SHELLMAGIC}
+exec -
+exec - !
+exec - ;;
+exec - esac
+exec - silent test -w silent -a -x silent || chmod u+w,+x silent
+done silent generated
+make ${INSTALLROOT}/lib
+exec - if silent test ! -d ${INSTALLROOT}/lib
+exec - then mkdir -p ${INSTALLROOT}/lib
+exec - fi
+done ${INSTALLROOT}/lib generated
+make ${INSTALLROOT}/lib/libcoshell.a archive
+prev ${INSTALLROOT}/lib
+prev libcoshell.a archive
+exec - test '' = 'libcoshell.a' || ${STDCMP} 2>/dev/null -s libcoshell.a ${INSTALLROOT}/lib/libcoshell.a || { ${STDMV} ${INSTALLROOT}/lib/libcoshell.a ${INSTALLROOT}/lib/libcoshell.a.old 2>/dev/null || true; ${STDCP} libcoshell.a ${INSTALLROOT}/lib/libcoshell.a ;}
+exec - (ranlib ${INSTALLROOT}/lib/libcoshell.a) >/dev/null 2>&1 || true
+done ${INSTALLROOT}/lib/libcoshell.a generated
+make ${INSTALLROOT}/man/man3
+exec - if silent test ! -d ${INSTALLROOT}/man/man3
+exec - then mkdir -p ${INSTALLROOT}/man/man3
+exec - fi
+done ${INSTALLROOT}/man/man3 generated
+make ${INSTALLROOT}/man/man3/coshell.3
+prev ${INSTALLROOT}/man/man3
+make coshell.3
+done coshell.3
+exec - test '' = 'coshell.3' || ${STDCMP} 2>/dev/null -s coshell.3 ${INSTALLROOT}/man/man3/coshell.3 || { ${STDMV} ${INSTALLROOT}/man/man3/coshell.3 ${INSTALLROOT}/man/man3/coshell.3.old 2>/dev/null || true; ${STDCP} coshell.3 ${INSTALLROOT}/man/man3/coshell.3 ;}
+done ${INSTALLROOT}/man/man3/coshell.3 generated
+make ${INSTALLROOT}/lib/lib
+exec - if silent test ! -d ${INSTALLROOT}/lib/lib
+exec - then mkdir -p ${INSTALLROOT}/lib/lib
+exec - fi
+done ${INSTALLROOT}/lib/lib generated
+make ${INSTALLROOT}/lib/lib/coshell
+prev ${INSTALLROOT}/lib/lib
+prev coshell.req
+exec - test '' = 'coshell.req' || ${STDCMP} 2>/dev/null -s coshell.req ${INSTALLROOT}/lib/lib/coshell || { ${STDMV} ${INSTALLROOT}/lib/lib/coshell ${INSTALLROOT}/lib/lib/coshell.old 2>/dev/null || true; ${STDCP} coshell.req ${INSTALLROOT}/lib/lib/coshell ;}
+done ${INSTALLROOT}/lib/lib/coshell generated
+make ${INSTALLROOT}/bin
+exec - if silent test ! -d ${INSTALLROOT}/bin
+exec - then mkdir -p ${INSTALLROOT}/bin
+exec - fi
+done ${INSTALLROOT}/bin generated
+make ${INSTALLROOT}/bin/ignore
+prev ${INSTALLROOT}/bin
+prev ignore
+exec - test '' = 'ignore' || ${STDCMP} 2>/dev/null -s ignore ${INSTALLROOT}/bin/ignore || { ${STDMV} ${INSTALLROOT}/bin/ignore ${INSTALLROOT}/bin/ignore.old 2>/dev/null || true; ${STDCP} ignore ${INSTALLROOT}/bin/ignore ;}
+done ${INSTALLROOT}/bin/ignore generated
+make ${INSTALLROOT}/bin/silent
+prev silent
+exec - test '' = 'silent' || ${STDCMP} 2>/dev/null -s silent ${INSTALLROOT}/bin/silent || { ${STDMV} ${INSTALLROOT}/bin/silent ${INSTALLROOT}/bin/silent.old 2>/dev/null || true; ${STDCP} silent ${INSTALLROOT}/bin/silent ;}
+done ${INSTALLROOT}/bin/silent generated
+make ${PACKAGE_ast_INCLUDE}
+exec - if silent test ! -d ${PACKAGE_ast_INCLUDE}
+exec - then mkdir -p ${PACKAGE_ast_INCLUDE}
+exec - fi
+done ${PACKAGE_ast_INCLUDE} generated
+make ${PACKAGE_ast_INCLUDE}/coshell.h
+prev ${PACKAGE_ast_INCLUDE}
+prev coshell.h
+exec - proto -p -s -l ${PACKAGEROOT}/lib/package/ast.lic '-o since=1990,author=gsf' coshell.h > 1.${COTEMP}.x
+exec - if cmp 2>/dev/null -s ${PACKAGE_ast_INCLUDE}/coshell.h 1.${COTEMP}.x
+exec - then rm -f 1.${COTEMP}.x
+exec - else mv 1.${COTEMP}.x ${PACKAGE_ast_INCLUDE}/coshell.h
+exec - fi
+done ${PACKAGE_ast_INCLUDE}/coshell.h generated
+done install virtual
+make test
+done test dontcare virtual
diff --git a/src/lib/libcoshell/RELEASE b/src/lib/libcoshell/RELEASE
new file mode 100644
index 0000000..9d09db2
--- /dev/null
+++ b/src/lib/libcoshell/RELEASE
@@ -0,0 +1,49 @@
+12-02-22 coinit.c: handle non-identifier export var names
+11-12-13 cowait.c: handle sfpoll() error return on interrupt
+11-11-21 cowait.c: poll before blocking read to weed out killed jobs (no 'x' message)
+11-08-30 codata.c,coopen.c: drop macro "..." catenation for old cc
+10-08-11 coinit.c: force _BLD_DLL for environ intercept
+10-06-01 sync with ast api 20100601
+10-05-19 cokill.c: do cowait(co,co,0) to drain pending messages
+10-05-15 coshell.h,coopen.c: add CO_ORPHAN for PROC_ORPHAN
+10-05-11 coopen.c: add PROC_ORPHAN for CO_SHELL
+10-05-10 coopen.c: no atexit() for CO_SHELL
+10-04-15 first ksh93u local job pool tests work (service daemon tbd)
+10-04-14 cowait.c: add 3rd cowait() arg timeout; 0 Coshell_t* operates on all open coshells
+10-04-10 coshell.h: add CO_SHELL for shell using coshell!
+09-12-09 coexport.c: add runtime CO_ENV_EXPORT hook that avoids changing environ
+08-10-28 coopen.c: close write side of parent msgfd -- doh
+08-04-28 coexec.c: check for fd 1,2 equivalence before CO_SERIALIZE 2>&1
+07-10-29 coshell.h,coexec.c: fix procrun()/system() intercept logic
+07-08-15 add CO_SEPARATE,CO_MODE_SEPARATE for separate shell+wait per action
+07-04-09 Makefile: $(CC.PIC) to allow archive to be pulled into other dlls
+06-08-22 coshell.h: procrun => coprocrun, system => cosystem
+06-08-09 coshell.h: export CO_ENV_MSGFD for COSHELL=coshell
+06-08-02 coexec.c: Cojob_t.flags&CO_SERVICE for service requests
+06-08-02 cokill.c: cokill() signal==0 => kill CO_SERVICE jobs
+06-07-27 coexec.c: drop server cowait() that bypassed caller
+06-06-21 coexec.c: add non-block cowait() to drain responses
+06-06-11 fix service intercept cleanup
+06-05-24 add service=name:init lightweight service intercepts
+05-04-19 cowait.c: beef up invalid message tests and diagnostics
+05-04-11 drop fixed CO_MSGFD for $_coshell_msgfd
+05-04-07 coexec.c: fix !_lib_fork&&_map_spawnve close-on-exec redirection
+04-09-22 cowait.c: remove CO_SERIALIZE temporaries after listing -- duh
+04-09-01 co*: add CO_SERIALIZE
+04-07-22 system.c: access() => eaccess()
+04-02-11 coinit.c: fix CO_CROSS PATH initialization
+02-10-30 coclose.c: fix reference-after-free bug in coclose()
+02-01-31 codata.c,coopen.c: fix CO_MSGFD parameterization
+02-01-24 coopen.c: fix small memory leak
+01-10-26 coopen.c: hung sfclose(fp) -> close(sffileno(fp)) -- wow
+01-09-11 coinit.c: fix coident[] for ancient bsh that die on `test == 1'
+ coinit.c: and fix coident[] to weed out buggy ksh88i trap on exit
+01-05-31 co*: add CO_CROSS, expose CO_DEVFD
+01-04-23 coquote: add state.type to avoid getenv() overwrite on some systems
+01-01-01 cokill: killjob => cokilljob, killshell => cokillshell
+00-12-18 coinit: CO_OSH ? "${!-$$}" : "${!:-$$}"
+00-10-25 codata: $ZSH_VERSION is not ksh
+00-02-14 procrun,system: system(3) returns wait() status (not shell status)
+99-11-19 co*: add CO_OSH for bsdi lack of times(1)
+ coexec: CO_IGNORE for all but real ksh
+98-06-22 coinit: quote cd path arg
diff --git a/src/lib/libcoshell/coclose.c b/src/lib/libcoshell/coclose.c
new file mode 100644
index 0000000..9ca00b5
--- /dev/null
+++ b/src/lib/libcoshell/coclose.c
@@ -0,0 +1,113 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * close a coshell
+ */
+
+#include "colib.h"
+
+/*
+ * called when coshell is hung
+ */
+
+static void
+hung(int sig)
+{
+ NoP(sig);
+ kill(state.current->pid, SIGKILL);
+}
+
+/*
+ * shut down one coshell
+ */
+
+static int
+shut(register Coshell_t* co)
+{
+ register Coshell_t* cs;
+ int n;
+ int status;
+ Coshell_t* ps;
+ Coservice_t* sv;
+ Sig_handler_t handler;
+
+ sfclose(co->msgfp);
+ close(co->cmdfd);
+ if (co->pid)
+ {
+ if (co->running > 0)
+ killpg(co->pid, SIGTERM);
+ state.current = co;
+ handler = signal(SIGALRM, hung);
+ n = alarm(3);
+ if (waitpid(co->pid, &status, 0) != co->pid)
+ status = -1;
+ alarm(n);
+ signal(SIGALRM, handler);
+ killpg(co->pid, SIGTERM);
+ }
+ else
+ status = 0;
+ if (co->flags & CO_DEBUG)
+ errormsg(state.lib, 2, "coshell %d jobs %d user %s sys %s", co->index, co->total, fmtelapsed(co->user, CO_QUANT), fmtelapsed(co->sys, CO_QUANT));
+ for (sv = co->service; sv; sv = sv->next)
+ {
+ if (sv->fd > 0)
+ close(sv->fd);
+ if (sv->pid)
+ waitpid(sv->pid, &status, 0);
+ }
+ cs = state.coshells;
+ ps = 0;
+ while (cs)
+ {
+ if (cs == co)
+ {
+ cs = cs->next;
+ if (ps)
+ ps->next = cs;
+ else
+ state.coshells = cs;
+ vmclose(co->vm);
+ break;
+ }
+ ps = cs;
+ cs = cs->next;
+ }
+ return status;
+}
+
+/*
+ * close coshell co
+ */
+
+int
+coclose(register Coshell_t* co)
+{
+ if (co)
+ return shut(co);
+ while (state.coshells)
+ shut(state.coshells);
+ return 0;
+}
diff --git a/src/lib/libcoshell/codata.c b/src/lib/libcoshell/codata.c
new file mode 100644
index 0000000..fa6559f
--- /dev/null
+++ b/src/lib/libcoshell/codata.c
@@ -0,0 +1,169 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * coshell readonly data
+ */
+
+#include "colib.h"
+
+char coident[] = "\
+# @(#)$Id: libcoshell (AT&T Research) 2012-02-22 $\n\
+%s=%d\n\
+{ { (eval 'function fun { trap \":\" 0; return 1; }; trap \"exit 0\" 0; fun; exit 1') && PATH= print -u$%s ksh; } || { times && echo bsh >&$%s; } || { echo osh >&$%s; }; } >/dev/null 2>&1\n\
+";
+
+char cobinit[] = "\
+if (eval 'f() echo') >/dev/null 2>&1\n\
+then eval 'ignore() {\n\
+ case $- in\n\
+ *x*) set -\n\
+ _coshell_silent=\n\
+ ;;\n\
+ *) _coshell_silent=1\n\
+ ;;\n\
+ esac\n\
+ _coshell_state=exp\n\
+ _coshell_stop=\"<< -- StoP -- >>\"\n\
+ _coshell_quote='\\\\\\''\n\
+ set \"$@\" \"$_coshell_stop\"\n\
+ while :\n\
+ do case $1 in\n\
+ $_coshell_stop)\n\
+ shift\n\
+ break\n\
+ ;;\n\
+ *=*) ;;\n\
+ *) _coshell_state=arg ;;\n\
+ esac\n\
+ case $_coshell_state in\n\
+ exp) _coshell_arg=`echo $1 | sed \"s/\\\\([^=]*\\\\)=\\\\(.*\\\\)/\\\\1=$_coshell_quote\\\\2$_coshell_quote/\"`\n\
+ set \"\" \"$@\" \"$_coshell_arg\"\n\
+ shift\n\
+ ;;\n\
+ arg) set \"\" \"$@\" \"$_coshell_quote$1$_coshell_quote\"\n\
+ shift\n\
+ ;;\n\
+ esac\n\
+ shift\n\
+ done\n\
+ case $_coshell_silent in\n\
+ \"\") set \"set -x;\" \"$@\" ;;\n\
+ esac\n\
+ eval \"$@\"\n\
+ return 0\n\
+ }'\n\
+ eval 'silent() {\n\
+ case $- in\n\
+ *x*) set -\n\
+ _coshell_silent=\n\
+ ;;\n\
+ *) _coshell_silent=1\n\
+ ;;\n\
+ esac\n\
+ _coshell_state=exp\n\
+ _coshell_stop=\"<< -- StoP -- >>\"\n\
+ _coshell_quote='\\\\\\''\n\
+ set \"$@\" \"$_coshell_stop\"\n\
+ while :\n\
+ do case $1 in\n\
+ $_coshell_stop)\n\
+ shift\n\
+ break\n\
+ ;;\n\
+ *=*) ;;\n\
+ *) _coshell_state=arg ;;\n\
+ esac\n\
+ case $_coshell_state in\n\
+ exp) _coshell_arg=`echo $1 | sed \"s/\\\\([^=]*\\\\)=\\\\(.*\\\\)/\\\\1=$_coshell_quote\\\\2$_coshell_quote/\"`\n\
+ set \"\" \"$@\" \"$_coshell_arg\"\n\
+ shift\n\
+ ;;\n\
+ arg) set \"\" \"$@\" \"$_coshell_quote$1$_coshell_quote\"\n\
+ shift\n\
+ ;;\n\
+ esac\n\
+ shift\n\
+ done\n\
+ eval \"$@\"\n\
+ _coshell_state=$?\n\
+ case $_coshell_silent in\n\
+ \"\") set -x ;;\n\
+ esac\n\
+ return $_coshell_state\n\
+ }'\n\
+else :\n\
+fi\n\
+";
+
+char cokinit[] = "\
+set +o bgnice -o monitor\n\
+(wait $$; exit 0) 2>/dev/null || alias wait=:\n\
+alias ignore='ignore '\n\
+function ignore\n\
+{\n\
+ integer argc=0\n\
+ typeset argv state=exp\n\
+ while :\n\
+ do case $# in\n\
+ 0) break ;;\n\
+ esac\n\
+ case $1 in\n\
+ *=*) ;;\n\
+ *) state=arg ;;\n\
+ esac\n\
+ case $state in\n\
+ exp) argv[argc]=${1%%=*}=\"'${1#*=}'\" ;;\n\
+ arg) argv[argc]=\"'\"$1\"'\" ;;\n\
+ esac\n\
+ ((argc=argc+1))\n\
+ shift\n\
+ done\n\
+ eval \"${argv[@]}\"\n\
+ return 0\n\
+}\n\
+alias silent='set +x X$- \"$@\";_coshell_flags_=$1;shift;silent '\n\
+function silent\n\
+{\n\
+ case $_coshell_flags_ in\n\
+ *x*) trap ' _coshell_status_=$?\n\
+ if ((_coshell_status_==0))\n\
+ then set -x\n\
+ else set -x;(set +x;exit $_coshell_status_)\n\
+ fi' 0\n\
+ ;;\n\
+ esac\n\
+ \"$@\"\n\
+}\n\
+typeset -xf ignore silent\n\
+";
+
+char* co_export[] = /* default export var list */
+{
+ CO_ENV_EXPORT, /* first */
+ CO_ENV_ATTRIBUTES,
+ CO_ENV_PROC,
+ "FPATH",
+ "VPATH",
+ 0 /* last */
+};
diff --git a/src/lib/libcoshell/coexec.c b/src/lib/libcoshell/coexec.c
new file mode 100644
index 0000000..637c650
--- /dev/null
+++ b/src/lib/libcoshell/coexec.c
@@ -0,0 +1,449 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * send an action to the coshell for execution
+ */
+
+#include "colib.h"
+
+#include <proc.h>
+#include <ls.h>
+
+static Cojob_t*
+service(register Coshell_t* co, Coservice_t* cs, Cojob_t* cj, int flags, Sfio_t* sp)
+{
+ Proc_t* proc;
+ size_t n;
+ int i;
+ int j;
+ int fds[2];
+ long ops[4];
+ char* s;
+ char** a;
+
+ if (flags & CO_DEBUG)
+ {
+ for (a = cs->argv; *a; a++)
+ sfprintf(sp, " %s", *a);
+ if (!(s = costash(sp)))
+ goto nospace;
+ errormsg(state.lib, ERROR_LIBRARY|2, "service %s:%s", cs->path, s);
+ }
+ if (pipe(fds) < 0)
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: cannot allocate service pipe", cs->name);
+ return 0;
+ }
+ if (co->flags & CO_SHELL)
+ for (i = 0; i < elementsof(fds); i++)
+ if (fds[i] < 10 && (j = fcntl(fds[i], F_DUPFD, 10)) >= 0)
+ {
+ close(fds[i]);
+ fds[i] = j;
+ }
+ cs->fd = fds[1];
+ ops[0] = PROC_FD_DUP(fds[0], 0, PROC_FD_PARENT);
+ ops[1] = PROC_FD_CLOSE(fds[1], PROC_FD_CHILD);
+ ops[2] = PROC_FD_DUP(co->gsmfd, 1, 0);
+ ops[3] = 0;
+ if (!(proc = procopen(cs->path, cs->argv, NiL, ops, PROC_DAEMON|PROC_IGNORE)))
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: cannot connect to %s service", cs->path, cs->name);
+ close(fds[0]);
+ close(fds[1]);
+ return 0;
+ }
+ fcntl(cs->fd, F_SETFD, FD_CLOEXEC);
+ cs->pid = proc->pid;
+ procfree(proc);
+ sfprintf(sp, "id=%d info\n", cj->id);
+ n = sfstrtell(sp);
+ if (!(s = costash(sp)))
+ goto bad;
+ if (write(cs->fd, s, n) != n || sfpoll(&co->msgfp, 1, 5 * 1000) <= 0)
+ goto bad;
+ cj->pid = 0;
+ cj->status = 0;
+ cj->local = 0;
+ cj->service = cs;
+ co->svc_outstanding++;
+ co->svc_running++;
+ if (!cowait(co, cj, -1))
+ goto bad;
+ return cj;
+ bad:
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: service not responding", cs->name);
+ nospace:
+ cj->pid = CO_PID_FREE;
+ cs->pid = 0;
+ close(cs->fd);
+ cs->fd = -1;
+ return 0;
+}
+
+static Cojob_t*
+request(register Coshell_t* co, Cojob_t* cj, Coservice_t* cs, const char* action, int flags)
+{
+ ssize_t n;
+ ssize_t i;
+ Sfio_t* sp;
+
+ if (!(sp = sfstropen()))
+ {
+ errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
+ return 0;
+ }
+ if (!cs->fd && !service(co, cs, cj, flags, sp))
+ goto bad;
+ if (!cs->pid)
+ goto bad;
+ if (flags & CO_DEBUG)
+ errormsg(state.lib, ERROR_LIBRARY|2, "job %d commands:\n\n%s %s\n", cj->id, cs->name, action);
+ if (!(flags & CO_SILENT))
+ sfprintf(sfstderr, "+ %s %s\n", cs->name, action);
+ sfprintf(sp, "id=%d %s\n", cj->id, action);
+ n = sfstrtell(sp);
+ action = sfstrbase(sp);
+ while ((i = write(cs->fd, action, n)) > 0 && (n -= i) > 0)
+ action += i;
+ sfstrclose(sp);
+ if (n)
+ goto bad;
+ sfclose(sp);
+ cj->pid = 0;
+ cj->status = 0;
+ cj->local = 0;
+ cj->service = cs;
+ co->svc_outstanding++;
+ co->svc_running++;
+ co->total++;
+ return cj;
+ bad:
+ cj->pid = CO_PID_FREE;
+ sfclose(sp);
+ return 0;
+}
+
+Cojob_t*
+coexec(register Coshell_t* co, const char* action, int flags, const char* out, const char* err, const char* att)
+{
+ register Cojob_t* cj;
+ register Sfio_t* sp;
+ register Coservice_t* cs;
+ int n;
+ int i;
+ int og;
+ int cg;
+ char* s;
+ char* t;
+ char* env;
+ char* red;
+ char* sh[4];
+ struct stat sto;
+ struct stat ste;
+
+ /*
+ * get a free job slot
+ */
+
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (cj->pid == CO_PID_FREE)
+ break;
+ if (cj)
+ cj->service = 0;
+ else if (!(cj = vmnewof(co->vm, 0, Cojob_t, 1, 0)))
+ return 0;
+ else
+ {
+ cj->coshell = co;
+ cj->pid = CO_PID_FREE;
+ cj->id = ++co->slots;
+ cj->next = co->jobs;
+ co->jobs = cj;
+ }
+
+ /*
+ * set the flags
+ */
+
+ flags &= ~co->mask;
+ flags |= co->flags;
+ cj->flags = flags;
+
+ /*
+ * check service intercepts
+ */
+
+ for (cs = co->service; cs; cs = cs->next)
+ {
+ for (s = cs->name, t = (char*)action; *s && *s == *t; s++, t++);
+ if (!*s && *t == ' ')
+ return request(co, cj, cs, t + 1, flags);
+ }
+ cj->flags &= ~CO_SERVICE;
+ red = (cj->flags & CO_APPEND) ? ">>" : ">";
+
+ /*
+ * package the action
+ */
+
+ if (!(env = coinitialize(co, co->flags)))
+ return 0;
+ if (!(sp = sfstropen()))
+ return 0;
+ n = strlen(action);
+ if (co->flags & CO_SERVER)
+ {
+ /*
+ * leave it to server
+ */
+
+ sfprintf(sp, "#%05d\ne %d %d %s %s %s",
+ 0,
+ cj->id,
+ cj->flags,
+ state.pwd,
+ out,
+ err);
+ if (att)
+ sfprintf(sp, " (%d:%s)", strlen(att), att);
+ else
+ sfprintf(sp, " %s", att);
+ sfprintf(sp, " (%d:%s) (%d:%s)\n", strlen(env), env, n, action);
+ }
+ else if (co->flags & CO_INIT)
+ {
+ if (flags & CO_DEBUG)
+ sfprintf(sp, "set -x\n");
+ sfprintf(sp, "%s%s\necho x %d $? >&$%s\n",
+ env,
+ action,
+ cj->id,
+ CO_ENV_MSGFD);
+ }
+ else if (flags & CO_KSH)
+ {
+#if !_lib_fork && defined(_map_spawnve)
+ Sfio_t* tp;
+
+ tp = sp;
+ if (!(sp = sfstropen()))
+ sp = tp;
+#endif
+ sfprintf(sp, "{\ntrap 'set %s$?; trap \"\" 0; IFS=\"\n\"; print -u$%s x %d $1 $(times); exit $1' 0 HUP INT QUIT TERM%s\n%s%s%s",
+ (flags & CO_SILENT) ? "" : "+x ",
+ CO_ENV_MSGFD,
+ cj->id,
+ (flags & CO_IGNORE) ? "" : " ERR",
+ env,
+ n > CO_MAXEVAL ? "" : "eval '",
+ (flags & CO_SILENT) ? "" : "set -x\n");
+ if (n > CO_MAXEVAL)
+ sfputr(sp, action, -1);
+ else
+ {
+ coquote(sp, action, 0);
+ sfprintf(sp, "\n'");
+ }
+ sfprintf(sp, "\n} </dev/null");
+ if (out)
+ {
+ if (*out == '/')
+ sfprintf(sp, " %s%s", red, out);
+ else
+ sfprintf(sp, " %s%s/%s", red, state.pwd, out);
+ }
+ else if ((flags & CO_SERIALIZE) && (cj->out = pathtemp(NiL, 64, NiL, "coo", NiL)))
+ sfprintf(sp, " >%s", cj->out);
+ if (err)
+ {
+ if (out && streq(out, err))
+ sfprintf(sp, " 2>&1");
+ else if (*err == '/')
+ sfprintf(sp, " 2%s%s", red, err);
+ else
+ sfprintf(sp, " 2%s%s/%s", red, state.pwd, err);
+ }
+ else if (flags & CO_SERIALIZE)
+ {
+ if (!out && !fstat(1, &sto) && !fstat(2, &ste) && sto.st_dev == ste.st_dev && sto.st_ino == ste.st_ino)
+ sfprintf(sp, " 2>&1");
+ else if (cj->err = pathtemp(NiL, 64, NiL, "coe", NiL))
+ sfprintf(sp, " 2>%s", cj->err);
+ }
+#if !_lib_fork && defined(_map_spawnve)
+ if (sp != tp)
+ {
+ sfprintf(tp, "%s -c '", state.sh);
+ if (!(s = costash(sp)))
+ return 0;
+ coquote(tp, s, 0);
+ sfprintf(tp, "'");
+ sfstrclose(sp);
+ sp = tp;
+ }
+#endif
+ sfprintf(sp, " &\nprint -u$%s j %d $!\n",
+ CO_ENV_MSGFD,
+ cj->id);
+ }
+ else
+ {
+#if !_lib_fork && defined(_map_spawnve)
+ Sfio_t* tp;
+
+ tp = sp;
+ if (!(sp = sfstropen())) sp = tp;
+#endif
+ flags |= CO_IGNORE;
+ if (co->mode & CO_MODE_SEPARATE)
+ {
+ flags &= ~CO_SERIALIZE;
+ og = '{';
+ cg = '}';
+ }
+ else
+ {
+ og = '(';
+ cg = ')';
+ }
+ sfprintf(sp, "%c\n%s%sset -%s%s\n",
+ og,
+ env,
+ n > CO_MAXEVAL ? "" : "eval '",
+ (flags & CO_IGNORE) ? "" : "e",
+ (flags & CO_SILENT) ? "" : "x");
+ if (n > CO_MAXEVAL)
+ sfprintf(sp, "%s", action);
+ else
+ {
+ coquote(sp, action, 0);
+ sfprintf(sp, "\n'");
+ }
+ sfprintf(sp, "\n%c </dev/null", cg);
+ if (out)
+ {
+ if (*out == '/')
+ sfprintf(sp, " %s%s", red, out);
+ else
+ sfprintf(sp, " %s%s/%s", red, state.pwd, out);
+ }
+ else if ((flags & CO_SERIALIZE) && (cj->out = pathtemp(NiL, 64, NiL, "coo", NiL)))
+ sfprintf(sp, " >%s", cj->out);
+ if (err)
+ {
+ if (out && streq(out, err))
+ sfprintf(sp, " 2>&1");
+ else if (*err == '/')
+ sfprintf(sp, " 2%s%s", red, err);
+ else
+ sfprintf(sp, " 2%s%s/%s", red, state.pwd, err);
+ }
+ else if (flags & CO_SERIALIZE)
+ {
+ if (out)
+ sfprintf(sp, " 2>&1");
+ else if (cj->err = pathtemp(NiL, 64, NiL, "coe", NiL))
+ sfprintf(sp, " 2>%s", cj->err);
+ }
+ if (!(co->mode & CO_MODE_SEPARATE))
+ {
+ if (flags & CO_OSH)
+ sfprintf(sp, " && echo x %d 0 >&$%s || echo x %d $? >&$%s",
+ cj->id,
+ CO_ENV_MSGFD,
+ cj->id,
+ CO_ENV_MSGFD);
+ else
+ sfprintf(sp, " && echo x %d 0 `times` >&$%s || echo x %d $? `times` >&$%s",
+ cj->id,
+ CO_ENV_MSGFD,
+ cj->id,
+ CO_ENV_MSGFD);
+ }
+#if !_lib_fork && defined(_map_spawnve)
+ if (sp != tp)
+ {
+ sfprintf(tp, "%s -c '", state.sh);
+ if (!(s = costash(sp)))
+ return 0;
+ coquote(tp, s, 0);
+ sfprintf(tp, "'");
+ sfstrclose(sp);
+ sp = tp;
+ }
+#endif
+ if (!(co->mode & CO_MODE_SEPARATE))
+ sfprintf(sp, " &\necho j %d $! >&$%s\n",
+ cj->id,
+ CO_ENV_MSGFD);
+ }
+ n = sfstrtell(sp);
+ if (!costash(sp))
+ return 0;
+ if (flags & CO_SERVER)
+ sfprintf(sp, "#%05d\n", n - 7);
+ s = sfstrseek(sp, 0, SEEK_SET);
+ if (flags & CO_DEBUG)
+ errormsg(state.lib, ERROR_LIBRARY|2, "job %d commands:\n\n%s\n", cj->id, s);
+ if (co->mode & CO_MODE_SEPARATE)
+ {
+ sh[0] = state.sh;
+ sh[1] = "-c";
+ sh[2] = s;
+ sh[3] = 0;
+ cj->status = procrun(state.sh, sh, 0);
+ sfstrclose(sp);
+ cj->pid = CO_PID_ZOMBIE;
+ cj->local = 0;
+ co->outstanding++;
+ co->total++;
+ }
+ else
+ {
+ /*
+ * send it off
+ */
+
+ while ((i = write(co->cmdfd, s, n)) > 0 && (n -= i) > 0)
+ s += i;
+ sfstrclose(sp);
+ if (n)
+ return 0;
+
+ /*
+ * it's a job
+ */
+
+ cj->pid = 0;
+ cj->status = 0;
+ cj->local = 0;
+ co->outstanding++;
+ co->running++;
+ co->total++;
+ if (co->mode & CO_MODE_ACK)
+ cj = cowait(co, cj, -1);
+ }
+ return cj;
+}
diff --git a/src/lib/libcoshell/coexport.c b/src/lib/libcoshell/coexport.c
new file mode 100644
index 0000000..4ba62a6
--- /dev/null
+++ b/src/lib/libcoshell/coexport.c
@@ -0,0 +1,80 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * at&t Research
+ *
+ * coshell export var set/unset
+ */
+
+#include "colib.h"
+
+/*
+ * set or unset coshell export variable
+ */
+
+int
+coexport(Coshell_t* co, const char* name, const char* value)
+{
+ Coexport_t* ex;
+ char* v;
+
+ if (!co->export)
+ {
+ if (!(co->exdisc = vmnewof(co->vm, 0, Dtdisc_t, 1, 0)))
+ return -1;
+ co->exdisc->link = offsetof(Coexport_t, link);
+ co->exdisc->key = offsetof(Coexport_t, name);
+ co->exdisc->size = 0;
+ if (!(co->export = dtnew(co->vm, co->exdisc, Dtset)))
+ {
+ vmfree(co->vm, co->exdisc);
+ return -1;
+ }
+ }
+ if (!(ex = (Coexport_t*)dtmatch(co->export, name)))
+ {
+ if (!value)
+ return 0;
+ if (!(ex = vmnewof(co->vm, 0, Coexport_t, 1, strlen(name))))
+ return -1;
+ strcpy(ex->name, name);
+ dtinsert(co->export, ex);
+ }
+ if (ex->value)
+ {
+ vmfree(co->vm, ex->value);
+ ex->value = 0;
+ }
+ if (value)
+ {
+ if (!(v = vmstrdup(co->vm, value)))
+ return -1;
+ ex->value = v;
+ }
+ else
+ {
+ dtdelete(co->export, ex);
+ vmfree(co->vm, ex);
+ }
+ co->init.sync = 1;
+ return 0;
+}
diff --git a/src/lib/libcoshell/coinit.c b/src/lib/libcoshell/coinit.c
new file mode 100644
index 0000000..d36fbde
--- /dev/null
+++ b/src/lib/libcoshell/coinit.c
@@ -0,0 +1,431 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * return job initialization commands
+ */
+
+#if _WIN32
+#undef _BLD_DLL
+#define _BLD_DLL 1
+#endif
+
+#include "colib.h"
+
+#include <ctype.h>
+#include <fs3d.h>
+#include <ls.h>
+
+static void
+exid(Sfio_t* sp, const char* pre, const char* name, const char* pos)
+{
+ int c;
+
+ sfputr(sp, pre, -1);
+ if ((c = *name++) && c != '=')
+ {
+ if (isdigit(c))
+ sfputc(sp, '_');
+ do
+ {
+ if (!isalnum(c))
+ c = '_';
+ sfputc(sp, c);
+ } while ((c = *name++) && c != '=');
+ }
+ else
+ sfputc(sp, '_');
+ sfputr(sp, pos, -1);
+}
+
+/*
+ * add n to the export list
+ * old!=0 formats in old style
+ * coex!=0 for CO_ENV_EXPORT
+ * if n prefixed by % then coquote conversion enabled
+ */
+
+static void
+putexport(Coshell_t* co, Sfio_t* sp, char* n, int old, int coex, int flags)
+{
+ int cvt;
+ char* v;
+ Coexport_t* ex;
+
+ if (cvt = *n == '%')
+ n++;
+
+ /*
+ * currently limited to valid identifer env var names
+ */
+
+ if (!co->export || !dtmatch(co->export, n))
+ {
+ if (old)
+ cvt = 0;
+ if ((v = getenv(n)) && *v || coex && ((flags & CO_EXPORT) || co->export && dtsize(co->export) > 0))
+ {
+ if (!old)
+ sfprintf(sp, "\\\n");
+ exid(sp, " ", n, "='");
+ if (coex && (flags & CO_EXPORT))
+ v = "(*)";
+ if (v)
+ coquote(sp, v, cvt);
+ if (coex && !(flags & CO_EXPORT))
+ {
+ v = v ? ":" : "";
+ for (ex = (Coexport_t*)dtfirst(co->export); ex; ex = (Coexport_t*)dtnext(co->export, ex))
+ {
+ sfprintf(sp, "%s%s", v, ex->name);
+ exid(sp, v, ex->name, "");
+ v = ":";
+ }
+ }
+ sfputc(sp, '\'');
+ if (old)
+ exid(sp, "\nexport ", n, "\n");
+ }
+ }
+}
+
+/*
+ * return job initialization commands
+ */
+
+char*
+coinitialize(Coshell_t* co, int flags)
+{
+ register char* s;
+ int n;
+ int m;
+ int old;
+ int sync;
+ char* t;
+ long p;
+ Coexport_t* ex;
+ Sfio_t* sp;
+ Sfio_t* tp;
+ struct stat st;
+
+ sync = co->init.sync;
+ co->init.sync = 0;
+
+ /*
+ * pwd
+ */
+
+ if (stat(".", &st))
+ return 0;
+ if (!state.pwd || st.st_ino != co->init.pwd_ino || st.st_dev != co->init.pwd_dev)
+ {
+ co->init.pwd_dev = st.st_dev;
+ co->init.pwd_ino = st.st_ino;
+ if (state.pwd)
+ free(state.pwd);
+ if (!(state.pwd = getcwd(NiL, 0)))
+ {
+ if (errno != EINVAL || !(state.pwd = newof(0, char, PATH_MAX, 0)))
+ return 0;
+ if (!getcwd(state.pwd, PATH_MAX))
+ {
+ free(state.pwd);
+ state.pwd = 0;
+ return 0;
+ }
+ }
+ if (!(flags & CO_INIT))
+ sync = 1;
+ }
+
+ /*
+ * umask
+ */
+
+ umask(n = umask(co->init.mask));
+ if (co->init.mask != n)
+ {
+ co->init.mask = n;
+ if (!(flags & CO_INIT))
+ sync = 1;
+ }
+ if (!co->init.script || sync)
+ {
+ /*
+ * co_export[] vars
+ */
+
+ if (!(sp = sfstropen()))
+ return 0;
+ tp = 0;
+ old = !(flags & (CO_KSH|CO_SERVER));
+ if (!old)
+ sfprintf(sp, "export");
+ if (sync)
+ {
+ if (flags & CO_EXPORT)
+ s = "(*)";
+ else
+ {
+ for (n = 0; s = co_export[n]; n++)
+ putexport(co, sp, s, old, !n, flags);
+ s = getenv(co_export[0]);
+ }
+ if (s)
+ {
+ if (*s == '(')
+ {
+ register char** ep = environ;
+ register char* e;
+ char* v;
+ char* es;
+ char* xs;
+
+ if (v = strchr(s, ':'))
+ *v = 0;
+ while (e = *ep++)
+ if ((t = strsubmatch(e, s, 1)) && (*t == '=' || !*t && (t = strchr(e, '='))))
+ {
+ m = (int)(t - e);
+ if (!strneq(e, "PATH=", 5) && !strneq(e, "_=", 2))
+ {
+ for (n = 0; xs = co_export[n]; n++)
+ {
+ es = e;
+ while (*xs && *es == *xs)
+ {
+ es++;
+ xs++;
+ }
+ if (*es == '=' && !*xs)
+ break;
+ }
+ if (!xs)
+ {
+ if (!old)
+ sfprintf(sp, "\\\n");
+ exid(sp, " ", e, "='");
+ coquote(sp, e + m + 1, 0);
+ sfputc(sp, '\'');
+ if (old)
+ exid(sp, "\nexport ", e, "\n");
+ }
+ }
+ }
+ if (v)
+ {
+ *v++ = ':';
+ s = v;
+ }
+ }
+ if (*s)
+ for (;;)
+ {
+ if (t = strchr(s, ':'))
+ *t = 0;
+ putexport(co, sp, s, old, 0, 0);
+ if (!(s = t))
+ break;
+ *s++ = ':';
+ }
+ }
+ if (co->export)
+ for (ex = (Coexport_t*)dtfirst(co->export); ex; ex = (Coexport_t*)dtnext(co->export, ex))
+ {
+ if (!old)
+ sfprintf(sp, "\\\n");
+ exid(sp, " ", ex->name, "='");
+ coquote(sp, ex->value, 0);
+ sfputc(sp, '\'');
+ if (old)
+ exid(sp, "\nexport ", ex->name, "\n");
+ }
+ }
+
+ /*
+ * PATH
+ */
+
+ if (!old)
+ sfprintf(sp, "\\\n");
+ sfprintf(sp, " PATH='");
+ n = PATH_MAX;
+ if (!(t = sfstrrsrv(sp, n)))
+ {
+ bad:
+ sfstrclose(sp);
+ if (tp)
+ sfstrclose(tp);
+ return 0;
+ }
+ t += n / 2;
+ if (!(flags & CO_CROSS) && !pathpath("ignore", NiL, PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, t, n / 2) && pathpath("bin/ignore", "", PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, t, n / 2))
+ {
+ *strrchr(t, '/') = 0;
+ sfputc(sp, ':');
+ coquote(sp, t, !old);
+ sfputc(sp, ':');
+ s = pathbin();
+ }
+ else
+ {
+ s = pathbin();
+ if (!(flags & CO_CROSS))
+ {
+ if (!sync && (*s == ':' || *s == '.' && *(s + 1) == ':'))
+ {
+ sfstrseek(sp, 0, SEEK_SET);
+ goto done;
+ }
+ sfputc(sp, ':');
+ }
+ }
+ for (;;)
+ {
+ if (*s == ':')
+ s++;
+ else if (*s == '.' && *(s + 1) == ':')
+ s += 2;
+ else
+ break;
+ }
+ if (!(flags & CO_CROSS))
+ tp = 0;
+ else if (!(tp = sfstropen()))
+ goto bad;
+ else
+ {
+ while (n = *s++)
+ {
+ if (n == ':')
+ {
+ while (*s == ':')
+ s++;
+ if (!*s)
+ break;
+ if (*s == '.')
+ {
+ if (!*(s + 1))
+ break;
+ if (*(s + 1) == ':')
+ {
+ s++;
+ continue;
+ }
+ }
+ }
+ sfputc(tp, n);
+ }
+ if (!(s = costash(tp)))
+ goto bad;
+ }
+ coquote(sp, s, !old);
+ if (tp)
+ sfstrclose(tp);
+ sfputc(sp, '\'');
+ if (old)
+ sfprintf(sp, "\nexport PATH");
+ sfputc(sp, '\n');
+ if (sync)
+ {
+ /*
+ * VPATH
+ */
+
+ p = (int)sfstrtell(sp);
+ sfprintf(sp, "vpath ");
+ n = PATH_MAX;
+ if (fs3d(FS3D_TEST))
+ for (;;)
+ {
+ if (!(t = sfstrrsrv(sp, n)))
+ goto bad;
+ if ((m = mount(NiL, t, FS3D_GET|FS3D_ALL|FS3D_SIZE(n), NiL)) > 0)
+ m = n;
+ else
+ {
+ if (!m)
+ sfstrseek(sp, strlen(t), SEEK_CUR);
+ break;
+ }
+ }
+ else
+ {
+ m = 0;
+ sfprintf(sp, "- /#option/2d");
+ }
+ if (m)
+ sfstrseek(sp, p, SEEK_SET);
+ else
+ sfprintf(sp, " 2>/dev/null || :\n");
+ sfprintf(sp, "umask 0%o\ncd '%s'\n", co->init.mask, state.pwd);
+ }
+ done:
+ if (!(flags & CO_SERVER))
+ {
+ sfprintf(sp, "%s%s=%05d${!%s-$$}\n", old ? "" : "export ", CO_ENV_TEMP, getpid(), (flags & CO_OSH) ? "" : ":");
+ if (old)
+ sfprintf(sp, "export %s\n", CO_ENV_TEMP);
+ }
+ sfputc(sp, 0);
+ n = (int)sfstrtell(sp);
+ if (co->vm)
+ {
+ if (co->init.script)
+ vmfree(co->vm, co->init.script);
+ if (!(co->init.script = vmnewof(co->vm, 0, char, n, 1)))
+ goto bad;
+ }
+ else
+ {
+ if (co->init.script)
+ free(co->init.script);
+ if (!(co->init.script = newof(0, char, n, 1)))
+ goto bad;
+ }
+ memcpy(co->init.script, sfstrbase(sp), n);
+ sfstrclose(sp);
+ }
+ else if (!co->init.script)
+ {
+ if (co->init.script = co->vm ? vmnewof(co->vm, 0, char, 1, 0) : newof(0, char, 1, 0))
+ *co->init.script = 0;
+ }
+ return co->init.script;
+}
+
+/*
+ * return generic job initialization commands
+ */
+
+char*
+coinit(int flags)
+{
+ if (!state.generic)
+ {
+ if (!(state.generic = newof(0, Coshell_t, 1, 0)))
+ return 0;
+ state.generic->init.sync = 1;
+ }
+ return coinitialize(state.generic, flags);
+}
diff --git a/src/lib/libcoshell/cokill.c b/src/lib/libcoshell/cokill.c
new file mode 100644
index 0000000..b0c4fd4
--- /dev/null
+++ b/src/lib/libcoshell/cokill.c
@@ -0,0 +1,134 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * if co==0 then kill all coshell jobs with sig
+ * elif cj==0 then kill co jobs with sig
+ * else kill cj with sig
+ *
+ * if sig==0 then cause all CO_SERVICE jobs to fail
+ */
+
+#include "colib.h"
+
+/*
+ * kill job cj in shell co with signal sig
+ */
+
+static int
+cokilljob(register Coshell_t* co, register Cojob_t* cj, int sig)
+{
+ int n;
+
+ if (co->flags & CO_DEBUG)
+ errormsg(state.lib, 2, "coshell %d kill co=%d cj=%d sig=%d", co->index, co->pid, cj->pid, sig);
+ if (cj->pid < 0)
+ return 0;
+ if (cj->pid == 0)
+ {
+ if (cj->service)
+ co->svc_running--;
+ else
+ co->running--;
+ cj->pid = CO_PID_ZOMBIE;
+ cj->status = EXIT_TERM(sig);
+ return 0;
+ }
+ if (sig == SIGKILL)
+ {
+ co->running--;
+ cj->pid = CO_PID_ZOMBIE;
+ cj->status = EXIT_TERM(sig);
+ }
+ n = kill(cj->pid, sig);
+ killpg(cj->pid, sig);
+ return n;
+}
+
+/*
+ * kill cj (or all jobs if cj==0) in shell co with sig
+ */
+
+static int
+cokillshell(register Coshell_t* co, register Cojob_t* cj, int sig)
+{
+ int n;
+
+ if (sig && (co->flags & CO_SERVER))
+ {
+ char buf[CO_BUFSIZ];
+
+ n = sfsprintf(buf, sizeof(buf), "#%05d\nk %d %d\n", 0, cj ? cj->id : 0, sig);
+ sfsprintf(buf, 7, "#%05d\n", n - 7);
+ return write(co->cmdfd, buf, n) == n ? 0 : -1;
+ }
+ if (cj)
+ return cokilljob(co, cj, sig);
+ n = 0;
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (cj->pid > 0)
+ n |= cokilljob(co, cj, sig);
+ return n;
+}
+
+int
+cokill(register Coshell_t* co, register Cojob_t* cj, int sig)
+{
+ int any;
+ int n;
+
+ if (cj)
+ {
+ if (!co)
+ co = cj->coshell;
+ else if (co != cj->coshell)
+ return -1;
+ any = 0;
+ }
+ else if (co)
+ any = 0;
+ else if (!(co = state.coshells))
+ return -1;
+ else
+ any = 1;
+ if (co->flags & CO_DEBUG)
+ errormsg(state.lib, 2, "coshell %d kill co=%d cj=%d sig=%d", co->index, co ? co->pid : 0, cj ? cj->pid : 0, sig);
+ switch (sig)
+ {
+ case SIGINT:
+ sig = SIGTERM;
+ break;
+#if defined(SIGSTOP) && defined(SIGTSTP)
+ case SIGTSTP:
+ sig = SIGSTOP;
+ break;
+#endif
+ }
+ n = 0;
+ do
+ {
+ cowait(co, (Cojob_t*)co, 0);
+ n |= cokillshell(co, cj, sig);
+ } while (any && (co = co->next));
+ return n;
+}
diff --git a/src/lib/libcoshell/colib.h b/src/lib/libcoshell/colib.h
new file mode 100644
index 0000000..e4512b5
--- /dev/null
+++ b/src/lib/libcoshell/colib.h
@@ -0,0 +1,137 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * coshell library private definitions
+ */
+
+#ifndef _COLIB_H
+#define _COLIB_H
+
+#include <ast.h>
+#include <dt.h>
+#include <vmalloc.h>
+
+#define _CO_JOB_PRIVATE_ /* Cojob_t private additions */ \
+ Cojob_t* next; /* next in list */ \
+ Coservice_t* service; /* service */ \
+ int pid; /* pid */ \
+ char* out; /* serialized stdout file */ \
+ char* err; /* serialized stderr file */ \
+ /* end of private additions */
+
+#define _CO_SHELL_PRIVATE_ /* Coshell_t private additions */ \
+ Vmalloc_t* vm; /* Coshell_t vm */ \
+ Coshell_t* next; /* next in list */ \
+ Cojob_t* jobs; /* job list */ \
+ Coservice_t* service; /* service */ \
+ Dt_t* export; /* coexport() dictionary */ \
+ Dtdisc_t* exdisc; /* coexport() discipline */ \
+ struct Coinit_s /* initialization script state */ \
+ { \
+ char* script; /* initialization script */ \
+ dev_t pwd_dev; /* previous pwd dev */ \
+ ino_t pwd_ino; /* previous pwd inode number */ \
+ int mask; /* previous umask */ \
+ int sync; /* sync script */ \
+ } init; \
+ int cmdfd; /* command pipe fd */ \
+ int gsmfd; /* msgfp child write side */ \
+ int mask; /* CO_* flags to clear */ \
+ int mode; /* connection modes */ \
+ int svc_outstanding;/* outstanding service intercepts */ \
+ int svc_running; /* running service intercepts */ \
+ int pid; /* pid */ \
+ int index; /* coshell index */ \
+ int slots; /* number of job slots */ \
+ /* end of private additions */
+
+typedef struct Coexport_s
+{
+ Dtlink_t link;
+ char* value;
+ char name[1];
+} Coexport_t;
+
+struct Coservice_s;
+typedef struct Coservice_s Coservice_t;
+
+struct Coservice_s /* service info */
+{
+ Coservice_t* next; /* next in list */
+ char* name; /* instance name */
+ char* path; /* coexec() command path */
+ char* db; /* state/db path */
+ int fd; /* command pipe */
+ int pid; /* pid */
+ char* argv[16]; /* coexec() command argv[] */
+};
+
+#include <coshell.h>
+#include <error.h>
+#include <sig.h>
+#include <wait.h>
+
+#define state _coshell_info_ /* hide external symbol */
+
+#define CO_MODE_ACK (1<<0) /* wait for coexec() ack */
+#define CO_MODE_INDIRECT (1<<1) /* indirect CO_SERVER */
+#define CO_MODE_SEPARATE (1<<2) /* 1 shell+wait per action */
+
+#define CO_INIT (CO_USER>>1) /* initial command */
+
+#define CO_PID_FREE (-3) /* free job slot */
+#define CO_PID_WARPED (-2) /* exit before start message */
+#define CO_PID_ZOMBIE (-1) /* ready for wait */
+
+#define CO_BUFSIZ (PATH_MAX/2) /* temporary buffer size */
+#define CO_MAXEVAL (PATH_MAX*8) /* max eval'd action size */
+
+typedef struct Costate_s /* global coshell state */
+{
+ const char* lib; /* library id */
+ Coshell_t* coshells; /* list of all coshells */
+ Coshell_t* current; /* current coshell */
+ Coshell_t* generic; /* generic coshell for coinit() */
+ char* pwd; /* pwd */
+ char* sh; /* sh from first coopen() */
+ char* type; /* CO_ENV_TYPE value */
+ int init; /* 0 if first coopen() */
+ int index; /* last coshell index */
+} Costate_t;
+
+extern char coident[]; /* coshell ident script */
+extern char cobinit[]; /* bsh initialition script */
+extern char cokinit[]; /* ksh initialition script */
+extern char* co_export[]; /* default export var list */
+
+extern Costate_t state; /* global coshell info */
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern char* costash(Sfio_t*);
+extern char* coinitialize(Coshell_t*, int);
+
+#endif
diff --git a/src/lib/libcoshell/coopen.c b/src/lib/libcoshell/coopen.c
new file mode 100644
index 0000000..07dcb87
--- /dev/null
+++ b/src/lib/libcoshell/coopen.c
@@ -0,0 +1,411 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * open a new coshell
+ */
+
+#include "colib.h"
+
+#include <namval.h>
+#include <proc.h>
+#include <sfdisc.h>
+#include <tok.h>
+
+static const Namval_t options[] =
+{
+ "cross", CO_CROSS,
+ "debug", CO_DEBUG,
+ "devfd", CO_DEVFD,
+ "ignore", CO_IGNORE,
+ "orphan", CO_ORPHAN,
+ "silent", CO_SILENT,
+ "separate", CO_SEPARATE,
+ "service", CO_SERVICE,
+ 0, 0
+};
+
+Costate_t state = { "libcoshell:coshell" };
+
+/*
+ * called when ident sequence hung
+ */
+
+static void
+hung(int sig)
+{
+ NoP(sig);
+ close(sffileno(state.current->msgfp));
+}
+
+/*
+ * close all open coshells
+ */
+
+static void
+clean(void)
+{
+ coclose(NiL);
+}
+
+#ifdef SIGCONT
+
+/*
+ * pass job control signals to the coshell and self
+ */
+
+static void
+stop(int sig)
+{
+ cokill(NiL, NiL, sig);
+ signal(sig, SIG_DFL);
+ sigunblock(sig);
+ kill(getpid(), sig);
+ cokill(NiL, NiL, SIGCONT);
+ signal(sig, stop);
+}
+
+#endif
+
+/*
+ * called by stropt() to set options
+ */
+
+static int
+setopt(void* handle, register const void* p, int n, const char* v)
+{
+ Coshell_t* co = (Coshell_t*)handle;
+ Coservice_t* cs;
+ char* s;
+ char** a;
+
+ NoP(v);
+ if (p)
+ {
+ if (n)
+ {
+ co->flags |= ((Namval_t*)p)->value;
+ if (((Namval_t*)p)->value == CO_SERVICE && v && (cs = vmnewof(co->vm, 0, Coservice_t, 1, 2 * strlen(v))))
+ {
+ a = cs->argv;
+ *a++ = s = cs->path = cs->name = (char*)(cs + 1);
+ while (*s = *v++)
+ if (*s++ == ':')
+ {
+ *(s - 1) = 0;
+ if (*v == '-')
+ {
+ v++;
+ if (*v == '-')
+ v++;
+ }
+ if (strneq(v, "command=", 8))
+ cs->path = s + 8;
+ else if (strneq(v, "state=", 6))
+ cs->db = s + 6;
+ else if (strneq(v, "db=", 3))
+ cs->db = s + 3;
+ else if (a < &cs->argv[elementsof(cs->argv)-2] && *v && *v != ':')
+ {
+ *a++ = s;
+ *s++ = '-';
+ *s++ = '-';
+ }
+ }
+ if (cs->db)
+ *a++ = cs->db;
+ *a = 0;
+ cs->next = co->service;
+ co->service = cs;
+ }
+ }
+ else
+ co->mask |= ((Namval_t*)p)->value;
+ }
+ return 0;
+}
+
+Coshell_t*
+coopen(const char* path, int flags, const char* attributes)
+{
+ register Coshell_t* co;
+ register char* s;
+ register int i;
+ char* t;
+ int n;
+ Proc_t* proc;
+ Cojob_t* cj;
+ Vmalloc_t* vm;
+ Sfio_t* sp;
+ Sig_handler_t handler;
+ int pio[4];
+ long ops[5];
+ char devfd[16];
+ char evbuf[sizeof(CO_ENV_MSGFD) + 8];
+ char* av[8];
+ char* ev[2];
+
+ static char* sh[] = { 0, 0, "ksh", "sh", "/bin/sh" };
+
+ if (!state.type && (!(s = getenv(CO_ENV_TYPE)) || !(state.type = strdup(s))))
+ state.type = "";
+ if ((flags & CO_ANY) && (co = state.coshells))
+ return co;
+ if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(co = vmnewof(vm, 0, Coshell_t, 1, 0)))
+ {
+ if (vm)
+ vmclose(vm);
+ errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
+ return 0;
+ }
+ co->vm = vm;
+ co->index = ++state.index;
+ stropt(getenv(CO_ENV_OPTIONS), options, sizeof(*options), setopt, co);
+ if (attributes)
+ stropt(attributes, options, sizeof(*options), setopt, co);
+ co->flags |= ((flags | CO_DEVFD) & ~co->mask);
+ if (co->flags & CO_SEPARATE)
+ {
+ co->flags &= ~CO_SEPARATE;
+ co->mode |= CO_MODE_SEPARATE;
+ }
+ co->flags |= CO_INIT;
+ if (co->mode & CO_MODE_SEPARATE)
+ {
+ flags = 0;
+ proc = 0;
+ }
+ else
+ {
+ for (i = 0; i < elementsof(pio); i++)
+ pio[i] = -1;
+ if (pipe(&pio[0]) < 0 || pipe(&pio[2]) < 0)
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate pipes");
+ goto bad;
+ }
+ if (flags & CO_SHELL)
+ for (i = 0; i < elementsof(pio); i++)
+ if (pio[i] < 10 && (n = fcntl(pio[i], F_DUPFD, 10)) >= 0)
+ {
+ close(pio[i]);
+ pio[i] = n;
+ }
+ co->cmdfd = pio[1];
+ co->gsmfd = pio[3];
+ if (!(co->msgfp = sfnew(NiL, NiL, 256, pio[2], SF_READ)))
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate message stream");
+ goto bad;
+ }
+ sfdcslow(co->msgfp);
+ ops[0] = PROC_FD_DUP(pio[0], 0, PROC_FD_PARENT);
+ ops[1] = PROC_FD_CLOSE(pio[1], PROC_FD_CHILD);
+ ops[2] = PROC_FD_CLOSE(pio[2], PROC_FD_CHILD);
+ ops[3] = PROC_FD_CLOSE(pio[3], PROC_FD_PARENT);
+ ops[4] = 0;
+ sfsprintf(devfd, sizeof(devfd), "/dev/fd/%d", pio[0]);
+ flags = !access(devfd, F_OK);
+ }
+ sh[0] = (char*)path;
+ sh[1] = getenv(CO_ENV_SHELL);
+ for (i = 0; i < elementsof(sh); i++)
+ if ((s = sh[i]) && *s && (s = strdup(s)))
+ {
+ if ((n = tokscan(s, NiL, " %v ", av, elementsof(av) - 1)) > 0)
+ {
+ if (t = strrchr(s = av[0], '/'))
+ av[0] = t + 1;
+ if (flags || (co->flags & CO_DEVFD) && strmatch(s, "*ksh*"))
+ av[n++] = devfd;
+ av[n] = 0;
+ sfsprintf(evbuf, sizeof(evbuf), "%s=%d", CO_ENV_MSGFD, co->gsmfd);
+ ev[0] = evbuf;
+ ev[1] = 0;
+ if ((co->mode & CO_MODE_SEPARATE) || (proc = procopen(s, av, ev, ops, (co->flags & (CO_SHELL|CO_ORPHAN)) ? (PROC_ORPHAN|PROC_DAEMON|PROC_IGNORE) : (PROC_DAEMON|PROC_IGNORE))))
+ {
+ if (!state.sh)
+ state.sh = strdup(s);
+ free(s);
+ if (proc)
+ {
+ co->pid = proc->pid;
+ procfree(proc);
+ }
+ break;
+ }
+ }
+ free(s);
+ }
+ if (i >= elementsof(sh))
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot execute");
+ goto bad;
+ }
+ if (!(co->mode & CO_MODE_SEPARATE))
+ {
+ /*
+ * send the shell identification sequence
+ */
+
+ if (!(sp = sfstropen()))
+ {
+ errormsg(state.lib, ERROR_LIBRARY|2, "out of buffer space");
+ goto bad;
+ }
+ sfprintf(sp, "#%05d\n%s='", 0, CO_ENV_ATTRIBUTES);
+ if (t = getenv(CO_ENV_ATTRIBUTES))
+ {
+ coquote(sp, t, 0);
+ if (attributes)
+ sfprintf(sp, ",");
+ }
+ if (attributes)
+ coquote(sp, attributes, 0);
+ sfprintf(sp, "'\n");
+ sfprintf(sp, coident, CO_ENV_MSGFD, pio[3], CO_ENV_MSGFD, CO_ENV_MSGFD, CO_ENV_MSGFD);
+ i = sfstrtell(sp);
+ sfstrseek(sp, 0, SEEK_SET);
+ sfprintf(sp, "#%05d\n", i - 7);
+ i = write(co->cmdfd, sfstrbase(sp), i) != i;
+ sfstrclose(sp);
+ if (i)
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot write initialization message");
+ goto nope;
+ }
+ state.current = co;
+ handler = signal(SIGALRM, hung);
+ i = alarm(30);
+ if (!(s = sfgetr(co->msgfp, '\n', 1)))
+ {
+ if (errno == EINTR)
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "identification message read timeout");
+ goto nope;
+ }
+ alarm(i);
+ signal(SIGALRM, handler);
+ if (co->flags & CO_DEBUG)
+ errormsg(state.lib, 2, "coshell %d shell path %s identification \"%s\"", co->index, state.sh, s);
+ switch (*s)
+ {
+ case 'o':
+ co->flags |= CO_OSH;
+ /*FALLTHROUGH*/
+ case 'b':
+ s = cobinit;
+ break;
+ case 'k':
+ co->flags |= CO_KSH;
+ s = cokinit;
+ break;
+ case 'i': /* NOTE: 'i' is obsolete */
+ case 's':
+ co->flags |= CO_SERVER;
+ co->pid = 0;
+ for (;;)
+ {
+ if (t = strchr(s, ','))
+ *t = 0;
+ if (streq(s, CO_OPT_ACK))
+ co->mode |= CO_MODE_ACK;
+ else if (streq(s, CO_OPT_INDIRECT))
+ co->mode |= CO_MODE_INDIRECT;
+ if (!(s = t))
+ break;
+ s++;
+ }
+ if (!(co->mode & CO_MODE_INDIRECT))
+ wait(NiL);
+ break;
+ default:
+ goto nope;
+ }
+ if (s)
+ {
+ if (!(cj = coexec(co, s, 0, NiL, NiL, NiL)) || cowait(co, cj, -1) != cj)
+ {
+ errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "initialization message exec error");
+ goto nope;
+ }
+ co->total = 0;
+ co->user = 0;
+ co->sys = 0;
+ }
+ }
+ co->flags &= ~CO_INIT;
+ fcntl(pio[1], F_SETFD, FD_CLOEXEC);
+ fcntl(pio[2], F_SETFD, FD_CLOEXEC);
+ co->next = state.coshells;
+ state.coshells = co;
+ if (!(co->flags & CO_SHELL))
+ {
+#ifdef SIGCONT
+#ifdef SIGTSTP
+ signal(SIGTSTP, stop);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, stop);
+#endif
+#ifdef SIGTTOU
+ signal(SIGTTOU, stop);
+#endif
+#endif
+ if (!state.init)
+ {
+ state.init = 1;
+ atexit(clean);
+ }
+ }
+ return co;
+ bad:
+ n = errno;
+ if (co->msgfp)
+ {
+ sfclose(co->msgfp);
+ pio[2] = -1;
+ }
+ for (i = 0; i < elementsof(pio); i++)
+ if (pio[i] >= 0)
+ close(pio[i]);
+ coclose(co);
+ errno = n;
+ return 0;
+ nope:
+ i = errno;
+ if (!(s = sh[1]) || (s = (t = strrchr(s, '/')) ? (t + 1) : s) && !strmatch(s, "?(k)sh") && !streq(s, CO_ID))
+ error(2, "export %s={ksh,sh,%s}", CO_ENV_SHELL, CO_ID);
+ coclose(co);
+ errno = i;
+ return 0;
+}
+
+/*
+ * set coshell attributes
+ */
+
+int
+coattr(Coshell_t* co, const char* attributes)
+{
+ return 0;
+}
diff --git a/src/lib/libcoshell/coquote.c b/src/lib/libcoshell/coquote.c
new file mode 100644
index 0000000..1c1edf2
--- /dev/null
+++ b/src/lib/libcoshell/coquote.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * single quote s into sp
+ * if type!=0 then /<getenv(<CO_ENV_TYPE>)/ translated to /$<CO_ENV_TYPE>/
+ */
+
+#include "colib.h"
+
+void
+coquote(register Sfio_t* sp, register const char* s, int type)
+{
+ register int c;
+
+ if (type && (!state.type || !*state.type))
+ type = 0;
+ while (c = *s++)
+ {
+ sfputc(sp, c);
+ if (c == '\'')
+ {
+ sfputc(sp, '\\');
+ sfputc(sp, '\'');
+ sfputc(sp, '\'');
+ }
+ else if (type && c == '/' && *s == *state.type)
+ {
+ register const char* x = s;
+ register char* t = state.type;
+
+ while (*t && *t++ == *x) x++;
+ if (!*t && *x == '/')
+ {
+ s = x;
+ sfprintf(sp, "'$%s'", CO_ENV_TYPE);
+ }
+ }
+ }
+}
diff --git a/src/lib/libcoshell/coshell.3 b/src/lib/libcoshell/coshell.3
new file mode 100644
index 0000000..b0a1201
--- /dev/null
+++ b/src/lib/libcoshell/coshell.3
@@ -0,0 +1,396 @@
+.fp 5 CW
+.de L \" literal font
+.ft 5
+.if !\\$1 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \f1
+..
+.de LR
+.}S 5 1 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
+..
+.de RL
+.}S 1 5 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
+..
+.de EX \" start example
+.ta 1i 2i 3i 4i 5i 6i
+.PP
+.RS
+.PD 0
+.ft 5
+.nf
+..
+.de EE \" end example
+.fi
+.ft
+.PD
+.RE
+.PP
+..
+.TH COSHELL 3
+.SH NAME \" @(#)coshell.3 (gsf@research.att.com) 10/11/90
+coshell \- shell coprocess support
+.SH SYNOPSIS
+.L "#include <coshell.h>"
+.br
+.L "\-lcoshell \-last"
+.SH DESCRIPTION
+The
+.I coshell
+routines support the shell as a coprocess.
+This coprocess may be either
+.IR ksh (1)
+or
+.IR sh (1)
+executing on the local host, or it may be
+.IR coshell (1)
+with access to shells on hosts throughout the local network.
+.PP
+The coshell inherits the environment of the calling process.
+Signals sent to the calling process are passed to the coshell.
+.PP
+More than one coshell may be open in the current process.
+If the
+.L Coshell_t*
+argument to the
+.LR cowait() ,
+.LR cokill() ,
+.LR copending() ,
+.LR cozombie() ,
+or
+.L coclose()
+calls below is
+.L 0
+then the call is applied to all open coshell.
+.PP
+.L "Coshell_t* coopen(const char* shell, int flags, const char* attributes)"
+.PP
+Returns a pointer to a new coshell.
+.L NULL
+is returned on error.
+If
+.L shell
+is
+.L NULL
+then the coshell executable is determined by doing the usual path search,
+in order, on the value of the environment variable
+.B COSHELL
+and the commands
+.BR ksh
+and
+.BR sh .
+.L flags
+is the inclusive-or of the following:
+.TP
+.L CO_ANY
+Return a pointer to a previously opened coshell if possible, otherwise
+open a new coshell.
+.TP
+.L CO_DEBUG
+Enable library debug tracing.
+.TP
+.L CO_IGNORE
+Ignore any command errors.
+By default any command error that is not tested by a condtional causes
+the job to terminate.
+.TP
+.L CO_LOCAL
+Commands are to be executed on the local host only.
+.TP
+.L CO_SHELL
+The caller is
+.BR sh (1):
+internal file descriptors are moved to 10 or above;
+SIGSTOP and SIGCONT handlers are not installed.
+.TP
+.L CO_SILENT
+Don't trace commands.
+By default commands are traced using the shell
+.B \-x
+option.
+.TP
+.L CO_NONBLOCK
+Normally
+.L coexec()
+blocks when the job queue is full and waits until a job completes.
+.L CO_NONBLOCK
+causes
+.L coexec()
+to return
+.L NULL
+when the job queue is full.
+.PP
+.L attributes
+is a string that is interpreted by the coshell.
+If
+.L attributes
+is
+.L NULL
+then the value of the environment variable
+.B COATTRIBUTES
+is used if defined.
+.B ksh
+and
+.B sh
+ignore this string.
+The return value points to a structure with the following readonly elements:
+.TP
+.L "int flags"
+The default flags.
+.TP
+.L "int outstanding"
+The number of jobs that have not been waited for.
+.TP
+.L "int running"
+The number of jobs still running.
+.TP
+.L "int total"
+The total number of jobs sent to the coshell.
+.TP
+.L "unsigned long user"
+The total user time of all completed jobs in
+.L 1/CO_QUANT
+second increments.
+.TP
+.L "unsigned long sys"
+The total system time of all completed jobs in
+.L 1/CO_QUANT
+second increments.
+.PP
+.L "int coclose(Coshell_t* sh)"
+.PP
+Close an open coshell pointed to by
+.LR sh .
+The coshell exit status is returned.
+.PP
+.L "Cojob_t* coexec(Coshell_t* sh, const char* cmd, int flags, const char* out, const char* err, const char* att)"
+.PP
+Sends the shell command line
+.L cmd
+to the open coshell pointed to by
+.L sh
+for execution.
+.L flags
+are the same as in the
+.L coopen()
+call, and are used to augment the default settings from
+.LR coopen() .
+.L out
+is the standard output file name and defaults to
+.B stdout
+if
+.LR NULL .
+.L err
+is the standard error file name and defaults to
+.B stderr
+if
+.LR NULL .
+.LR att ,
+if
+.RL non- NULL ,
+contains job attributes that are appended to the attributes from
+.L coopen()
+before being sent to the coshell.
+The return value points to a structure with the following elements:
+.TP
+.L "int id"
+A number that uniquely identifies the job within the coshell.
+.TP
+.L "int status"
+The job exit status, valid only for job pointers returned by
+.LR cowait() .
+.TP
+.L "int flags"
+The flags enabled for this job.
+.TP
+.L "void* local"
+A user reserved pointer, initially set to
+.L NULL
+on return from
+.LR coexec() .
+This is the only job field that may be modified by the user.
+The user defined value is preserved until after the
+.L cowait()
+call that returns the job pointer.
+.TP
+.L "unsigned long user"
+The user time of this job in
+.L 1/CO_QUANT
+second increments, valid only for job pointers returned by
+.LR cowait() .
+.TP
+.L "unsigned long sys"
+The system time of this job in
+.L 1/CO_QUANT
+second increments, valid only for job pointers returned by
+.LR cowait() .
+.PP
+.L "Cojob_t* cowait(Coshell_t* sh, Cojob_t* job, int timeout)"
+.PP
+Returns the job pointer in the coshell pointed to by
+.L sh
+for the job pointed to by
+.LR job .
+If
+.L job
+is
+.L NULL
+then a pointer to any completed job is returned.
+.L cowait()
+blocks until the specified job(s) complete.
+.L NULL
+is returned on error or if all jobs have completed and
+.L errno
+is set to EINVAL for coshell communication errors,
+ECHILD if
+.L job
+is
+.L NULL
+and there are no children, and ESRCH if
+.L job
+is not
+.L NULL
+and not an active job.
+.L "cozombie(sh)"
+is the number of jobs that may be waited for without blocking.
+The return value
+.LR status ,
+.L user
+and
+.L sys
+job fields are set to their final values.
+The return value is valid until the next
+.LR coexec() ,
+.L cowait()
+or
+.L coclose()
+call.
+.L timeout
+is the maximum time in milliseconds that wait will block.
+If the wait times out then 0 is returned.
+A negative
+.L timeout
+waits until a job completes or a signal is received.
+.TP
+.L "int cojobs(Coshell_t* sh)"
+Returns the number of outstanding jobs that are children of the caller.
+(Remote jobs or jobs executed by a separate daemon are not counted here.)
+.TP
+.L "int copending(Coshell_t* sh)"
+Returns the number of pending jobs; this is the number of
+.L cowait()
+calls required to reap all running jobs.
+.TP
+.L "int cozombie(Coshell_t* sh)"
+Returns the number of jobs that have completed but have not been
+.L cowait()'d
+for.
+.TP
+.L "int cokill(Coshell_t* sh, Cojob_t* job, int sig)"
+The signal
+.L sig
+is sent to the job pointed to by
+.L job
+running in the coshell pointed to by
+.LR sh .
+If
+.L job
+is
+.L NULL
+then the signal is sent to all jobs in the coshell.
+If both
+.L sh
+and
+.L job
+are
+.L NULL
+then the signal is sent to all jobs in all coshells.
+.L \-1
+is returned on error,
+.L 0
+otherwise.
+.TP
+.L "int cosync(Coshell_t* sh, const char* path, int fd, int mode)"
+Sync all outstanding file operations for either the file
+.L path
+or the file descriptor
+.L fd
+after its shell action has completed in
+.LR sh .
+If
+.L path
+is
+.L NULL
+then
+.L fd
+is used.
+If
+.L fd<0
+and
+.L mode>=0
+then
+.L path
+is opened using
+.L mode.
+This is an unfortunate workaround for NFS and remote coshells, and is a
+no-op for all real file systems.
+It should be called after
+.L cowait()
+to ensure that all file system cache info has been flushed.
+.IR sync (2)
+or
+.IR fsync (2)
+must still be called to schedule file data to be written to disk.
+.TP
+.L "char* coinit(Coshell_t* sh)"
+Returns the shell initialization commands for the next job.
+These commands represent process state changes that may have occurred
+since the last call to
+.L coinit(),
+e.g., current working directory or umask.
+If
+.L sh
+is local (a child of the calling process)
+.L coinit()
+may return the empty string;
+if
+.L sh
+is remote then considerably more information may be returned.
+This routine is used by remote coshell implementations and is
+not normally called from user code.
+.TP
+.L "void coquote(Sfio_T* sp, const char* string, int type)"
+Applies shell single quoting to
+.L string
+and copies the result into the sfio stream
+.L sp.
+If
+.L type!=0
+then any occurence of \f5/\fP\fIhosttype\fP\f5/\fP is translated to
+\f5/$HOSTTYPE/\fP, where
+.I hosttype
+is the current value of the
+.L HOSTTYPE
+environment variable.
+This routine is used by remote coshell implementations and is
+not normally called from user code.
+.SH CAVEATS
+.L cosync()
+is a hack workaround, but we do have to work in the real world.
+.PP
+A bug in
+.IR bsh (1)
+and
+.IR ksh (1)
+implementations up to and including ksh88e causes some interrupted
+jobs to return 0 exit status.
+This should be fixed in later shell releases.
+.PP
+.L "trap 0"
+is reserved by
+.L coexec()
+at the outermost scope.
+To use
+.L "trap 0"
+use
+.L "(...)"
+to force a subshell.
+.SH "SEE ALSO"
+coshell(1), ksh(1), nmake(1), sh(1), cs(3), libast(3)
diff --git a/src/lib/libcoshell/coshell.h b/src/lib/libcoshell/coshell.h
new file mode 100644
index 0000000..9063f14
--- /dev/null
+++ b/src/lib/libcoshell/coshell.h
@@ -0,0 +1,143 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * coshell library interface
+ */
+
+#ifndef _COSHELL_H
+#define _COSHELL_H
+
+#include <ast.h>
+
+#if !_BLD_coshell
+
+#undef procrun
+#define procrun(a,b,c) coprocrun(a,b,c)
+#undef system
+#define system(a) cosystem(a)
+
+#endif
+
+struct Coshell_s; typedef struct Coshell_s Coshell_t;
+struct Cojob_s; typedef struct Cojob_s Cojob_t;
+
+/*
+ * DEPRECATED names for compatibility
+ */
+
+#define COSHELL Coshell_t
+#define COJOB Cojob_t
+
+#define CO_ID "coshell" /* library/command id */
+
+#define CO_ENV_ATTRIBUTES "COATTRIBUTES"/* coshell attributes env var */
+#define CO_ENV_EXPORT "COEXPORT" /* coshell env var export list */
+#define CO_ENV_HOST "HOSTNAME" /* coshell host name env var */
+#define CO_ENV_MSGFD "_COSHELL_msgfd"/* msg fd */
+#define CO_ENV_OPTIONS "COSHELL_OPTIONS"/* options environment var */
+#define CO_ENV_PROC "NPROC" /* concurrency environment var */
+#define CO_ENV_SHELL "COSHELL" /* coshell path environment var */
+#define CO_ENV_TEMP "COTEMP" /* 10 char temp file base */
+#define CO_ENV_TYPE "HOSTTYPE" /* coshell host type env var */
+
+#define CO_OPT_ACK "ack" /* wait for server coexec() ack */
+#define CO_OPT_INDIRECT "indirect" /* indirect server connection */
+#define CO_OPT_SERVER "server" /* server connection */
+
+#define CO_QUANT 100 /* time quanta per sec */
+
+#define CO_ANY 0x000001 /* return any open coshell */
+#define CO_DEBUG 0x000002 /* library debug trace */
+#define CO_EXPORT 0x000004 /* export everything */
+#define CO_IGNORE 0x000008 /* ignore command errors */
+#define CO_LOCAL 0x000010 /* local affinity */
+#define CO_NONBLOCK 0x000020 /* don't block coexec if Q full */
+#define CO_SHELL 0x000040 /* shell using coshell! */
+#define CO_SILENT 0x000080 /* don't trace commands */
+
+#define CO_KSH 0x000100 /* coshell is ksh (readonly) */
+#define CO_SERVER 0x000200 /* coshell is server (readonly) */
+#define CO_OSH 0x000400 /* coshell is OLD (readonly) */
+
+#define CO_CROSS 0x000800 /* don't prepend local dirs */
+#define CO_DEVFD 0x001000 /* coshell handles /dev/fd/# */
+
+#define CO_SERIALIZE 0x002000 /* serialize stdout and stderr */
+#define CO_SERVICE 0x004000 /* service callouts */
+
+#define CO_APPEND 0x008000 /* append coexec() out/err */
+#define CO_SEPARATE 0x010000 /* 1 shell+wait per coexec() */
+#define CO_ORPHAN 0x020000 /* PROC_ORPHAN */
+
+#define CO_USER 0x100000 /* first user flag */
+
+struct Cojob_s /* coshell job info */
+{
+ Coshell_t* coshell; /* running in this coshell */
+ int id; /* job id */
+ int status; /* exit status */
+ int flags; /* CO_* flags */
+ void* local; /* local info */
+ unsigned long user; /* user time in 1/CO_QUANT secs */
+ unsigned long sys; /* sys time in 1/CO_QUANT secs */
+#ifdef _CO_JOB_PRIVATE_
+ _CO_JOB_PRIVATE_ /* library private additions */
+#endif
+};
+
+struct Coshell_s /* coshell connection info */
+{
+ void* data; /* user data, initially 0 */
+ int flags; /* flags */
+ int outstanding; /* number of outstanding jobs */
+ int running; /* number of running jobs */
+ int total; /* number of coexec() jobs */
+ unsigned long user; /* user time in 1/CO_QUANT secs */
+ unsigned long sys; /* sys time in 1/CO_QUANT secs */
+ Sfio_t* msgfp; /* message stream for sfpoll() */
+#ifdef _CO_SHELL_PRIVATE_
+ _CO_SHELL_PRIVATE_ /* library private additions */
+#endif
+};
+
+extern int coclose(Coshell_t*);
+extern Cojob_t* coexec(Coshell_t*, const char*, int, const char*, const char*, const char*);
+extern char* coinit(int);
+extern int coexport(Coshell_t*, const char*, const char*);
+extern int cokill(Coshell_t*, Cojob_t*, int);
+extern Coshell_t* coopen(const char*, int, const char*);
+extern void coquote(Sfio_t*, const char*, int);
+extern int cosync(Coshell_t*, const char*, int, int);
+extern Cojob_t* cowait(Coshell_t*, Cojob_t*, int);
+
+extern int cojobs(Coshell_t*);
+extern int copending(Coshell_t*);
+extern int cozombie(Coshell_t*);
+
+extern int coattr(Coshell_t*, const char*);
+
+extern int coprocrun(const char*, char**, int);
+extern int cosystem(const char*);
+
+#endif
diff --git a/src/lib/libcoshell/costash.c b/src/lib/libcoshell/costash.c
new file mode 100644
index 0000000..c378909
--- /dev/null
+++ b/src/lib/libcoshell/costash.c
@@ -0,0 +1,40 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ */
+
+#include <colib.h>
+
+/*
+ * 0 terminate string stream, reset, and return value
+ */
+
+char*
+costash(Sfio_t* sp)
+{
+ char* s;
+
+ if (!(s = sfstruse(sp)))
+ errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
+ return s;
+}
diff --git a/src/lib/libcoshell/cosync.c b/src/lib/libcoshell/cosync.c
new file mode 100644
index 0000000..4439efa
--- /dev/null
+++ b/src/lib/libcoshell/cosync.c
@@ -0,0 +1,127 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * sync all outstanding file operations for file opened on fd
+ * if file==0 then fd used
+ * if fd<0 then file used
+ * if mode<0 then fd not created
+ *
+ * NOTE: this is an unfortunate NFS workaround that should be done by fsync()
+ */
+
+#include "colib.h"
+
+#include <ls.h>
+
+#include "FEATURE/nfsd"
+
+int
+cosync(Coshell_t* co, const char* file, int fd, int mode)
+{
+#if defined(_cmd_nfsd)
+ if (!co || (co->flags & CO_SERVER))
+ {
+ char tmp[PATH_MAX];
+
+ if (file && *file)
+ {
+ register const char* s;
+ register char* t;
+ register char* b;
+ int td;
+
+ /*
+ * writing to a dir apparently flushes the
+ * attribute cache for all entries in the dir
+ */
+
+ s = file;
+ b = t = tmp;
+ while (t < &tmp[sizeof(tmp) - 1])
+ {
+ if (!(*t = *s++)) break;
+ if (*t++ == '/') b = t;
+ }
+ s = "..nfs..botch..";
+ t = b;
+ while (t < &tmp[sizeof(tmp) - 1] && (*t++ = *s++));
+ *t = 0;
+ if ((td = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0)) >= 0) close(td);
+ unlink(tmp);
+ if (fd >= 0 && mode >= 0)
+ {
+ if ((td = open(file, mode)) < 0) return(-1);
+ close(fd);
+ dup2(td, fd);
+ close(td);
+ }
+ }
+#if defined(F_SETLK)
+ else
+ {
+ int clean = 0;
+ struct flock lock;
+
+ if (fd < 0)
+ {
+ if (!file || mode < 0 || (fd = open(file, O_RDONLY)) < 0) return(-1);
+ clean = 1;
+ }
+
+ /*
+ * this sets the VNOCACHE flag across NFS
+ */
+
+ lock.l_type = F_RDLCK;
+ lock.l_whence = 0;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ if (!fcntl(fd, F_SETLK, &lock))
+ {
+ lock.l_type = F_UNLCK;
+ fcntl(fd, F_SETLK, &lock);
+ }
+ if (clean) close(fd);
+
+ /*
+ * 4.1 has a bug that lets VNOCACHE linger after unlock
+ * VNOCACHE inhibits mapping which kills exec
+ * the double rename flushes the incore vnode (and VNOCACHE)
+ *
+ * this kind of stuff doesn't happen with *real* file systems
+ */
+
+ if (file && *file)
+ {
+ strcpy(tmp, file);
+ fd = strlen(tmp) - 1;
+ tmp[fd] = (tmp[fd] == '*') ? '?' : '*';
+ if (!rename(file, tmp)) rename(tmp, file);
+ }
+ }
+#endif
+ }
+#endif
+ return(0);
+}
diff --git a/src/lib/libcoshell/cowait.c b/src/lib/libcoshell/cowait.c
new file mode 100644
index 0000000..ccc98d3
--- /dev/null
+++ b/src/lib/libcoshell/cowait.c
@@ -0,0 +1,411 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * wait for and return status of job or the next coshell job that completes
+ * job==co for non-blocking wait
+ */
+
+#include "colib.h"
+
+#include <ctype.h>
+
+/*
+ * cat and remove fd {1,2} serialized output
+ */
+
+static void
+cat(Cojob_t* job, char** path, Sfio_t* op)
+{
+ Sfio_t* sp;
+
+ if (sp = sfopen(NiL, *path, "r"))
+ {
+ sfmove(sp, op, SF_UNBOUND, -1);
+ sfclose(sp);
+ }
+ else
+ errormsg(state.lib, ERROR_LIBRARY|2, "%s: cannot open job %d serialized output", *path, job->id);
+ remove(*path);
+ free(*path);
+ *path = 0;
+}
+
+/*
+ * the number of running+zombie jobs
+ * these would count against --jobs or NPROC
+ */
+
+int
+cojobs(Coshell_t* co)
+{
+ int any;
+ int n;
+
+ if (co)
+ any = 0;
+ else if (!(co = state.coshells))
+ return -1;
+ else
+ any = 1;
+ n = 0;
+ do
+ {
+ n += co->outstanding;
+ } while (any && (co = co->next));
+ return n;
+}
+
+/*
+ * the number of pending cowait()'s
+ */
+
+int
+copending(Coshell_t* co)
+{
+ int any;
+ int n;
+
+ if (co)
+ any = 0;
+ else if (!(co = state.coshells))
+ return -1;
+ else
+ any = 1;
+ n = 0;
+ do
+ {
+ n += co->outstanding + co->svc_outstanding;
+ } while (any && (co = co->next));
+ return n;
+}
+
+/*
+ * the number of completed jobs not cowait()'d for
+ * cowait() always reaps the zombies first
+ */
+
+int
+cozombie(Coshell_t* co)
+{
+ int any;
+ int n;
+
+ if (co)
+ any = 0;
+ else if (!(co = state.coshells))
+ return -1;
+ else
+ any = 1;
+ n = 0;
+ do
+ {
+ n += (co->outstanding + co->svc_outstanding) - (co->running + co->svc_running);
+ } while (any && (co = co->next));
+ return n;
+}
+
+Cojob_t*
+cowait(register Coshell_t* co, Cojob_t* job, int timeout)
+{
+ register char* s;
+ register Cojob_t* cj;
+ register Coservice_t* cs;
+ register ssize_t n;
+ char* b;
+ char* e;
+ unsigned long user;
+ unsigned long sys;
+ int active;
+ int any;
+ int id;
+ int loop;
+ int to;
+ int type;
+ char buf[128];
+
+ static unsigned long serial = 0;
+
+ serial++;
+ if (co || job && (co = job->coshell))
+ any = 0;
+ else if (!(co = state.coshells))
+ goto echild;
+ else
+ any = 1;
+
+ /*
+ * first drain the zombies
+ */
+
+ active = 0;
+ to = timeout >= 0 ? timeout : 60 * 1000;
+ zombies:
+ do
+ {
+#if 0
+ errormsg(state.lib, 2, "coshell %d zombie wait %lu timeout=%d outstanding=<%d,%d> running=<%d,%d>", co->index, serial, timeout, co->outstanding, co->svc_outstanding, co->running, co->svc_running);
+#endif
+ if ((co->outstanding + co->svc_outstanding) > (co->running + co->svc_running))
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (cj->pid == CO_PID_ZOMBIE && (!job || cj == job))
+ {
+ cj->pid = CO_PID_FREE;
+ if (cj->service)
+ co->svc_outstanding--;
+ else
+ co->outstanding--;
+#if 0
+ errormsg(state.lib, 2, "coshell %d zombie wait %lu timeout=%d outstanding=<%d,%d> running=<%d,%d> reap job %d", co->index, serial, timeout, co->outstanding, co->svc_outstanding, co->running, co->svc_running, cj->id);
+#endif
+ return cj;
+ }
+ else if (cj->service && !cj->service->pid)
+ {
+ cj->pid = CO_PID_ZOMBIE;
+ cj->status = 2;
+ cj->service = 0;
+ co->svc_running--;
+ }
+ if (co->running > 0)
+ active = 1;
+ else if (co->svc_running > 0)
+ {
+ n = 0;
+ for (cs = co->service; cs; cs = cs->next)
+ if (cs->pid && kill(cs->pid, 0))
+ {
+ cs->pid = 0;
+ close(cs->fd);
+ cs->fd = -1;
+ n = 1;
+ }
+ if (n)
+ goto zombies;
+ active = 1;
+ }
+ } while (any && (co = co->next));
+
+ /*
+ * reap the active jobs
+ */
+
+ if (!active)
+ goto echild;
+ if (any)
+ co = state.coshells;
+ do
+ {
+ loop = 0;
+ for (;;)
+ {
+ if (co->flags & CO_DEBUG)
+ {
+ loop++;
+ errormsg(state.lib, 2, "coshell %d wait %lu.%d timeout=%d outstanding=<%d,%d> running=<%d,%d>", co->index, serial, loop, timeout, co->outstanding, co->svc_outstanding, co->running, co->svc_running);
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (cj->pid != CO_PID_FREE)
+ errormsg(state.lib, 2, "\tjob %d pid=%d status=%d", cj->id, cj->pid, cj->status);
+ }
+ if (co->running <= 0)
+ break;
+ while ((n = sfpoll(&co->msgfp, 1, to)) < 1)
+ {
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ return 0;
+ break;
+ }
+ if (timeout >= 0)
+ break;
+
+ /*
+ * check for a killed job with no status
+ */
+
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (cj->pid > 0)
+ {
+ n = sfsprintf(buf, sizeof(buf), "kill -0 %d 2>/dev/null || echo k %d `wait %d 2>/dev/null; echo $?` >&$%s\n", cj->pid, cj->id, cj->pid, CO_ENV_MSGFD);
+ write(co->cmdfd, buf, n);
+ break;
+ }
+ }
+
+ /*
+ * get one coshell message
+ */
+
+ if (!(s = b = sfgetr(co->msgfp, '\n', 1)))
+ break;
+#if 0
+ errormsg(state.lib, 2, "coshell %d active wait %lu timeout=%d outstanding=<%d,%d> running=<%d,%d>", co->index, serial, timeout, co->outstanding, co->svc_outstanding, co->running, co->svc_running);
+#endif
+
+ /*
+ * read and parse a coshell message packet of the form
+ *
+ * <type> <id> <args> <newline>
+ * %c %d %s %c
+ */
+
+ while (isspace(*s))
+ s++;
+ if (!(type = *s) || type != 'a' && type != 'j' && type != 'k' && type != 'x')
+ goto invalid;
+ while (*++s && !isspace(*s));
+ id = strtol(s, &e, 10);
+ if (*e && !isspace(*e))
+ goto invalid;
+ for (s = e; isspace(*s); s++);
+
+ /*
+ * locate id in the job list
+ */
+
+ for (cj = co->jobs; cj; cj = cj->next)
+ if (id == cj->id)
+ break;
+ if ((co->flags | (cj ? cj->flags : 0)) & CO_DEBUG)
+ errormsg(state.lib, 2, "coshell %d message \"%c %d %s\"", co->index, type, id, s);
+ if (!cj)
+ {
+ if (type == 'k')
+ continue;
+ errormsg(state.lib, 2, "coshell %d job id %d not found [%s]", co->index, id, b);
+ errno = ESRCH;
+ return 0;
+ }
+
+ /*
+ * now interpret the message
+ */
+
+ switch (type)
+ {
+
+ case 'a':
+ /*
+ * coexec() ack
+ */
+
+ if (cj == job)
+ return cj;
+ break;
+
+ case 'j':
+ /*
+ * <s> is the job pid
+ */
+
+ n = cj->pid;
+ cj->pid = strtol(s, NiL, 10);
+ if (n == CO_PID_WARPED)
+ goto nuke;
+ break;
+
+ case 'k':
+ /*
+ * <s> is a synthesized killed status
+ */
+
+ if (cj->pid < 0)
+ continue;
+ /*FALLTHROUGH*/
+
+ case 'x':
+ /*
+ * <s> is the job exit code and user,sys times
+ */
+
+ cj->status = strtol(s, &e, 10);
+ user = sys = 0;
+ for (;;)
+ {
+ if (e <= s)
+ break;
+ for (s = e; isalpha(*s) || isspace(*s); s++);
+ user += strelapsed(s, &e, CO_QUANT);
+ if (e <= s)
+ break;
+ for (s = e; isalpha(*s) || isspace(*s); s++);
+ sys += strelapsed(s, &e, CO_QUANT);
+ }
+ cj->user += user;
+ cj->sys += sys;
+ co->user += user;
+ co->sys += sys;
+ if (cj->out)
+ cat(cj, &cj->out, sfstdout);
+ if (cj->err)
+ cat(cj, &cj->err, sfstderr);
+ if (cj->pid > 0 || cj->service || (co->flags & (CO_INIT|CO_SERVER)))
+ {
+ nuke:
+ if (cj->pid > 0 && type != 'k')
+ {
+ /*
+ * nuke the zombies
+ */
+
+ n = sfsprintf(buf, sizeof(buf), "wait %d\n", cj->pid);
+ write(co->cmdfd, buf, n);
+ }
+ if (cj->service)
+ co->svc_running--;
+ else
+ co->running--;
+ if (!job || cj == job)
+ {
+ cj->pid = CO_PID_FREE;
+ if (cj->service)
+ co->svc_outstanding--;
+ else
+ co->outstanding--;
+#if 0
+ errormsg(state.lib, 2, "coshell %d active wait %lu timeout=%d outstanding=<%d,%d> running=<%d,%d> reap job %d", co->index, serial, timeout, co->outstanding, co->svc_outstanding, co->running, co->svc_running, cj->id);
+#endif
+ return cj;
+ }
+ cj->pid = CO_PID_ZOMBIE;
+ }
+ else
+ cj->pid = CO_PID_WARPED;
+ break;
+
+ }
+ }
+ } while (any && (co = co->next));
+ return 0;
+ echild:
+#if 0
+ errormsg(state.lib, 2, "coshell wait ECHILD");
+#endif
+ errno = ECHILD;
+ return 0;
+ invalid:
+ errormsg(state.lib, 2, "coshell %d invalid message \"%-.*s>>>%s<<<\"", co->index, s - b, b, s);
+ errno = EINVAL;
+ return 0;
+}
diff --git a/src/lib/libcoshell/ignore.sh b/src/lib/libcoshell/ignore.sh
new file mode 100644
index 0000000..f70002e
--- /dev/null
+++ b/src/lib/libcoshell/ignore.sh
@@ -0,0 +1,45 @@
+########################################################################
+# #
+# This software is part of the ast package #
+# Copyright (c) 1990-2011 AT&T Intellectual Property #
+# and is licensed under the #
+# Eclipse Public License, Version 1.0 #
+# by AT&T Intellectual Property #
+# #
+# A copy of the License is available at #
+# http://www.eclipse.org/org/documents/epl-v10.html #
+# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
+# #
+# Information and Software Systems Research #
+# AT&T Research #
+# Florham Park NJ #
+# #
+# Glenn Fowler <gsf@research.att.com> #
+# #
+########################################################################
+:
+#
+# Glenn Fowler
+# AT&T Bell Laboratories
+#
+# Bourne coshell support
+#
+# @(#)ignore (AT&T Bell Laboratories) 08/11/92
+#
+while :
+do case $# in
+ 0) exit 0 ;;
+ esac
+ case $1 in
+ *=*) case $RANDOM in
+ $RANDOM)`echo $1 | sed "s/\\([^=]*\\)=\\(.*\\)/eval \\1='\\2'; export \\1/"` ;;
+ *) export "$1" ;;
+ esac
+ shift
+ ;;
+ *) break
+ ;;
+ esac
+done
+"$@"
+exit 0
diff --git a/src/lib/libcoshell/procrun.c b/src/lib/libcoshell/procrun.c
new file mode 100644
index 0000000..cdd5357
--- /dev/null
+++ b/src/lib/libcoshell/procrun.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * coshell procrun(3)
+ */
+
+#include "colib.h"
+
+#include <proc.h>
+
+int
+coprocrun(const char* path, char** argv, int flags)
+{
+ register char* s;
+ register char** a;
+ register Sfio_t* tmp;
+ int n;
+
+ if (!(a = argv))
+ return procclose(procopen(path, a, NiL, NiL, PROC_FOREGROUND|PROC_GID|PROC_UID|flags));
+ if (!(tmp = sfstropen()))
+ return -1;
+ sfputr(tmp, path ? path : "sh", -1);
+ while (s = *++a)
+ {
+ sfputr(tmp, " '", -1);
+ coquote(tmp, s, 0);
+ sfputc(tmp, '\'');
+ }
+ if (!(s = costash(tmp)))
+ return -1;
+ n = cosystem(s);
+ sfstrclose(tmp);
+ return n;
+}
diff --git a/src/lib/libcoshell/silent.sh b/src/lib/libcoshell/silent.sh
new file mode 100644
index 0000000..1f3f4b7
--- /dev/null
+++ b/src/lib/libcoshell/silent.sh
@@ -0,0 +1,44 @@
+########################################################################
+# #
+# This software is part of the ast package #
+# Copyright (c) 1990-2011 AT&T Intellectual Property #
+# and is licensed under the #
+# Eclipse Public License, Version 1.0 #
+# by AT&T Intellectual Property #
+# #
+# A copy of the License is available at #
+# http://www.eclipse.org/org/documents/epl-v10.html #
+# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
+# #
+# Information and Software Systems Research #
+# AT&T Research #
+# Florham Park NJ #
+# #
+# Glenn Fowler <gsf@research.att.com> #
+# #
+########################################################################
+:
+#
+# Glenn Fowler
+# AT&T Bell Laboratories
+#
+# Bourne coshell support
+#
+# @(#)silent (AT&T Bell Laboratories) 08/11/92
+#
+while :
+do case $# in
+ 0) exit 0 ;;
+ esac
+ case $1 in
+ *=*) case $RANDOM in
+ $RANDOM)`echo $1 | sed "s/\\([^=]*\\)=\\(.*\\)/eval \\1='\\2'; export \\1/"` ;;
+ *) export "$1" ;;
+ esac
+ shift
+ ;;
+ *) break
+ ;;
+ esac
+done
+"$@"
diff --git a/src/lib/libcoshell/system.c b/src/lib/libcoshell/system.c
new file mode 100644
index 0000000..9179ef8
--- /dev/null
+++ b/src/lib/libcoshell/system.c
@@ -0,0 +1,57 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1990-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * coshell system(3)
+ */
+
+#include "colib.h"
+
+int
+cosystem(const char* cmd)
+{
+ Coshell_t* co;
+ Cojob_t* cj;
+ int status;
+
+ if (!cmd)
+ return !eaccess(pathshell(), X_OK);
+ if (!(co = coopen(NiL, CO_ANY, NiL)))
+ return -1;
+ if (cj = coexec(co, cmd, CO_SILENT, NiL, NiL, NiL))
+ cj = cowait(co, cj, -1);
+ if (!cj)
+ return -1;
+
+ /*
+ * synthesize wait() status from shell status
+ * lack of synthesis is the standard's proprietary sellout
+ */
+
+ status = cj->status;
+ if (EXITED_TERM(status))
+ status &= ((1<<(EXIT_BITS-1))-1);
+ else
+ status = (status & ((1<<EXIT_BITS)-1)) << EXIT_BITS;
+ return status;
+}