Home | History | Annotate | Download | only in bltins
      1  4887   chin /***********************************************************************
      2  4887   chin *                                                                      *
      3  4887   chin *               This software is part of the ast package               *
      4  8462  April *          Copyright (c) 1982-2007 AT&T Intellectual Property          *
      5  4887   chin *                      and is licensed under the                       *
      6  4887   chin *                  Common Public License, Version 1.0                  *
      7  8462  April *                    by AT&T Intellectual Property                     *
      8  4887   chin *                                                                      *
      9  4887   chin *                A copy of the License is available at                 *
     10  4887   chin *            http://www.opensource.org/licenses/cpl1.0.txt             *
     11  4887   chin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
     12  4887   chin *                                                                      *
     13  4887   chin *              Information and Software Systems Research               *
     14  4887   chin *                            AT&T Research                             *
     15  4887   chin *                           Florham Park NJ                            *
     16  4887   chin *                                                                      *
     17  4887   chin *                  David Korn <dgk (at) research.att.com>                   *
     18  4887   chin *                                                                      *
     19  4887   chin ***********************************************************************/
     20  4887   chin #pragma prototyped
     21  4887   chin 
     22  4887   chin #include	<shell.h>
     23  4887   chin #include	<stdio.h>
     24  8462  April #include	<stdbool.h>
     25  4887   chin #include	<option.h>
     26  4887   chin #include	<stk.h>
     27  4887   chin #include	<tm.h>
     28  4887   chin #include	"name.h"
     29  4887   chin #undef nv_isnull
     30  4887   chin #ifndef SH_DICT
     31  4887   chin #   define SH_DICT     "libshell"
     32  4887   chin #endif
     33  4887   chin #include	<poll.h>
     34  8462  April 
     35  8462  April #define sh_contexttoshb(context)	((Shbltin_t*)(context))
     36  8462  April #define sh_contexttoshell(context)	((context)?(sh_contexttoshb(context)->shp):(NULL))
     37  4887   chin 
     38  4887   chin /*
     39  4887   chin  * time formatting related
     40  4887   chin */
     41  4887   chin struct dctime
     42  4887   chin {
     43  4887   chin 	Namfun_t	fun;
     44  4887   chin 	Namval_t 	*format;
     45  4887   chin 	char		buff[256]; /* Must be large enougth for |tmfmt()| */
     46  4887   chin };
     47  4887   chin 
     48  4887   chin static char *get_time(Namval_t* np, Namfun_t* nfp)
     49  4887   chin {
     50  4887   chin 	struct dctime *dp = (struct dctime*)nfp;
     51  4887   chin 	time_t t = nv_getn(np,nfp);
     52  4887   chin 	char *format = nv_getval(dp->format);
     53  4887   chin 	tmfmt(dp->buff,sizeof(dp->buff),format,(time_t*)0);
     54  4887   chin 	return(dp->buff);
     55  4887   chin }
     56  4887   chin 
     57  4887   chin static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
     58  4887   chin {
     59  4887   chin 	struct dctime *dp = (struct dctime*)nfp;
     60  4887   chin 	char *last;
     61  4887   chin 	if(val)
     62  4887   chin 	{
     63  4887   chin 		int32_t t;
     64  4887   chin 		if(flag&NV_INTEGER)
     65  4887   chin 		{
     66  4887   chin 			if(flag&NV_LONG)
     67  4887   chin 				t = *(Sfdouble_t*)val;
     68  4887   chin 			else
     69  4887   chin 				t = *(double*)val;
     70  4887   chin 		}
     71  4887   chin 		else
     72  4887   chin 		{
     73  4887   chin 			t = tmdate(val, &last, (time_t*)0);
     74  4887   chin 			if(*last)
     75  4887   chin 				errormsg(SH_DICT, ERROR_exit(1),"%s: invalid date/time string", val);
     76  4887   chin 		}
     77  4887   chin 		nv_putv(np, (char*)&t,NV_INTEGER, nfp);
     78  4887   chin 	}
     79  4887   chin 	else
     80  4887   chin 	{
     81  4887   chin 		nv_unset(dp->format);
     82  4887   chin 		free((void*)dp->format);
     83  4887   chin 		nv_putv(np, val, flag, nfp);
     84  4887   chin 	}
     85  4887   chin }
     86  4887   chin 
     87  4887   chin static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
     88  4887   chin {
     89  4887   chin 	struct dctime *dp = (struct dctime*)nfp;
     90  4887   chin 	if(strcmp(name, "format"))
     91  4887   chin 		return((Namval_t*)0);
     92  4887   chin 	return(dp->format);
     93  4887   chin }
     94  4887   chin 
     95  4887   chin static const Namdisc_t timedisc =
     96  4887   chin {
     97  4887   chin         sizeof(struct dctime),
     98  4887   chin         put_time,
     99  4887   chin         get_time,
    100  4887   chin         0,
    101  4887   chin         0,
    102  4887   chin         create_time,
    103  4887   chin };
    104  4887   chin 
    105  4887   chin 
    106  4887   chin static Namval_t *make_time(Namval_t* np)
    107  4887   chin {
    108  4887   chin 	int offset = stktell(stkstd);
    109  4887   chin 	char *name = nv_name(np);
    110  4887   chin 	struct dctime *dp = newof(NULL,struct dctime,1,0);
    111  4887   chin 	if(!dp)
    112  4887   chin 		return((Namval_t*)0);
    113  4887   chin 	sfprintf(stkstd,"%s.format\0",name);
    114  4887   chin 	sfputc(stkstd,0);
    115  4887   chin 	dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
    116  4887   chin 	dp->fun.disc = &timedisc;
    117  4887   chin 	nv_stack(np,&dp->fun);
    118  4887   chin 	return(np);
    119  4887   chin }
    120  4887   chin 
    121  4887   chin /*
    122  4887   chin  * mode formatting related
    123  4887   chin */
    124  4887   chin static char *get_mode(Namval_t* np, Namfun_t* nfp)
    125  4887   chin {
    126  4887   chin 	mode_t mode = nv_getn(np,nfp);
    127  4887   chin 	return(fmtperm(mode));
    128  4887   chin }
    129  4887   chin 
    130  4887   chin static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
    131  4887   chin {
    132  4887   chin 	if(val)
    133  4887   chin 	{
    134  4887   chin 		int32_t mode;
    135  4887   chin 		char *last;
    136  4887   chin 		if(flag&NV_INTEGER)
    137  4887   chin 		{
    138  4887   chin 			if(flag&NV_LONG)
    139  4887   chin 				mode = *(Sfdouble_t*)val;
    140  4887   chin 			else
    141  4887   chin 				mode = *(double*)val;
    142  4887   chin 		}
    143  4887   chin 		else
    144  4887   chin 		{
    145  4887   chin 			mode = strperm(val, &last,0);
    146  4887   chin 			if(*last)
    147  4887   chin 				errormsg(SH_DICT, ERROR_exit(1),"%s: invalid mode string", val);
    148  4887   chin 		}
    149  4887   chin 		nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
    150  4887   chin 	}
    151  4887   chin 	else
    152  4887   chin 		nv_putv(np,val,flag,nfp);
    153  4887   chin }
    154  4887   chin 
    155  4887   chin static const Namdisc_t modedisc =
    156  4887   chin {
    157  4887   chin 	0,
    158  4887   chin         put_mode,
    159  4887   chin         get_mode,
    160  4887   chin };
    161  4887   chin 
    162  4887   chin static Namval_t *make_mode(Namval_t* np)
    163  4887   chin {
    164  4887   chin 	char *name = nv_name(np);
    165  4887   chin 	Namfun_t *nfp = newof(NULL,Namfun_t,1,0);
    166  4887   chin 	if(!nfp)
    167  4887   chin 		return((Namval_t*)0);
    168  4887   chin 	nfp->disc = &modedisc;
    169  4887   chin 	nv_stack(np,nfp);
    170  4887   chin 	return(np);
    171  4887   chin }
    172  4887   chin 
    173  4887   chin /*
    174  4887   chin  *  field related typese and functions
    175  4887   chin  */
    176  4887   chin typedef struct _field_
    177  4887   chin {
    178  4887   chin 	char		*name;		/* field name */
    179  4887   chin 	int		flags;		/* flags */
    180  4887   chin 	short		offset;		/* offset of field into data */
    181  4887   chin 	short		size;		/* size of field */
    182  4887   chin 	Namval_t	*(*make)(Namval_t*);	/* discipline constructor */
    183  4887   chin } Shfield_t;
    184  4887   chin 
    185  4887   chin /*
    186  4887   chin  * lookup field in field table
    187  4887   chin  */
    188  4887   chin static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name)
    189  4887   chin {
    190  4887   chin 	Shfield_t *fp = ftable;
    191  4887   chin 	register int i,n;
    192  4887   chin 	register const char *cp;
    193  4887   chin 	for(cp=name; *cp; cp++)
    194  4887   chin 	{
    195  4887   chin 		if(*cp=='.')
    196  4887   chin 			break;
    197  4887   chin 	}
    198  4887   chin 	n = cp-name;
    199  4887   chin 	for(i=0; i < nelem; i++,fp++)
    200  4887   chin 	{
    201  4887   chin 		if(memcmp(fp->name,name,n)==0 && fp->name[n]==0)
    202  4887   chin 			return(fp);
    203  4887   chin 	}
    204  4887   chin 	return(0);
    205  4887   chin }
    206  4887   chin 
    207  4887   chin /*
    208  4887   chin  * class types and functions
    209  4887   chin  */
    210  4887   chin 
    211  4887   chin typedef struct _class_
    212  4887   chin {
    213  4887   chin 	int		nelem;		/* number of elements */
    214  4887   chin 	int		dsize;		/* size for data structure */
    215  4887   chin 	Shfield_t 	*fields;	/* field description table */
    216  4887   chin } Shclass_t;
    217  4887   chin 
    218  4887   chin struct dcclass
    219  4887   chin {
    220  4887   chin 	Namfun_t	fun;
    221  4887   chin 	Shclass_t	sclass;
    222  4887   chin };
    223  4887   chin 
    224  4887   chin static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np)
    225  4887   chin {
    226  4887   chin 	char *val = np->nvalue + fp->offset;
    227  4887   chin 	char *name = nv_name(np);
    228  4887   chin 	register Namval_t *nq;
    229  4887   chin 	int offset = stktell(stkstd);
    230  4887   chin 	sfprintf(stkstd,"%s.%s\0",name,fp->name);
    231  4887   chin 	sfputc(stkstd,0);
    232  4887   chin 	nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
    233  4887   chin 	if(fp->size<0)
    234  4887   chin 		val = *(char**)val;
    235  4887   chin 	nv_putval(nq,val,fp->flags|NV_NOFREE);
    236  4887   chin 	if(fp->make)
    237  4887   chin 		(*fp->make)(nq);
    238  4887   chin 	return(nq);
    239  4887   chin }
    240  4887   chin 
    241  4887   chin static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
    242  4887   chin {
    243  4887   chin 	struct dcclass *dcp = (struct dcclass*)nfp;
    244  4887   chin 	Shclass_t *sp = &dcp->sclass;
    245  4887   chin 	Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name);
    246  4887   chin 	Namval_t *nq,**nodes = (Namval_t**)(dcp+1);
    247  4887   chin 	int n = fp-sp->fields;
    248  4887   chin 	int len =  strlen(fp->name);
    249  4887   chin 	void *data = (void*)np->nvalue;
    250  4887   chin 	if(!(nq=nodes[n]))
    251  4887   chin 	{
    252  4887   chin 		nodes[n] = nq = sh_newnode(fp,np);
    253  4887   chin 		nfp->last = "";
    254  4887   chin 	}
    255  4887   chin 	if(name[len]==0)
    256  4887   chin 		return(nq);
    257  4887   chin 	return(nq);
    258  4887   chin }
    259  4887   chin 
    260  4887   chin static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar)
    261  4887   chin {
    262  4887   chin 	Shfield_t *fp = sp->fields;
    263  4887   chin 	Namval_t *np, **nodes= (Namval_t**)(sp+1);
    264  4887   chin 	register int i,isarray;
    265  4887   chin 	if(out)
    266  4887   chin 	{
    267  4887   chin 		sfwrite(out,"(\n",2);
    268  4887   chin 		indent++;
    269  4887   chin 	}
    270  4887   chin 	for(i=0; i < sp->nelem; i++,fp++)
    271  4887   chin 	{
    272  4887   chin #if 0
    273  4887   chin 		/* handle recursive case */
    274  4887   chin #endif
    275  4887   chin 		if(!(np=nodes[i]) && out)
    276  4887   chin 			np = sh_newnode(fp,npar);
    277  4887   chin 		if(np)
    278  4887   chin 		{
    279  4887   chin 			isarray=0;
    280  4887   chin 			if(nv_isattr(np,NV_ARRAY))
    281  4887   chin 			{
    282  4887   chin 				isarray=1;
    283  4887   chin 				if(array_elem(nv_arrayptr(np))==0)
    284  4887   chin 					isarray=2;
    285  4887   chin 				else
    286  4887   chin 					nv_putsub(np,(char*)0,ARRAY_SCAN);
    287  4887   chin 			}
    288  4887   chin 			sfnputc(out,'\t',indent);
    289  4887   chin 			sfputr(out,fp->name,(isarray==2?'\n':'='));
    290  4887   chin 			if(isarray)
    291  4887   chin 			{
    292  4887   chin 				if(isarray==2)
    293  4887   chin 					continue;
    294  4887   chin 				sfwrite(out,"(\n",2);
    295  4887   chin 				sfnputc(out,'\t',++indent);
    296  4887   chin 			}
    297  4887   chin 			while(1)
    298  4887   chin 			{
    299  4887   chin 				char *fmtq;
    300  4887   chin 				if(isarray)
    301  4887   chin 				{
    302  4887   chin 					sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np)));
    303  4887   chin 					sfputc(out,'=');
    304  4887   chin 				}
    305  4887   chin 				if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq)))
    306  4887   chin 					fmtq = "";
    307  4887   chin 				sfputr(out,fmtq,'\n');
    308  4887   chin 				if(!nv_nextsub(np))
    309  4887   chin 					break;
    310  4887   chin 				sfnputc(out,'\t',indent);
    311  4887   chin 			}
    312  4887   chin 			if(isarray)
    313  4887   chin 			{
    314  4887   chin 				sfnputc(out,'\t',--indent);
    315  4887   chin 				sfwrite(out,")\n",2);
    316  4887   chin 			}
    317  4887   chin 		}
    318  4887   chin 	}
    319  4887   chin 	if(out)
    320  4887   chin 	{
    321  4887   chin 		if(indent>1)
    322  4887   chin 			sfnputc(out,'\t',indent-1);
    323  4887   chin 		sfputc(out,')');
    324  4887   chin 	}
    325  4887   chin }
    326  4887   chin 
    327  4887   chin static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp)
    328  4887   chin {
    329  4887   chin 	static Sfio_t *out;
    330  4887   chin 	Sfio_t *outfile;
    331  4887   chin 	int savtop = stktell(stkstd);
    332  4887   chin 	char *savptr =  stkfreeze(stkstd,0);
    333  4887   chin 	if(dlete)
    334  4887   chin 		outfile = 0;
    335  4887   chin 	else if(!(outfile=out))
    336  4887   chin                 outfile = out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
    337  4887   chin 	else
    338  4887   chin 		sfseek(outfile,0L,SEEK_SET);
    339  4887   chin 	genvalue(outfile,&dcp->sclass,0,np);
    340  4887   chin 	stkset(stkstd,savptr,savtop);
    341  4887   chin 	if(!outfile)
    342  4887   chin 		return((char*)0);
    343  4887   chin 	sfputc(out,0);
    344  4887   chin 	return((char*)out->_data);
    345  4887   chin }
    346  4887   chin 
    347  4887   chin static char *get_classval(Namval_t* np, Namfun_t* nfp)
    348  4887   chin {
    349  4887   chin 	return(walk_class(np,0,(struct dcclass *)nfp));
    350  4887   chin }
    351  4887   chin 
    352  4887   chin static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
    353  4887   chin {
    354  4887   chin 	walk_class(np,1,(struct dcclass *)nfp);
    355  4887   chin 	if(nfp = nv_stack(np,(Namfun_t*)0))
    356  4887   chin 	{
    357  4887   chin 		free((void*)nfp);
    358  4887   chin 		if(np->nvalue && !nv_isattr(np,NV_NOFREE))
    359  4887   chin 			free((void*)np->nvalue);
    360  4887   chin 	}
    361  4887   chin 	if(val)
    362  4887   chin 		nv_putval(np,val,flag);
    363  4887   chin }
    364  4887   chin 
    365  4887   chin static const Namdisc_t classdisc =
    366  4887   chin {
    367  4887   chin         sizeof(struct dcclass),
    368  4887   chin         put_classval,
    369  4887   chin         get_classval,
    370  4887   chin         0,
    371  4887   chin         0,
    372  4887   chin 	fieldcreate
    373  4887   chin };
    374  4887   chin 
    375  4887   chin static int mkclass(Namval_t *np, Shclass_t *sp)
    376  4887   chin {
    377  4887   chin 	struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*));
    378  4887   chin 	if(!tcp)
    379  4887   chin 		return(0);
    380  4887   chin 	memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*));
    381  4887   chin 	tcp->fun.disc = &classdisc;
    382  4887   chin 	tcp->sclass = *sp;
    383  4887   chin 	np->nvalue = (char*)calloc(sp->dsize,1);
    384  4887   chin 	nv_stack(np,&tcp->fun);
    385  4887   chin 	return(1);
    386  4887   chin }
    387  4887   chin 
    388  4887   chin /*
    389  4887   chin  * ====================from here down is file class specific
    390  4887   chin  */
    391  4887   chin static struct stat *Sp;
    392  4887   chin 
    393  4887   chin struct filedata
    394  4887   chin {
    395  4887   chin 	struct stat	statb;
    396  4887   chin 	int		fd;
    397  4887   chin 	char		*name;
    398  4887   chin };
    399  4887   chin 
    400  4887   chin static Shfield_t filefield[] =
    401  4887   chin {
    402  4887   chin 	{ "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time},
    403  4887   chin 	{ "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time},
    404  4887   chin 	{ "dev",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)},
    405  4887   chin 	{ "fd",    NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), 		sizeof(int)},
    406  4887   chin 	{ "gid",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)},
    407  4887   chin 	{ "ino",   NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)},
    408  4887   chin 	{ "mode",  NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode},
    409  4887   chin 	{ "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time},
    410  4887   chin 	{ "name",   NV_RDONLY, offsetof(struct filedata,name), 	-1 },
    411  4887   chin 	{ "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)},
    412  4887   chin 	{ "size",  NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)},
    413  4887   chin 	{ "uid",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)}
    414  4887   chin };
    415  4887   chin 
    416  4887   chin static Shclass_t Fileclass =
    417  4887   chin {
    418  4887   chin 	sizeof(filefield)/sizeof(*filefield),
    419  4887   chin 	sizeof(struct filedata),
    420  4887   chin 	filefield
    421  4887   chin };
    422  4887   chin 
    423  4887   chin 
    424  4887   chin #define letterbit(bit)	(1<<((bit)-'a'))
    425  4887   chin 
    426  4887   chin static const char sh_optopen[] =
    427  4887   chin "[-?\n@(#)$Id: open (AT&T Labs Research) 2007-05-07 $\n]"
    428  4887   chin "[-author?David Korn <dgk (at) research.att.com>]"
    429  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    430  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    431  4887   chin "[+NAME? open - create a shell variable correspnding to a file]"
    432  4887   chin "[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding "
    433  4887   chin 	"to the file given by the pathname \afile\a.  The elements of \avar\a "
    434  4887   chin 	"are the names of elements in the \astat\a structure with the \bst_\b "
    435  4887   chin 	"prefix removed.]"
    436  4887   chin "[+?\afile\a is opened (based on \b-r\b and/or \b-w\b) and the variable "
    437  4887   chin 	"\avar\a\b.fd\b is the file descriptor.]"
    438  4887   chin "[a:append?Open for append.]"
    439  4887   chin "[b:binary?Open in binary mode"
    440  4887   chin #ifndef O_BINARY
    441  4887   chin 	" (not supported/ignored on this platform)"
    442  4887   chin #endif
    443  4887   chin 	".]"
    444  4887   chin "[t:text?Open in text mode"
    445  4887   chin #ifndef O_TEXT
    446  4887   chin 	" (not supported/ignored on this platform)"
    447  4887   chin #endif
    448  4887   chin 	".]"
    449  4887   chin "[c:create?Open for create.]"
    450  4887   chin "[i:inherit?Open without the close-on-exec bit set.]"
    451  4887   chin "[I:noinherit?Open with the close-on-exec bit set.]"
    452  4887   chin "[r:read?Open with read access.]"
    453  4887   chin "[w:write?Open with write access.]"
    454  4887   chin "[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]"
    455  4887   chin "[x:exclusive?Open exclusive.]"
    456  4887   chin 
    457  4887   chin "[N:nofollow?If the path names a symbolic link, open fails with ELOOP "
    458  4887   chin #ifndef O_NOFOLLOW
    459  4887   chin 	" (not supported/ignored on this platform)"
    460  4887   chin #endif
    461  4887   chin 	".]"
    462  4887   chin "[S:sync?Write I/O operations on the file descriptor complete as "
    463  4887   chin 	"defined by synchronized I/O file integrity completion"
    464  4887   chin #ifndef O_SYNC
    465  4887   chin 	" (not supported/ignored on this platform)"
    466  4887   chin #endif
    467  4887   chin 	".]"
    468  4887   chin "[T:trunc?If the file exists and is a regular file, and  the  file "
    469  4887   chin         "is successfully opened read/write or write-only, its length is "
    470  4887   chin         "truncated to 0 and the mode and owner are unchanged.  It "
    471  4887   chin         "has  no  effect on FIFO special files or terminal device "
    472  4887   chin         "files.   Its   effect   on   other   file    types    is "
    473  4887   chin         "implementation-dependent.  The  result  of using -T "
    474  4887   chin         "with read-only files is undefined"
    475  4887   chin #ifndef O_TRUNC
    476  4887   chin 	" (not supported/ignored on this platform)"
    477  4887   chin #endif
    478  4887   chin 	".]"
    479  4887   chin "\n"
    480  4887   chin "\nvar file\n"
    481  4887   chin "\n"
    482  4887   chin "[+EXIT STATUS?]{"
    483  4887   chin         "[+0?Success.]"
    484  4887   chin         "[+>0?An error occurred.]"
    485  4887   chin "}"
    486  4887   chin "[+SEE ALSO?\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bpoll\b(1),\bstat\b(2)]"
    487  4887   chin ;
    488  4887   chin 
    489  4887   chin 
    490  4887   chin extern int b_open(int argc, char *argv[], void *extra)
    491  4887   chin {
    492  4887   chin 	register Namval_t *np;
    493  4887   chin 	register int n,oflag=0;
    494  8462  April 	Shell_t *shp = sh_contexttoshell(extra);
    495  4887   chin 	struct filedata *fdp;
    496  4887   chin 	mode_t mode = 0666;
    497  4887   chin 	long flags = 0;
    498  4887   chin 	int fd = -1;
    499  4887   chin 	char *arg;
    500  4887   chin 
    501  4887   chin 	while (n = optget(argv, sh_optopen)) switch (n)
    502  4887   chin 	{
    503  4887   chin 	    case 'r':
    504  4887   chin 	    case 'w':
    505  4887   chin 	    case 'i':
    506  4887   chin 		flags |= letterbit(n);
    507  4887   chin 		break;
    508  4887   chin 	    case 'I':
    509  4887   chin 		flags &= ~(letterbit('i'));
    510  4887   chin 		break;
    511  4887   chin 	    case 'b':
    512  4887   chin #ifdef O_BINARY
    513  4887   chin 		oflag |= O_BINARY;
    514  4887   chin #endif
    515  4887   chin 		break;
    516  4887   chin 	    case 't':
    517  4887   chin #ifdef O_TEXT
    518  4887   chin 		oflag |= O_TEXT;
    519  4887   chin #endif
    520  4887   chin 		break;
    521  4887   chin 	    case 'N':
    522  4887   chin #ifdef O_NOFOLLOW
    523  4887   chin 		oflag |= O_NOFOLLOW;
    524  4887   chin #endif
    525  4887   chin 		break;
    526  4887   chin 	    case 'T':
    527  4887   chin #ifdef O_TRUNC
    528  4887   chin 		oflag |= O_TRUNC;
    529  4887   chin #endif
    530  4887   chin 		break;
    531  4887   chin 	    case 'x':
    532  4887   chin 		oflag |= O_EXCL;
    533  4887   chin 		break;
    534  4887   chin 	    case 'c':
    535  4887   chin 		oflag |= O_CREAT;
    536  4887   chin 		break;
    537  4887   chin 	    case 'a':
    538  4887   chin 		oflag |= O_APPEND;
    539  4887   chin 		break;
    540  4887   chin 	    case 'S':
    541  4887   chin #ifdef O_SYNC
    542  4887   chin 		oflag |= O_SYNC;
    543  4887   chin #endif
    544  4887   chin 		break;
    545  4887   chin 	    case 'm':
    546  4887   chin 		mode = strperm(arg = opt_info.arg, &opt_info.arg, mode);
    547  4887   chin 		if (*opt_info.arg)
    548  4887   chin 			errormsg(SH_DICT, ERROR_system(1), "%s: invalid mode", arg);
    549  4887   chin 	    	break;
    550  4887   chin 	    case ':':
    551  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    552  4887   chin 		break;
    553  4887   chin 	    case '?':
    554  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    555  4887   chin 		break;
    556  4887   chin 	}
    557  4887   chin 	argc -= opt_info.index;
    558  4887   chin 	argv += opt_info.index;
    559  4887   chin 	if(argc!=2 || !(flags&(letterbit('r')|letterbit('w'))))
    560  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    561  4887   chin 
    562  4887   chin 	if(flags&letterbit('r'))
    563  4887   chin 	{
    564  4887   chin 		if(flags&letterbit('w'))
    565  4887   chin 			oflag |= O_RDWR;
    566  4887   chin 		else
    567  4887   chin 			oflag |= O_RDONLY;
    568  4887   chin 	}
    569  4887   chin 	else if(flags&letterbit('w'))
    570  4887   chin 		oflag |= O_WRONLY;
    571  4887   chin 
    572  4887   chin 	fd = sh_open(argv[1], oflag, mode);
    573  4887   chin 	if(fd<0)
    574  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: open failed", argv[1]);
    575  4887   chin 
    576  4887   chin 	if(!(flags&letterbit('i')))
    577  4887   chin 		fcntl(fd, F_SETFL, 0);
    578  4887   chin 
    579  4887   chin 	np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
    580  4887   chin 	if(!nv_isnull(np))
    581  4887   chin 		nv_unset(np);
    582  4887   chin 	mkclass(np, &Fileclass);
    583  4887   chin 	fdp = (struct filedata*)np->nvalue;
    584  4887   chin 	fstat(fd, &fdp->statb);
    585  4887   chin 	fdp->fd = fd;
    586  4887   chin 	fdp->name = strdup(argv[1]);
    587  4887   chin 	return(0);
    588  4887   chin }
    589  4887   chin 
    590  4887   chin static const char sh_optclose[] =
    591  4887   chin "[-?\n@(#)$Id: close (AT&T Labs Research) 2007-04-21 $\n]"
    592  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    593  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    594  4887   chin "[+NAME? close - close a file descriptor]"
    595  4887   chin "[+DESCRIPTION?\bclose\b closes the file descriptor specified by fd.]"
    596  4887   chin "\n"
    597  4887   chin "\nfd\n"
    598  4887   chin "\n"
    599  4887   chin "[+EXIT STATUS?]{"
    600  4887   chin         "[+0?Success.]"
    601  4887   chin         "[+>0?An error occurred.]"
    602  4887   chin "}"
    603  4887   chin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\btmpfile\b(1),\bpoll\b(1),\bstat\b(1)]"
    604  4887   chin ;
    605  4887   chin 
    606  4887   chin extern int b_close(int argc, char *argv[], void *extra)
    607  4887   chin {
    608  4887   chin 	register int n=0;
    609  4887   chin 	int fd = -1;
    610  4887   chin 
    611  4887   chin 	while (n = optget(argv, sh_optclose)) switch (n)
    612  4887   chin 	{
    613  4887   chin 	    case ':':
    614  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    615  4887   chin 		break;
    616  4887   chin 	    case '?':
    617  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    618  4887   chin 		break;
    619  4887   chin 	}
    620  4887   chin 	argc -= opt_info.index;
    621  4887   chin 	argv += opt_info.index;
    622  4887   chin 	if(argc!=1)
    623  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    624  4887   chin 
    625  4887   chin 	errno = 0;
    626  4887   chin 	fd = strtol(argv[0], (char **)NULL, 0);
    627  4887   chin 	if (errno != 0 || fd < 0)
    628  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: invalid descriptor", argv[0]);
    629  4887   chin 
    630  4887   chin         n = sh_close(fd);
    631  4887   chin 
    632  4887   chin 	if (n < 0)
    633  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: close error", argv[0]);
    634  4887   chin 
    635  4887   chin 	return(n==0?0:1);
    636  4887   chin }
    637  4887   chin 
    638  4887   chin 
    639  4887   chin static const char sh_opttmpfile[] =
    640  4887   chin "[-?\n@(#)$Id: tmpfile (AT&T Labs Research) 2007-05-07 $\n]"
    641  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    642  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    643  4887   chin "[+NAME? tmpfile - create a shell variable correspnding to a temporary file]"
    644  4887   chin "[+DESCRIPTION?\btmpfile\b creates the compound variable \avar\a correspinding "
    645  4887   chin 	"to a temporary file.  The elements of \avar\a "
    646  4887   chin 	"are the names of elements in the \astat\a structure with the \bst_\b "
    647  4887   chin 	"prefix removed.]"
    648  4887   chin "[i:inherit?Open without the close-on-exec bit set.]"
    649  4887   chin "[I:noinherit?Open with the close-on-exec bit set.]"
    650  4887   chin "\n"
    651  4887   chin "\nvar\n"
    652  4887   chin "\n"
    653  4887   chin "[+EXIT STATUS?]{"
    654  4887   chin         "[+0?Success.]"
    655  4887   chin         "[+>0?An error occurred.]"
    656  4887   chin "}"
    657  4887   chin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
    658  4887   chin ;
    659  4887   chin 
    660  4887   chin 
    661  4887   chin extern int b_tmpfile(int argc, char *argv[], void *extra)
    662  4887   chin {
    663  4887   chin 	register Namval_t *np;
    664  4887   chin 	register int n;
    665  8462  April 	Shell_t *shp = sh_contexttoshell(extra);
    666  4887   chin 	struct filedata *fdp;
    667  8462  April 	bool inherit = false;
    668  4887   chin 	FILE *file = NULL;
    669  4887   chin 	int ffd, fd = -1;
    670  4887   chin 	while (n = optget(argv, sh_opttmpfile)) switch (n)
    671  4887   chin 	{
    672  4887   chin 	    case 'i':
    673  8462  April 		inherit = true;
    674  4887   chin 		break;
    675  4887   chin 	    case 'I':
    676  8462  April 		inherit = false;
    677  4887   chin 		break;
    678  4887   chin 	    case ':':
    679  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    680  4887   chin 		break;
    681  4887   chin 	    case '?':
    682  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    683  4887   chin 		break;
    684  4887   chin 	}
    685  4887   chin 	argc -= opt_info.index;
    686  4887   chin 	argv += opt_info.index;
    687  4887   chin 	if(argc!=1)
    688  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    689  4887   chin 
    690  4887   chin 	file = tmpfile();
    691  4887   chin 	if(!file)
    692  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
    693  4887   chin 	ffd = fileno(file);
    694  4887   chin 	fd = sh_dup(ffd);
    695  4887   chin 	if(fd<0)
    696  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
    697  4887   chin 	fclose(file);
    698  4887   chin 
    699  4887   chin 	if(!inherit)
    700  4887   chin 		fcntl(fd, F_SETFL, 0);
    701  4887   chin 
    702  4887   chin 	np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
    703  4887   chin 	if(!nv_isnull(np))
    704  4887   chin 		nv_unset(np);
    705  4887   chin 	mkclass(np,&Fileclass);
    706  4887   chin 	fdp = (struct filedata*)np->nvalue;
    707  4887   chin 
    708  4887   chin 	fstat(fd, &fdp->statb);
    709  4887   chin 	fdp->fd = fd;
    710  4887   chin 	fdp->name = NULL;
    711  4887   chin 	return(0);
    712  4887   chin }
    713  4887   chin 
    714  4887   chin static const char sh_optdup[] =
    715  4887   chin "[-?\n@(#)$Id: dup (AT&T Labs Research) 2007-05-07 $\n]"
    716  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    717  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    718  4887   chin "[+NAME? dup - duplicate an open file descriptor]"
    719  4887   chin "[+DESCRIPTION?The \bdup\b commands returns a new file descriptor having the "
    720  4887   chin      "following in common with the original open file descriptor "
    721  4887   chin      "fd: same open file (or pipe), same file pointer (that is, both  file descriptors "
    722  4887   chin      "share one file pointer) same access mode (read, write or read/write). "
    723  4887   chin      "The file descriptor returned is the lowest one available.]"
    724  4887   chin "[i:inherit?Open without the close-on-exec bit set.]"
    725  4887   chin "[I:noinherit?Open with the close-on-exec bit set.]"
    726  4887   chin "\n"
    727  4887   chin "\nvar fd\n"
    728  4887   chin "\n"
    729  4887   chin "[+EXIT STATUS?]{"
    730  4887   chin         "[+0?Success.]"
    731  4887   chin         "[+>0?An error occurred.]"
    732  4887   chin "}"
    733  4887   chin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(1)]"
    734  4887   chin ;
    735  4887   chin 
    736  4887   chin 
    737  4887   chin extern int b_dup(int argc, char *argv[], void *extra)
    738  4887   chin {
    739  4887   chin 	register Namval_t *np;
    740  4887   chin 	register int n;
    741  8462  April 	Shell_t *shp = sh_contexttoshell(extra);
    742  4887   chin 	struct filedata *fdp;
    743  8462  April 	bool inherit = false;
    744  4887   chin 	int ffd, fd = -1;
    745  4887   chin 	while (n = optget(argv, sh_optdup)) switch (n)
    746  4887   chin 	{
    747  4887   chin 	    case 'i':
    748  8462  April 		inherit = true;
    749  4887   chin 		break;
    750  4887   chin 	    case 'I':
    751  8462  April 		inherit = false;
    752  4887   chin 		break;
    753  4887   chin 	    case ':':
    754  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    755  4887   chin 		break;
    756  4887   chin 	    case '?':
    757  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    758  4887   chin 		break;
    759  4887   chin 	}
    760  4887   chin 	argc -= opt_info.index;
    761  4887   chin 	argv += opt_info.index;
    762  4887   chin 	if(argc!=2)
    763  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    764  4887   chin 
    765  4887   chin 	errno = 0;
    766  4887   chin 	ffd = strtol(argv[1], (char **)NULL, 0);
    767  4887   chin 	if (errno != 0 || ffd < 0)
    768  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[1]);
    769  4887   chin 
    770  4887   chin 	fd = sh_dup(ffd);
    771  4887   chin 	if(fd<0)
    772  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: dup failed", argv[1]);
    773  4887   chin 
    774  4887   chin 	if(!inherit)
    775  4887   chin 		fcntl(fd,F_SETFL,0);
    776  4887   chin 
    777  4887   chin 	np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
    778  4887   chin 	if(!nv_isnull(np))
    779  4887   chin 		nv_unset(np);
    780  4887   chin 	mkclass(np, &Fileclass);
    781  4887   chin 	fdp = (struct filedata*)np->nvalue;
    782  4887   chin 
    783  4887   chin 	fstat(fd, &fdp->statb);
    784  4887   chin 	fdp->fd = fd;
    785  4887   chin 	fdp->name = NULL;
    786  4887   chin 	return(0);
    787  4887   chin }
    788  4887   chin 
    789  4887   chin static const char sh_optstat[] =
    790  4887   chin "[-?\n@(#)$Id: stat (AT&T Labs Research) 2007-05-07 $\n]"
    791  4887   chin "[-author?David Korn <dgk (at) research.att.com>]"
    792  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    793  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    794  4887   chin "[+NAME? stat - get file status]"
    795  4887   chin "[+DESCRIPTION?\bstat\b creates the compound variable \avar\a correspinding "
    796  4887   chin 	"to the file given by the pathname \afile\a.  The elements of \avar\a "
    797  4887   chin 	"are the names of elements in the \astat\a structure with the \bst_\b "
    798  4887   chin 	"prefix removed.]"
    799  4887   chin "[l:lstat?If the the named file is a symbolic link returns information about "
    800  4887   chin 	"the link itself.]"
    801  4887   chin "\n"
    802  4887   chin "\nvar file\n"
    803  4887   chin "\n"
    804  4887   chin "[+EXIT STATUS?]{"
    805  4887   chin         "[+0?Success.]"
    806  4887   chin         "[+>0?An error occurred.]"
    807  4887   chin "}"
    808  4887   chin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(2),\blstat\b(2)]"
    809  4887   chin ;
    810  4887   chin 
    811  4887   chin 
    812  4887   chin extern int b_stat(int argc, char *argv[], void *extra)
    813  4887   chin {
    814  4887   chin 	register Namval_t *np;
    815  4887   chin 	register int n;
    816  8462  April 	Shell_t *shp = sh_contexttoshell(extra);
    817  4887   chin 	struct filedata *fdp;
    818  4887   chin 	long flags = 0;
    819  4887   chin 	struct stat statb;
    820  4887   chin 	while (n = optget(argv, sh_optstat)) switch (n)
    821  4887   chin 	{
    822  4887   chin 	    case 'l':
    823  4887   chin 		flags |= letterbit(n);
    824  4887   chin 		break;
    825  4887   chin 	    case ':':
    826  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    827  4887   chin 		break;
    828  4887   chin 	    case '?':
    829  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    830  4887   chin 		break;
    831  4887   chin 	}
    832  4887   chin 	argc -= opt_info.index;
    833  4887   chin 	argv += opt_info.index;
    834  4887   chin 	if(argc!=2)
    835  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    836  4887   chin 
    837  4887   chin 	if(flags&letterbit('l'))
    838  4887   chin 	{
    839  4887   chin 		if(lstat(argv[1], &statb) < 0)
    840  4887   chin 			errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
    841  4887   chin 	}
    842  4887   chin 	else
    843  4887   chin 	{
    844  4887   chin 		if(stat(argv[1], &statb) < 0)
    845  4887   chin 			errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
    846  4887   chin 
    847  4887   chin 	}
    848  4887   chin 
    849  4887   chin 	np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
    850  4887   chin 	if(!nv_isnull(np))
    851  4887   chin 		nv_unset(np);
    852  4887   chin 	mkclass(np,&Fileclass);
    853  4887   chin 	fdp = (struct filedata*)np->nvalue;
    854  4887   chin 	fdp->statb = statb;
    855  4887   chin 	fdp->fd = -1;
    856  4887   chin 	fdp->name = strdup(argv[1]);
    857  4887   chin 	return(0);
    858  4887   chin }
    859  4887   chin 
    860  4887   chin 
    861  4887   chin static const char sh_optrewind[] =
    862  4887   chin "[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]"
    863  4887   chin "[-author?Roland Mainz <roland.mainz (at) nrubsig.org>]"
    864  4887   chin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
    865  4887   chin "[+NAME? rewind - reset file position indicator in a stream]"
    866  4887   chin "[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]"
    867  4887   chin "\n"
    868  4887   chin "\nfd\n"
    869  4887   chin "\n"
    870  4887   chin "[+EXIT STATUS?]{"
    871  4887   chin         "[+0?Success.]"
    872  4887   chin         "[+>0?An error occurred.]"
    873  4887   chin "}"
    874  4887   chin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
    875  4887   chin ;
    876  4887   chin 
    877  4887   chin 
    878  4887   chin extern int b_rewind(int argc, char *argv[], void *extra)
    879  4887   chin {
    880  8462  April 	Shell_t *shp = sh_contexttoshell(extra);
    881  4887   chin 	int fd = -1;
    882  4887   chin 	register int n;
    883  4887   chin 	while (n = optget(argv, sh_optrewind)) switch (n)
    884  4887   chin 	{
    885  4887   chin 	    case ':':
    886  4887   chin 		errormsg(SH_DICT, 2, "%s", opt_info.arg);
    887  4887   chin 		break;
    888  4887   chin 	    case '?':
    889  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
    890  4887   chin 		break;
    891  4887   chin 	}
    892  4887   chin 	argc -= opt_info.index;
    893  4887   chin 	argv += opt_info.index;
    894  4887   chin 	if(argc!=1)
    895  4887   chin 		errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
    896  4887   chin 
    897  4887   chin 	errno = 0;
    898  4887   chin 	fd = strtol(argv[0], (char **)NULL, 0);
    899  4887   chin 	if (errno != 0 || fd < 0)
    900  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]);
    901  4887   chin 
    902  4887   chin 	if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1)
    903  4887   chin 		errormsg(SH_DICT, ERROR_system(1), "seek error");
    904  4887   chin 
    905  4887   chin 	return(0);
    906  4887   chin }
    907