COSHELL(3)
โจ coshell(3) โ shell coprocess support โจ
okay bestie, so this is coshell(3) from the Library Functions Manual, and it's literally the whole "run a shell as a coprocess" situation. Sit down, grab a lil drink ๐, we're doing this.
๐ธ NAME ๐ธ
coshell โ shell coprocess support ๐
๐ฆ SYNOPSIS ๐ฆ
#include <coshell.h>
-lcoshell -last
link it up with -lcoshell -last, no cap.
๐ DESCRIPTION ๐
The coshell routines are the whole support system for treating a shell as a coprocess. And like, this coprocess can be either ksh(1) or sh(1) running on the local host, or it can be coshell(1) with access to shells on hosts all over your local network. it's giving networking era ๐
The coshell inherits the environment of the calling process. And signals sent to the calling process are passed along to the coshell, too โ they stay in sync, periodt.
Also bestie, you can have more than one coshell open in the current process. and here's the slay part: if the Coshell_t* argument to cowait(), cokill(), copending(), cozombie(), or coclose() is 0, then the call gets applied to all open coshells. all of them. every single one ๐
๐ the opening move: coopen ๐
Coshell_t* coopen(const char* shell, int flags, const char* attributes)
Returns a pointer to a new coshell. NULL comes back on error ๐ญ.
If shell is NULL then the coshell executable is figured out by doing the usual path search, in order, on the value of the environment variable COSHELL and the commands ksh and sh. iykyk.
flags is the inclusive-or of these icons:
CO_ANYโ return a pointer to a previously opened coshell if possible; otherwise open a brand new coshell. reusing is giving sustainable queen โป๏ธCO_DEBUGโ turn on library debug tracing.CO_IGNOREโ ignore any command errors. by default, any command error that isn't tested by a conditional causes the job to terminate. so this is the "no thoughts head empty" flag ๐CO_LOCALโ commands are to be executed on the local host only. stay home bestie ๐CO_SHELLโ the caller issh(1): internal file descriptors get moved to10or above, andSIGSTOPandSIGCONThandlers are not installed.CO_SILENTโ don't trace commands. by default commands are traced using the shell-xoption. (so this is the "stop narrating my life" flag ๐)CO_NONBLOCKโ normallycoexec()blocks when the job queue is full and waits until a job completes.CO_NONBLOCKmakescoexec()returnNULLwhen the job queue is full instead of waiting. no queuing, we die like icons ๐
attributes is a string that gets interpreted by the coshell. If attributes is NULL then the value of the environment variable COATTRIBUTES is used if it's defined. ksh and sh ignore this string entirely (rude but ok).
The return value points to a structure with these readonly elements:
int flagsโ the default flags.int outstandingโ the number of jobs that have not been waited for.int runningโ the number of jobs still running.int totalโ the total number of jobs sent to the coshell.unsigned long userโ the total user time of all completed jobs, in1/CO_QUANTsecond increments.unsigned long sysโ the total system time of all completed jobs, in1/CO_QUANTsecond increments.
๐ coclose โ the goodbye ๐
int coclose(Coshell_t* sh)
Closes an open coshell pointed to by sh, and the coshell exit status is returned. it's giving closure, literally ๐ซถ
๐ฅ coexec โ send it ๐ฅ
Cojob_t* coexec(Coshell_t* sh, const char* cmd, int flags, const char* out, const char* err, const char* att)
Sends the shell command line cmd to the open coshell pointed to by sh for execution. go little command go ๐
flagsare the same as in thecoopen()call, and are used to augment the default settings fromcoopen().outis the standard output file name and defaults tostdoutifNULL.erris the standard error file name and defaults tostderrifNULL.att, if non-NULL, contains job attributes that are appended to the attributes fromcoopen()before being sent to the coshell.
The return value points to a structure with these elements:
int idโ a number that uniquely identifies the job within the coshell.int statusโ the job exit status, valid only for job pointers returned bycowait().int flagsโ the flags enabled for this job.void* localโ a user reserved pointer, initially set toNULLon return fromcoexec(). This is the only job field that may be modified by the user. The user defined value is preserved until after thecowait()call that returns the job pointer. it's your little pocket, protect it ๐unsigned long userโ the user time of this job in1/CO_QUANTsecond increments, valid only for job pointers returned bycowait().unsigned long sysโ the system time of this job in1/CO_QUANTsecond increments, valid only for job pointers returned bycowait().
โญ cowait โ the waiting game โญ
Cojob_t* cowait(Coshell_t* sh, Cojob_t* job, int timeout)
Returns the job pointer in the coshell pointed to by sh for the job pointed to by job. If job is NULL then a pointer to any completed job is returned. cowait() blocks until the specified job(s) complete โ so yes, it will just stand there. patiently. like a bestie holding your bag ๐
NULL is returned on error, or if all jobs have completed. and errno gets set to:
EINVALfor coshell communication errorsECHILDifjobisNULLand there are no childrenESRCHifjobis notNULLand it's not an active job
cozombie(sh) is the number of jobs that may be waited for without blocking. The return value status, user and sys job fields are set to their final values. The return value is valid until the next coexec(), cowait() or coclose() call โ so don't go hoarding it, it expires ๐ญ
timeout is the maximum time in milliseconds that wait will block. If the wait times out then 0 is returned. A negative timeout waits until a job completes or a signal is received. negative timeout is the "I have all the time in the world" era ๐ฆ
๐ the little counters ๐
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, ok? don't @ me)int copending(Coshell_t* sh)โ returns the number of pending jobs; this is the number ofcowait()calls required to reap all running jobs. math queen ๐งฎint cozombie(Coshell_t* sh)โ returns the number of jobs that have completed but have not beencowait()'d for. the undead jobs ๐ง
๐ง cokill โ sending the vibes (and signals) ๐ง
int cokill(Coshell_t* sh, Cojob_t* job, int sig)
The signal sig is sent to the job pointed to by job running in the coshell pointed to by sh.
- If
jobisNULLthen the signal is sent to all jobs in the coshell. - If both
shandjobareNULLthen the signal is sent to all jobs in all coshells. yes, all of them. chaos mode activated ๐
-1 is returned on error, 0 otherwise.
๐ cosync โ the NFS workaround era ๐
int cosync(Coshell_t* sh, const char* path, int fd, int mode)
Sync all outstanding file operations for either the file path or the file descriptor fd, after its shell action has completed in sh.
- If
pathisNULLthenfdis used. - If
fd<0andmode>=0thenpathis opened usingmode.
This is an unfortunate workaround for NFS and remote coshells, and it's a no-op for all real file systems. It should be called after cowait() to ensure that all file system cache info has been flushed. But heads up bestie: sync(2) or fsync(2) must still be called to schedule file data to be written to disk. so it's not a substitute, it's a supplement ๐
๐ coinit โ get the init commands ๐
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 coinit(), e.g. current working directory or umask.
If sh is local (a child of the calling process) coinit() may return the empty string; if 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. so like, if you're here, you're built different ๐ซก
๐
coquote โ the quoting queen ๐
void coquote(Sfio_T* sp, const char* string, int type)
Applies shell single quoting to string and copies the result into the sfio stream sp.
If type!=0 then any occurence of /hosttype/ is translated to /$HOSTTYPE/, where hosttype is the current value of the HOSTTYPE environment variable. (yes, "occurence" โ we're keeping it exactly as written, don't come for me ๐)
This routine is used by remote coshell implementations and is not normally called from user code. same energy as above. iconic but off-limits ๐
๐ CAVEATS ๐
cosync() is a hack workaround, but we do have to work in the real world. ๐ญ reality is unfortunately real.
A bug inbsh(1)andksh(1)implementations up to and includingksh88ecauses some interrupted jobs to return0exit status. This should be fixed in later shell releases. so if you see a0where you expected pain, that's the bug, not you ๐
trap 0is reserved bycoexec()at the outermost scope. To usetrap 0use(...)to force a subshell. don't fight it, just wrap it in parens bestie ๐
๐ธ SEE ALSO ๐ธ
coshell(1), ksh(1), nmake(1), sh(1), cs(3), libast(3)
read them, love them, link them ๐
okay that's the whole page, you ate that. this was coshell(3) out of the Library Functions Manual โ go forth and coprocess, bestie. mwah ๐โจ๐
๐ฆ where this page comes from
- opensuse-leap 16.0: ksh-devel 93vu-bp160.1.33 ยท CPL-1.0
- opensuse-leap 16.0: ksh-devel 93vu-bp160.1.33 ยท CPL-1.0
- opensuse-leap 16.0: ksh-devel 93vu-bp160.1.33 ยท CPL-1.0
- opensuse-leap 16.0: ksh-devel 93vu-bp160.1.33 ยท CPL-1.0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms