14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2007 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin
224887Schin #include <shell.h>
234887Schin #include <stdio.h>
24*8462SApril.Chin@Sun.COM #include <stdbool.h>
254887Schin #include <option.h>
264887Schin #include <stk.h>
274887Schin #include <tm.h>
284887Schin #include "name.h"
294887Schin #undef nv_isnull
304887Schin #ifndef SH_DICT
314887Schin # define SH_DICT "libshell"
324887Schin #endif
334887Schin #include <poll.h>
344887Schin
35*8462SApril.Chin@Sun.COM #define sh_contexttoshb(context) ((Shbltin_t*)(context))
36*8462SApril.Chin@Sun.COM #define sh_contexttoshell(context) ((context)?(sh_contexttoshb(context)->shp):(NULL))
37*8462SApril.Chin@Sun.COM
384887Schin /*
394887Schin * time formatting related
404887Schin */
414887Schin struct dctime
424887Schin {
434887Schin Namfun_t fun;
444887Schin Namval_t *format;
454887Schin char buff[256]; /* Must be large enougth for |tmfmt()| */
464887Schin };
474887Schin
get_time(Namval_t * np,Namfun_t * nfp)484887Schin static char *get_time(Namval_t* np, Namfun_t* nfp)
494887Schin {
504887Schin struct dctime *dp = (struct dctime*)nfp;
514887Schin time_t t = nv_getn(np,nfp);
524887Schin char *format = nv_getval(dp->format);
534887Schin tmfmt(dp->buff,sizeof(dp->buff),format,(time_t*)0);
544887Schin return(dp->buff);
554887Schin }
564887Schin
put_time(Namval_t * np,const char * val,int flag,Namfun_t * nfp)574887Schin static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
584887Schin {
594887Schin struct dctime *dp = (struct dctime*)nfp;
604887Schin char *last;
614887Schin if(val)
624887Schin {
634887Schin int32_t t;
644887Schin if(flag&NV_INTEGER)
654887Schin {
664887Schin if(flag&NV_LONG)
674887Schin t = *(Sfdouble_t*)val;
684887Schin else
694887Schin t = *(double*)val;
704887Schin }
714887Schin else
724887Schin {
734887Schin t = tmdate(val, &last, (time_t*)0);
744887Schin if(*last)
754887Schin errormsg(SH_DICT, ERROR_exit(1),"%s: invalid date/time string", val);
764887Schin }
774887Schin nv_putv(np, (char*)&t,NV_INTEGER, nfp);
784887Schin }
794887Schin else
804887Schin {
814887Schin nv_unset(dp->format);
824887Schin free((void*)dp->format);
834887Schin nv_putv(np, val, flag, nfp);
844887Schin }
854887Schin }
864887Schin
create_time(Namval_t * np,const char * name,int flags,Namfun_t * nfp)874887Schin static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
884887Schin {
894887Schin struct dctime *dp = (struct dctime*)nfp;
904887Schin if(strcmp(name, "format"))
914887Schin return((Namval_t*)0);
924887Schin return(dp->format);
934887Schin }
944887Schin
954887Schin static const Namdisc_t timedisc =
964887Schin {
974887Schin sizeof(struct dctime),
984887Schin put_time,
994887Schin get_time,
1004887Schin 0,
1014887Schin 0,
1024887Schin create_time,
1034887Schin };
1044887Schin
1054887Schin
make_time(Namval_t * np)1064887Schin static Namval_t *make_time(Namval_t* np)
1074887Schin {
1084887Schin int offset = stktell(stkstd);
1094887Schin char *name = nv_name(np);
1104887Schin struct dctime *dp = newof(NULL,struct dctime,1,0);
1114887Schin if(!dp)
1124887Schin return((Namval_t*)0);
1134887Schin sfprintf(stkstd,"%s.format\0",name);
1144887Schin sfputc(stkstd,0);
1154887Schin dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
1164887Schin dp->fun.disc = &timedisc;
1174887Schin nv_stack(np,&dp->fun);
1184887Schin return(np);
1194887Schin }
1204887Schin
1214887Schin /*
1224887Schin * mode formatting related
1234887Schin */
get_mode(Namval_t * np,Namfun_t * nfp)1244887Schin static char *get_mode(Namval_t* np, Namfun_t* nfp)
1254887Schin {
1264887Schin mode_t mode = nv_getn(np,nfp);
1274887Schin return(fmtperm(mode));
1284887Schin }
1294887Schin
put_mode(Namval_t * np,const char * val,int flag,Namfun_t * nfp)1304887Schin static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1314887Schin {
1324887Schin if(val)
1334887Schin {
1344887Schin int32_t mode;
1354887Schin char *last;
1364887Schin if(flag&NV_INTEGER)
1374887Schin {
1384887Schin if(flag&NV_LONG)
1394887Schin mode = *(Sfdouble_t*)val;
1404887Schin else
1414887Schin mode = *(double*)val;
1424887Schin }
1434887Schin else
1444887Schin {
1454887Schin mode = strperm(val, &last,0);
1464887Schin if(*last)
1474887Schin errormsg(SH_DICT, ERROR_exit(1),"%s: invalid mode string", val);
1484887Schin }
1494887Schin nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
1504887Schin }
1514887Schin else
1524887Schin nv_putv(np,val,flag,nfp);
1534887Schin }
1544887Schin
1554887Schin static const Namdisc_t modedisc =
1564887Schin {
1574887Schin 0,
1584887Schin put_mode,
1594887Schin get_mode,
1604887Schin };
1614887Schin
make_mode(Namval_t * np)1624887Schin static Namval_t *make_mode(Namval_t* np)
1634887Schin {
1644887Schin char *name = nv_name(np);
1654887Schin Namfun_t *nfp = newof(NULL,Namfun_t,1,0);
1664887Schin if(!nfp)
1674887Schin return((Namval_t*)0);
1684887Schin nfp->disc = &modedisc;
1694887Schin nv_stack(np,nfp);
1704887Schin return(np);
1714887Schin }
1724887Schin
1734887Schin /*
1744887Schin * field related typese and functions
1754887Schin */
1764887Schin typedef struct _field_
1774887Schin {
1784887Schin char *name; /* field name */
1794887Schin int flags; /* flags */
1804887Schin short offset; /* offset of field into data */
1814887Schin short size; /* size of field */
1824887Schin Namval_t *(*make)(Namval_t*); /* discipline constructor */
1834887Schin } Shfield_t;
1844887Schin
1854887Schin /*
1864887Schin * lookup field in field table
1874887Schin */
sh_findfield(Shfield_t * ftable,int nelem,const char * name)1884887Schin static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name)
1894887Schin {
1904887Schin Shfield_t *fp = ftable;
1914887Schin register int i,n;
1924887Schin register const char *cp;
1934887Schin for(cp=name; *cp; cp++)
1944887Schin {
1954887Schin if(*cp=='.')
1964887Schin break;
1974887Schin }
1984887Schin n = cp-name;
1994887Schin for(i=0; i < nelem; i++,fp++)
2004887Schin {
2014887Schin if(memcmp(fp->name,name,n)==0 && fp->name[n]==0)
2024887Schin return(fp);
2034887Schin }
2044887Schin return(0);
2054887Schin }
2064887Schin
2074887Schin /*
2084887Schin * class types and functions
2094887Schin */
2104887Schin
2114887Schin typedef struct _class_
2124887Schin {
2134887Schin int nelem; /* number of elements */
2144887Schin int dsize; /* size for data structure */
2154887Schin Shfield_t *fields; /* field description table */
2164887Schin } Shclass_t;
2174887Schin
2184887Schin struct dcclass
2194887Schin {
2204887Schin Namfun_t fun;
2214887Schin Shclass_t sclass;
2224887Schin };
2234887Schin
sh_newnode(register Shfield_t * fp,Namval_t * np)2244887Schin static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np)
2254887Schin {
2264887Schin char *val = np->nvalue + fp->offset;
2274887Schin char *name = nv_name(np);
2284887Schin register Namval_t *nq;
2294887Schin int offset = stktell(stkstd);
2304887Schin sfprintf(stkstd,"%s.%s\0",name,fp->name);
2314887Schin sfputc(stkstd,0);
2324887Schin nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
2334887Schin if(fp->size<0)
2344887Schin val = *(char**)val;
2354887Schin nv_putval(nq,val,fp->flags|NV_NOFREE);
2364887Schin if(fp->make)
2374887Schin (*fp->make)(nq);
2384887Schin return(nq);
2394887Schin }
2404887Schin
fieldcreate(Namval_t * np,const char * name,int flags,Namfun_t * nfp)2414887Schin static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
2424887Schin {
2434887Schin struct dcclass *dcp = (struct dcclass*)nfp;
2444887Schin Shclass_t *sp = &dcp->sclass;
2454887Schin Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name);
2464887Schin Namval_t *nq,**nodes = (Namval_t**)(dcp+1);
2474887Schin int n = fp-sp->fields;
2484887Schin int len = strlen(fp->name);
2494887Schin void *data = (void*)np->nvalue;
2504887Schin if(!(nq=nodes[n]))
2514887Schin {
2524887Schin nodes[n] = nq = sh_newnode(fp,np);
2534887Schin nfp->last = "";
2544887Schin }
2554887Schin if(name[len]==0)
2564887Schin return(nq);
2574887Schin return(nq);
2584887Schin }
2594887Schin
genvalue(Sfio_t * out,Shclass_t * sp,int indent,Namval_t * npar)2604887Schin static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar)
2614887Schin {
2624887Schin Shfield_t *fp = sp->fields;
2634887Schin Namval_t *np, **nodes= (Namval_t**)(sp+1);
2644887Schin register int i,isarray;
2654887Schin if(out)
2664887Schin {
2674887Schin sfwrite(out,"(\n",2);
2684887Schin indent++;
2694887Schin }
2704887Schin for(i=0; i < sp->nelem; i++,fp++)
2714887Schin {
2724887Schin #if 0
2734887Schin /* handle recursive case */
2744887Schin #endif
2754887Schin if(!(np=nodes[i]) && out)
2764887Schin np = sh_newnode(fp,npar);
2774887Schin if(np)
2784887Schin {
2794887Schin isarray=0;
2804887Schin if(nv_isattr(np,NV_ARRAY))
2814887Schin {
2824887Schin isarray=1;
2834887Schin if(array_elem(nv_arrayptr(np))==0)
2844887Schin isarray=2;
2854887Schin else
2864887Schin nv_putsub(np,(char*)0,ARRAY_SCAN);
2874887Schin }
2884887Schin sfnputc(out,'\t',indent);
2894887Schin sfputr(out,fp->name,(isarray==2?'\n':'='));
2904887Schin if(isarray)
2914887Schin {
2924887Schin if(isarray==2)
2934887Schin continue;
2944887Schin sfwrite(out,"(\n",2);
2954887Schin sfnputc(out,'\t',++indent);
2964887Schin }
2974887Schin while(1)
2984887Schin {
2994887Schin char *fmtq;
3004887Schin if(isarray)
3014887Schin {
3024887Schin sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np)));
3034887Schin sfputc(out,'=');
3044887Schin }
3054887Schin if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq)))
3064887Schin fmtq = "";
3074887Schin sfputr(out,fmtq,'\n');
3084887Schin if(!nv_nextsub(np))
3094887Schin break;
3104887Schin sfnputc(out,'\t',indent);
3114887Schin }
3124887Schin if(isarray)
3134887Schin {
3144887Schin sfnputc(out,'\t',--indent);
3154887Schin sfwrite(out,")\n",2);
3164887Schin }
3174887Schin }
3184887Schin }
3194887Schin if(out)
3204887Schin {
3214887Schin if(indent>1)
3224887Schin sfnputc(out,'\t',indent-1);
3234887Schin sfputc(out,')');
3244887Schin }
3254887Schin }
3264887Schin
walk_class(register Namval_t * np,int dlete,struct dcclass * dcp)3274887Schin static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp)
3284887Schin {
3294887Schin static Sfio_t *out;
3304887Schin Sfio_t *outfile;
3314887Schin int savtop = stktell(stkstd);
3324887Schin char *savptr = stkfreeze(stkstd,0);
3334887Schin if(dlete)
3344887Schin outfile = 0;
3354887Schin else if(!(outfile=out))
3364887Schin outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
3374887Schin else
3384887Schin sfseek(outfile,0L,SEEK_SET);
3394887Schin genvalue(outfile,&dcp->sclass,0,np);
3404887Schin stkset(stkstd,savptr,savtop);
3414887Schin if(!outfile)
3424887Schin return((char*)0);
3434887Schin sfputc(out,0);
3444887Schin return((char*)out->_data);
3454887Schin }
3464887Schin
get_classval(Namval_t * np,Namfun_t * nfp)3474887Schin static char *get_classval(Namval_t* np, Namfun_t* nfp)
3484887Schin {
3494887Schin return(walk_class(np,0,(struct dcclass *)nfp));
3504887Schin }
3514887Schin
put_classval(Namval_t * np,const char * val,int flag,Namfun_t * nfp)3524887Schin static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
3534887Schin {
3544887Schin walk_class(np,1,(struct dcclass *)nfp);
3554887Schin if(nfp = nv_stack(np,(Namfun_t*)0))
3564887Schin {
3574887Schin free((void*)nfp);
3584887Schin if(np->nvalue && !nv_isattr(np,NV_NOFREE))
3594887Schin free((void*)np->nvalue);
3604887Schin }
3614887Schin if(val)
3624887Schin nv_putval(np,val,flag);
3634887Schin }
3644887Schin
3654887Schin static const Namdisc_t classdisc =
3664887Schin {
3674887Schin sizeof(struct dcclass),
3684887Schin put_classval,
3694887Schin get_classval,
3704887Schin 0,
3714887Schin 0,
3724887Schin fieldcreate
3734887Schin };
3744887Schin
mkclass(Namval_t * np,Shclass_t * sp)3754887Schin static int mkclass(Namval_t *np, Shclass_t *sp)
3764887Schin {
3774887Schin struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*));
3784887Schin if(!tcp)
3794887Schin return(0);
3804887Schin memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*));
3814887Schin tcp->fun.disc = &classdisc;
3824887Schin tcp->sclass = *sp;
3834887Schin np->nvalue = (char*)calloc(sp->dsize,1);
3844887Schin nv_stack(np,&tcp->fun);
3854887Schin return(1);
3864887Schin }
3874887Schin
3884887Schin /*
3894887Schin * ====================from here down is file class specific
3904887Schin */
3914887Schin static struct stat *Sp;
3924887Schin
3934887Schin struct filedata
3944887Schin {
3954887Schin struct stat statb;
3964887Schin int fd;
3974887Schin char *name;
3984887Schin };
3994887Schin
4004887Schin static Shfield_t filefield[] =
4014887Schin {
4024887Schin { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time},
4034887Schin { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time},
4044887Schin { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)},
4054887Schin { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)},
4064887Schin { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)},
4074887Schin { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)},
4084887Schin { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode},
4094887Schin { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time},
4104887Schin { "name", NV_RDONLY, offsetof(struct filedata,name), -1 },
4114887Schin { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)},
4124887Schin { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)},
4134887Schin { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)}
4144887Schin };
4154887Schin
4164887Schin static Shclass_t Fileclass =
4174887Schin {
4184887Schin sizeof(filefield)/sizeof(*filefield),
4194887Schin sizeof(struct filedata),
4204887Schin filefield
4214887Schin };
4224887Schin
4234887Schin
4244887Schin #define letterbit(bit) (1<<((bit)-'a'))
4254887Schin
4264887Schin static const char sh_optopen[] =
4274887Schin "[-?\n@(#)$Id: open (AT&T Labs Research) 2007-05-07 $\n]"
4284887Schin "[-author?David Korn <dgk@research.att.com>]"
4294887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
4304887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
4314887Schin "[+NAME? open - create a shell variable correspnding to a file]"
4324887Schin "[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding "
4334887Schin "to the file given by the pathname \afile\a. The elements of \avar\a "
4344887Schin "are the names of elements in the \astat\a structure with the \bst_\b "
4354887Schin "prefix removed.]"
4364887Schin "[+?\afile\a is opened (based on \b-r\b and/or \b-w\b) and the variable "
4374887Schin "\avar\a\b.fd\b is the file descriptor.]"
4384887Schin "[a:append?Open for append.]"
4394887Schin "[b:binary?Open in binary mode"
4404887Schin #ifndef O_BINARY
4414887Schin " (not supported/ignored on this platform)"
4424887Schin #endif
4434887Schin ".]"
4444887Schin "[t:text?Open in text mode"
4454887Schin #ifndef O_TEXT
4464887Schin " (not supported/ignored on this platform)"
4474887Schin #endif
4484887Schin ".]"
4494887Schin "[c:create?Open for create.]"
4504887Schin "[i:inherit?Open without the close-on-exec bit set.]"
4514887Schin "[I:noinherit?Open with the close-on-exec bit set.]"
4524887Schin "[r:read?Open with read access.]"
4534887Schin "[w:write?Open with write access.]"
4544887Schin "[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]"
4554887Schin "[x:exclusive?Open exclusive.]"
4564887Schin
4574887Schin "[N:nofollow?If the path names a symbolic link, open fails with ELOOP "
4584887Schin #ifndef O_NOFOLLOW
4594887Schin " (not supported/ignored on this platform)"
4604887Schin #endif
4614887Schin ".]"
4624887Schin "[S:sync?Write I/O operations on the file descriptor complete as "
4634887Schin "defined by synchronized I/O file integrity completion"
4644887Schin #ifndef O_SYNC
4654887Schin " (not supported/ignored on this platform)"
4664887Schin #endif
4674887Schin ".]"
4684887Schin "[T:trunc?If the file exists and is a regular file, and the file "
4694887Schin "is successfully opened read/write or write-only, its length is "
4704887Schin "truncated to 0 and the mode and owner are unchanged. It "
4714887Schin "has no effect on FIFO special files or terminal device "
4724887Schin "files. Its effect on other file types is "
4734887Schin "implementation-dependent. The result of using -T "
4744887Schin "with read-only files is undefined"
4754887Schin #ifndef O_TRUNC
4764887Schin " (not supported/ignored on this platform)"
4774887Schin #endif
4784887Schin ".]"
4794887Schin "\n"
4804887Schin "\nvar file\n"
4814887Schin "\n"
4824887Schin "[+EXIT STATUS?]{"
4834887Schin "[+0?Success.]"
4844887Schin "[+>0?An error occurred.]"
4854887Schin "}"
4864887Schin "[+SEE ALSO?\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bpoll\b(1),\bstat\b(2)]"
4874887Schin ;
4884887Schin
4894887Schin
b_open(int argc,char * argv[],void * extra)4904887Schin extern int b_open(int argc, char *argv[], void *extra)
4914887Schin {
4924887Schin register Namval_t *np;
4934887Schin register int n,oflag=0;
494*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra);
4954887Schin struct filedata *fdp;
4964887Schin mode_t mode = 0666;
4974887Schin long flags = 0;
4984887Schin int fd = -1;
4994887Schin char *arg;
5004887Schin
5014887Schin while (n = optget(argv, sh_optopen)) switch (n)
5024887Schin {
5034887Schin case 'r':
5044887Schin case 'w':
5054887Schin case 'i':
5064887Schin flags |= letterbit(n);
5074887Schin break;
5084887Schin case 'I':
5094887Schin flags &= ~(letterbit('i'));
5104887Schin break;
5114887Schin case 'b':
5124887Schin #ifdef O_BINARY
5134887Schin oflag |= O_BINARY;
5144887Schin #endif
5154887Schin break;
5164887Schin case 't':
5174887Schin #ifdef O_TEXT
5184887Schin oflag |= O_TEXT;
5194887Schin #endif
5204887Schin break;
5214887Schin case 'N':
5224887Schin #ifdef O_NOFOLLOW
5234887Schin oflag |= O_NOFOLLOW;
5244887Schin #endif
5254887Schin break;
5264887Schin case 'T':
5274887Schin #ifdef O_TRUNC
5284887Schin oflag |= O_TRUNC;
5294887Schin #endif
5304887Schin break;
5314887Schin case 'x':
5324887Schin oflag |= O_EXCL;
5334887Schin break;
5344887Schin case 'c':
5354887Schin oflag |= O_CREAT;
5364887Schin break;
5374887Schin case 'a':
5384887Schin oflag |= O_APPEND;
5394887Schin break;
5404887Schin case 'S':
5414887Schin #ifdef O_SYNC
5424887Schin oflag |= O_SYNC;
5434887Schin #endif
5444887Schin break;
5454887Schin case 'm':
5464887Schin mode = strperm(arg = opt_info.arg, &opt_info.arg, mode);
5474887Schin if (*opt_info.arg)
5484887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid mode", arg);
5494887Schin break;
5504887Schin case ':':
5514887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
5524887Schin break;
5534887Schin case '?':
5544887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
5554887Schin break;
5564887Schin }
5574887Schin argc -= opt_info.index;
5584887Schin argv += opt_info.index;
5594887Schin if(argc!=2 || !(flags&(letterbit('r')|letterbit('w'))))
5604887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
5614887Schin
5624887Schin if(flags&letterbit('r'))
5634887Schin {
5644887Schin if(flags&letterbit('w'))
5654887Schin oflag |= O_RDWR;
5664887Schin else
5674887Schin oflag |= O_RDONLY;
5684887Schin }
5694887Schin else if(flags&letterbit('w'))
5704887Schin oflag |= O_WRONLY;
5714887Schin
5724887Schin fd = sh_open(argv[1], oflag, mode);
5734887Schin if(fd<0)
5744887Schin errormsg(SH_DICT, ERROR_system(1), "%s: open failed", argv[1]);
5754887Schin
5764887Schin if(!(flags&letterbit('i')))
5774887Schin fcntl(fd, F_SETFL, 0);
5784887Schin
5794887Schin np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
5804887Schin if(!nv_isnull(np))
5814887Schin nv_unset(np);
5824887Schin mkclass(np, &Fileclass);
5834887Schin fdp = (struct filedata*)np->nvalue;
5844887Schin fstat(fd, &fdp->statb);
5854887Schin fdp->fd = fd;
5864887Schin fdp->name = strdup(argv[1]);
5874887Schin return(0);
5884887Schin }
5894887Schin
5904887Schin static const char sh_optclose[] =
5914887Schin "[-?\n@(#)$Id: close (AT&T Labs Research) 2007-04-21 $\n]"
5924887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
5934887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
5944887Schin "[+NAME? close - close a file descriptor]"
5954887Schin "[+DESCRIPTION?\bclose\b closes the file descriptor specified by fd.]"
5964887Schin "\n"
5974887Schin "\nfd\n"
5984887Schin "\n"
5994887Schin "[+EXIT STATUS?]{"
6004887Schin "[+0?Success.]"
6014887Schin "[+>0?An error occurred.]"
6024887Schin "}"
6034887Schin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\btmpfile\b(1),\bpoll\b(1),\bstat\b(1)]"
6044887Schin ;
6054887Schin
b_close(int argc,char * argv[],void * extra)6064887Schin extern int b_close(int argc, char *argv[], void *extra)
6074887Schin {
6084887Schin register int n=0;
6094887Schin int fd = -1;
6104887Schin
6114887Schin while (n = optget(argv, sh_optclose)) switch (n)
6124887Schin {
6134887Schin case ':':
6144887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
6154887Schin break;
6164887Schin case '?':
6174887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
6184887Schin break;
6194887Schin }
6204887Schin argc -= opt_info.index;
6214887Schin argv += opt_info.index;
6224887Schin if(argc!=1)
6234887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
6244887Schin
6254887Schin errno = 0;
6264887Schin fd = strtol(argv[0], (char **)NULL, 0);
6274887Schin if (errno != 0 || fd < 0)
6284887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid descriptor", argv[0]);
6294887Schin
6304887Schin n = sh_close(fd);
6314887Schin
6324887Schin if (n < 0)
6334887Schin errormsg(SH_DICT, ERROR_system(1), "%s: close error", argv[0]);
6344887Schin
6354887Schin return(n==0?0:1);
6364887Schin }
6374887Schin
6384887Schin
6394887Schin static const char sh_opttmpfile[] =
6404887Schin "[-?\n@(#)$Id: tmpfile (AT&T Labs Research) 2007-05-07 $\n]"
6414887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
6424887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
6434887Schin "[+NAME? tmpfile - create a shell variable correspnding to a temporary file]"
6444887Schin "[+DESCRIPTION?\btmpfile\b creates the compound variable \avar\a correspinding "
6454887Schin "to a temporary file. The elements of \avar\a "
6464887Schin "are the names of elements in the \astat\a structure with the \bst_\b "
6474887Schin "prefix removed.]"
6484887Schin "[i:inherit?Open without the close-on-exec bit set.]"
6494887Schin "[I:noinherit?Open with the close-on-exec bit set.]"
6504887Schin "\n"
6514887Schin "\nvar\n"
6524887Schin "\n"
6534887Schin "[+EXIT STATUS?]{"
6544887Schin "[+0?Success.]"
6554887Schin "[+>0?An error occurred.]"
6564887Schin "}"
6574887Schin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
6584887Schin ;
6594887Schin
6604887Schin
b_tmpfile(int argc,char * argv[],void * extra)6614887Schin extern int b_tmpfile(int argc, char *argv[], void *extra)
6624887Schin {
6634887Schin register Namval_t *np;
6644887Schin register int n;
665*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra);
6664887Schin struct filedata *fdp;
667*8462SApril.Chin@Sun.COM bool inherit = false;
6684887Schin FILE *file = NULL;
6694887Schin int ffd, fd = -1;
6704887Schin while (n = optget(argv, sh_opttmpfile)) switch (n)
6714887Schin {
6724887Schin case 'i':
673*8462SApril.Chin@Sun.COM inherit = true;
6744887Schin break;
6754887Schin case 'I':
676*8462SApril.Chin@Sun.COM inherit = false;
6774887Schin break;
6784887Schin case ':':
6794887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
6804887Schin break;
6814887Schin case '?':
6824887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
6834887Schin break;
6844887Schin }
6854887Schin argc -= opt_info.index;
6864887Schin argv += opt_info.index;
6874887Schin if(argc!=1)
6884887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
6894887Schin
6904887Schin file = tmpfile();
6914887Schin if(!file)
6924887Schin errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
6934887Schin ffd = fileno(file);
6944887Schin fd = sh_dup(ffd);
6954887Schin if(fd<0)
6964887Schin errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
6974887Schin fclose(file);
6984887Schin
6994887Schin if(!inherit)
7004887Schin fcntl(fd, F_SETFL, 0);
7014887Schin
7024887Schin np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
7034887Schin if(!nv_isnull(np))
7044887Schin nv_unset(np);
7054887Schin mkclass(np,&Fileclass);
7064887Schin fdp = (struct filedata*)np->nvalue;
7074887Schin
7084887Schin fstat(fd, &fdp->statb);
7094887Schin fdp->fd = fd;
7104887Schin fdp->name = NULL;
7114887Schin return(0);
7124887Schin }
7134887Schin
7144887Schin static const char sh_optdup[] =
7154887Schin "[-?\n@(#)$Id: dup (AT&T Labs Research) 2007-05-07 $\n]"
7164887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
7174887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
7184887Schin "[+NAME? dup - duplicate an open file descriptor]"
7194887Schin "[+DESCRIPTION?The \bdup\b commands returns a new file descriptor having the "
7204887Schin "following in common with the original open file descriptor "
7214887Schin "fd: same open file (or pipe), same file pointer (that is, both file descriptors "
7224887Schin "share one file pointer) same access mode (read, write or read/write). "
7234887Schin "The file descriptor returned is the lowest one available.]"
7244887Schin "[i:inherit?Open without the close-on-exec bit set.]"
7254887Schin "[I:noinherit?Open with the close-on-exec bit set.]"
7264887Schin "\n"
7274887Schin "\nvar fd\n"
7284887Schin "\n"
7294887Schin "[+EXIT STATUS?]{"
7304887Schin "[+0?Success.]"
7314887Schin "[+>0?An error occurred.]"
7324887Schin "}"
7334887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(1)]"
7344887Schin ;
7354887Schin
7364887Schin
b_dup(int argc,char * argv[],void * extra)7374887Schin extern int b_dup(int argc, char *argv[], void *extra)
7384887Schin {
7394887Schin register Namval_t *np;
7404887Schin register int n;
741*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra);
7424887Schin struct filedata *fdp;
743*8462SApril.Chin@Sun.COM bool inherit = false;
7444887Schin int ffd, fd = -1;
7454887Schin while (n = optget(argv, sh_optdup)) switch (n)
7464887Schin {
7474887Schin case 'i':
748*8462SApril.Chin@Sun.COM inherit = true;
7494887Schin break;
7504887Schin case 'I':
751*8462SApril.Chin@Sun.COM inherit = false;
7524887Schin break;
7534887Schin case ':':
7544887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
7554887Schin break;
7564887Schin case '?':
7574887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
7584887Schin break;
7594887Schin }
7604887Schin argc -= opt_info.index;
7614887Schin argv += opt_info.index;
7624887Schin if(argc!=2)
7634887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
7644887Schin
7654887Schin errno = 0;
7664887Schin ffd = strtol(argv[1], (char **)NULL, 0);
7674887Schin if (errno != 0 || ffd < 0)
7684887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[1]);
7694887Schin
7704887Schin fd = sh_dup(ffd);
7714887Schin if(fd<0)
7724887Schin errormsg(SH_DICT, ERROR_system(1), "%s: dup failed", argv[1]);
7734887Schin
7744887Schin if(!inherit)
7754887Schin fcntl(fd,F_SETFL,0);
7764887Schin
7774887Schin np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
7784887Schin if(!nv_isnull(np))
7794887Schin nv_unset(np);
7804887Schin mkclass(np, &Fileclass);
7814887Schin fdp = (struct filedata*)np->nvalue;
7824887Schin
7834887Schin fstat(fd, &fdp->statb);
7844887Schin fdp->fd = fd;
7854887Schin fdp->name = NULL;
7864887Schin return(0);
7874887Schin }
7884887Schin
7894887Schin static const char sh_optstat[] =
7904887Schin "[-?\n@(#)$Id: stat (AT&T Labs Research) 2007-05-07 $\n]"
7914887Schin "[-author?David Korn <dgk@research.att.com>]"
7924887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
7934887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
7944887Schin "[+NAME? stat - get file status]"
7954887Schin "[+DESCRIPTION?\bstat\b creates the compound variable \avar\a correspinding "
7964887Schin "to the file given by the pathname \afile\a. The elements of \avar\a "
7974887Schin "are the names of elements in the \astat\a structure with the \bst_\b "
7984887Schin "prefix removed.]"
7994887Schin "[l:lstat?If the the named file is a symbolic link returns information about "
8004887Schin "the link itself.]"
8014887Schin "\n"
8024887Schin "\nvar file\n"
8034887Schin "\n"
8044887Schin "[+EXIT STATUS?]{"
8054887Schin "[+0?Success.]"
8064887Schin "[+>0?An error occurred.]"
8074887Schin "}"
8084887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(2),\blstat\b(2)]"
8094887Schin ;
8104887Schin
8114887Schin
b_stat(int argc,char * argv[],void * extra)8124887Schin extern int b_stat(int argc, char *argv[], void *extra)
8134887Schin {
8144887Schin register Namval_t *np;
8154887Schin register int n;
816*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra);
8174887Schin struct filedata *fdp;
8184887Schin long flags = 0;
8194887Schin struct stat statb;
8204887Schin while (n = optget(argv, sh_optstat)) switch (n)
8214887Schin {
8224887Schin case 'l':
8234887Schin flags |= letterbit(n);
8244887Schin break;
8254887Schin case ':':
8264887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
8274887Schin break;
8284887Schin case '?':
8294887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
8304887Schin break;
8314887Schin }
8324887Schin argc -= opt_info.index;
8334887Schin argv += opt_info.index;
8344887Schin if(argc!=2)
8354887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
8364887Schin
8374887Schin if(flags&letterbit('l'))
8384887Schin {
8394887Schin if(lstat(argv[1], &statb) < 0)
8404887Schin errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
8414887Schin }
8424887Schin else
8434887Schin {
8444887Schin if(stat(argv[1], &statb) < 0)
8454887Schin errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
8464887Schin
8474887Schin }
8484887Schin
8494887Schin np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
8504887Schin if(!nv_isnull(np))
8514887Schin nv_unset(np);
8524887Schin mkclass(np,&Fileclass);
8534887Schin fdp = (struct filedata*)np->nvalue;
8544887Schin fdp->statb = statb;
8554887Schin fdp->fd = -1;
8564887Schin fdp->name = strdup(argv[1]);
8574887Schin return(0);
8584887Schin }
8594887Schin
8604887Schin
8614887Schin static const char sh_optrewind[] =
8624887Schin "[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]"
8634887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
8644887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
8654887Schin "[+NAME? rewind - reset file position indicator in a stream]"
8664887Schin "[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]"
8674887Schin "\n"
8684887Schin "\nfd\n"
8694887Schin "\n"
8704887Schin "[+EXIT STATUS?]{"
8714887Schin "[+0?Success.]"
8724887Schin "[+>0?An error occurred.]"
8734887Schin "}"
8744887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
8754887Schin ;
8764887Schin
8774887Schin
b_rewind(int argc,char * argv[],void * extra)8784887Schin extern int b_rewind(int argc, char *argv[], void *extra)
8794887Schin {
880*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra);
8814887Schin int fd = -1;
8824887Schin register int n;
8834887Schin while (n = optget(argv, sh_optrewind)) switch (n)
8844887Schin {
8854887Schin case ':':
8864887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg);
8874887Schin break;
8884887Schin case '?':
8894887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
8904887Schin break;
8914887Schin }
8924887Schin argc -= opt_info.index;
8934887Schin argv += opt_info.index;
8944887Schin if(argc!=1)
8954887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
8964887Schin
8974887Schin errno = 0;
8984887Schin fd = strtol(argv[0], (char **)NULL, 0);
8994887Schin if (errno != 0 || fd < 0)
9004887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]);
9014887Schin
9024887Schin if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1)
9034887Schin errormsg(SH_DICT, ERROR_system(1), "seek error");
9044887Schin
9054887Schin return(0);
9064887Schin }
907