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