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 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 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 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 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 */ 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 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 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 */ 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 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 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 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 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 3474887Schin static char *get_classval(Namval_t* np, Namfun_t* nfp) 3484887Schin { 3494887Schin return(walk_class(np,0,(struct dcclass *)nfp)); 3504887Schin } 3514887Schin 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 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 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 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 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 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 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 static const char sh_optpoll[] = 861*8462SApril.Chin@Sun.COM "[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-12-20 $\n]" 8624887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org]" 8634887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 8644887Schin "[+NAME? poll - input/output multiplexing]" 8654887Schin "[+DESCRIPTION?The poll command provides applications with a mechanism " 8664887Schin "for multiplexing input/output over a set of file descriptors. " 8674887Schin "For each member of the array variable \bvar\b, " 8684887Schin "poll examines the given file descriptor in the subscript \b.fd\b " 8694887Schin "for the event(s) specified in the subscript \b.events\b." 8704887Schin "The poll command identifies those file descriptors on which an " 8714887Schin "application can read or write data, or on which certain events have " 8724887Schin "occurred.]" 8734887Schin "[+?The \bvar\b argument specifies the file descriptors to be examined " 8744887Schin "and the events of interest for each file descriptor. " 8754887Schin "It is a array of structured variables with one member for each open " 8764887Schin "file descriptor of interest. The array's members contain the following " 8774887Schin "subscripts:]{" 8784887Schin "[+?\b.fd\b # file descriptor]" 8794887Schin "[+?\b.events\b # requested events]" 8804887Schin "[+?\b.revents\b # returned event]" 8814887Schin "}" 8824887Schin "[+?The \bfd\b variable specifies an open file descriptor and the " 8834887Schin "\bevents\b and \brevents\b members are strings constructed from " 8844887Schin "a concaternation of the following event flags, seperated by '|':]" 8854887Schin "{ " 8864887Schin "[+POLLIN?Data other than high priority data may be " 8874887Schin "read without blocking. For STREAMS, this " 8884887Schin "flag is set in revents even if the message " 8894887Schin "is of zero length.]" 8904887Schin "[+POLLRDNORM?Normal data (priority band equals 0) may be " 8914887Schin "read without blocking. For STREAMS, this " 8924887Schin "flag is set in revents even if the message " 8934887Schin "is of zero length.]" 8944887Schin "[+POLLRDBAND?Data from a non-zero priority band may be " 8954887Schin "read without blocking. For STREAMS, this " 8964887Schin "flag is set in revents even if the message " 8974887Schin "is of zero length.]" 8984887Schin "[+POLLPRI?High priority data may be received without " 8994887Schin "blocking. For STREAMS, this flag is set in " 9004887Schin "revents even if the message is of zero " 9014887Schin "length.]" 9024887Schin "[+POLLOUT?Normal data (priority band equals 0) may be " 9034887Schin "written without blocking.]" 9044887Schin "[+POLLWRNORM?The same as POLLOUT.]" 9054887Schin "[+POLLWRBAND?Priority data (priority band > 0) may be " 9064887Schin "written. This event only examines bands " 9074887Schin "that have been written to at least once.]" 9084887Schin "[+POLLERR?An error has occurred on the device or " 9094887Schin "stream. This flag is only valid in the " 9104887Schin "revents bitmask; it is not used in the " 9114887Schin "events member.]" 9124887Schin "[+POLLHUP?A hangup has occurred on the stream. This " 9134887Schin "event and POLLOUT are mutually exclusive; a " 9144887Schin "stream can never be writable if a hangup has " 9154887Schin "occurred. However, this event and POLLIN, " 9164887Schin ", POLLRDBAND, or POLLPRI are not " 9174887Schin "mutually exclusive. This flag is only valid " 9184887Schin "in the revents bitmask; it is not used in " 9194887Schin "the events member.]" 9204887Schin "[+POLLNVAL?The specified fd value does not belong to an " 9214887Schin "open file. This flag is only valid in the " 9224887Schin "revents member; it is not used in the events " 9234887Schin "member.]" 9244887Schin "}" 9254887Schin "]" 9264887Schin 9274887Schin "[+?If the value fd is less than 0, events is ignored and " 9284887Schin "revents is set to 0 in that entry on return from poll.]" 9294887Schin 9304887Schin "[+?The results of the poll query are stored in the revents " 9314887Schin "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b " 9324887Schin "variable to indicate which of the requested events are true. " 9334887Schin "If none are true, the \brevents\b will be an empty string when " 9344887Schin "the poll command returns. The event flags " 9354887Schin "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b " 9364887Schin "if the conditions they indicate are true; this occurs even " 9374887Schin "though these flags were not present in events.]" 9384887Schin 9394887Schin "[+?If none of the defined events have occurred on any selected " 9404887Schin "file descriptor, poll waits at least timeout milliseconds " 9414887Schin "for an event to occur on any of the selected file descriptors. " 9424887Schin "On a computer where millisecond timing accuracy is not " 9434887Schin "available, timeout is rounded up to the nearest legal value " 9444887Schin "available on that system. If the value timeout is 0, poll " 9454887Schin "returns immediately. If the value of timeout is -1, poll " 9464887Schin "blocks until a requested event occurs or until the call is " 9474887Schin "interrupted.]" 9484887Schin 9494887Schin "[+?The poll function supports regular files, terminal and " 9504887Schin "pseudo-terminal devices, STREAMS-based files, FIFOs and " 9514887Schin "pipes. The behavior of poll on elements of fds that refer " 9524887Schin "to other types of file is unspecified.]" 9534887Schin 9544887Schin "[+?The poll function supports sockets.]" 9554887Schin 9564887Schin "[+?A file descriptor for a socket that is listening for connections " 9574887Schin "will indicate that it is ready for reading, once connections " 9584887Schin "are available. A file descriptor for a socket that " 9594887Schin "is connecting asynchronously will indicate that it is ready " 9604887Schin "for writing, once a connection has been established.]" 9614887Schin 9624887Schin "[+?Regular files always poll TRUE for reading and writing.]" 9634887Schin 964*8462SApril.Chin@Sun.COM "[c:fdcount]:[fdcount?Upon successful completion, a non-negative value is " 965*8462SApril.Chin@Sun.COM "returned. A positive value indicates the total number of " 966*8462SApril.Chin@Sun.COM "file descriptors that has been selected (that is, file " 967*8462SApril.Chin@Sun.COM "descriptors for which the revents member is non-zero). A " 968*8462SApril.Chin@Sun.COM "value of 0 indicates that the call timed out and no file " 969*8462SApril.Chin@Sun.COM "descriptors have been selected. Upon failure, -1 is returned.]" 970*8462SApril.Chin@Sun.COM "[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, " 971*8462SApril.Chin@Sun.COM "poll returns immediately. If the value of timeout is -1, poll " 972*8462SApril.Chin@Sun.COM "blocks until a requested event occurs or until the call is " 973*8462SApril.Chin@Sun.COM "interrupted.]" 974*8462SApril.Chin@Sun.COM "[T:mtimeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " 9754887Schin "poll returns immediately. If the value of timeout is -1, poll " 9764887Schin "blocks until a requested event occurs or until the call is " 9774887Schin "interrupted.]" 9784887Schin "\n" 9794887Schin "\nvar\n" 9804887Schin "\n" 9814887Schin "[+EXIT STATUS?]{" 9824887Schin "[+0?Success.]" 9834887Schin "[+>0?An error occurred.]" 9844887Schin "}" 9854887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" 9864887Schin ; 9874887Schin 9884887Schin /* 9894887Schin * |mystpcpy| - like |strcpy()| but returns the end of the buffer 9904887Schin * 9914887Schin * Copy string s2 to s1. s1 must be large enough. 9924887Schin * return s1-1 (position of string terminator ('\0') in destnation buffer). 9934887Schin */ 9944887Schin static 9954887Schin char *mystpcpy(char *s1, const char *s2) 9964887Schin { 9974887Schin while (*s1++ = *s2++) 9984887Schin ; 9994887Schin return (s1-1); 10004887Schin } 10014887Schin 10024887Schin static 10034887Schin Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) 10044887Schin { 10054887Schin char varnamebuff[PATH_MAX]; 10064887Schin va_list ap; 10074887Schin 10084887Schin va_start(ap, namefmt); 10094887Schin vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); 10104887Schin va_end(ap); 10114887Schin 10124887Schin return nv_open(varnamebuff, dict, flags); 10134887Schin } 10144887Schin 10154887Schin static 10164887Schin int poll_strtoevents(const char *str) 10174887Schin { 10184887Schin int events = 0; 10194887Schin 10204887Schin if (strstr(str, "POLLIN")) events |= POLLIN; 10214887Schin if (strstr(str, "POLLRDNORM")) events |= POLLRDNORM; 10224887Schin if (strstr(str, "POLLRDBAND")) events |= POLLRDBAND; 10234887Schin if (strstr(str, "POLLPRI")) events |= POLLPRI; 10244887Schin if (strstr(str, "POLLOUT")) events |= POLLOUT; 10254887Schin if (strstr(str, "POLLWRNORM")) events |= POLLWRNORM; 10264887Schin if (strstr(str, "POLLWRBAND")) events |= POLLWRBAND; 10274887Schin if (strstr(str, "POLLERR")) events |= POLLERR; 10284887Schin if (strstr(str, "POLLHUP")) events |= POLLHUP; 10294887Schin if (strstr(str, "POLLNVAL")) events |= POLLNVAL; 10304887Schin 10314887Schin return events; 10324887Schin } 10334887Schin 10344887Schin 10354887Schin static 10364887Schin void poll_eventstostr(char *s, int events) 10374887Schin { 10384887Schin *s='\0'; 10394887Schin if (!events) 10404887Schin return; 10414887Schin 10424887Schin if (events & POLLIN) s=mystpcpy(s, "POLLIN|"); 10434887Schin if (events & POLLRDNORM) s=mystpcpy(s, "POLLRDNORM|"); 10444887Schin if (events & POLLRDBAND) s=mystpcpy(s, "POLLRDBAND|"); 10454887Schin if (events & POLLPRI) s=mystpcpy(s, "POLLPRI|"); 10464887Schin if (events & POLLOUT) s=mystpcpy(s, "POLLOUT|"); 10474887Schin if (events & POLLWRNORM) s=mystpcpy(s, "POLLWRNORM|"); 10484887Schin if (events & POLLWRBAND) s=mystpcpy(s, "POLLWRBAND|"); 10494887Schin if (events & POLLERR) s=mystpcpy(s, "POLLERR|"); 10504887Schin if (events & POLLHUP) s=mystpcpy(s, "POLLHUP|"); 10514887Schin if (events & POLLNVAL) s=mystpcpy(s, "POLLNVAL|"); 10524887Schin 10534887Schin /* Remove trailling '|' */ 10544887Schin s--; 10554887Schin if(*s=='|') 10564887Schin *s='\0'; 10574887Schin } 1058*8462SApril.Chin@Sun.COM 1059*8462SApril.Chin@Sun.COM #undef getconf 1060*8462SApril.Chin@Sun.COM #define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) 10614887Schin 10624887Schin extern int b_poll(int argc, char *argv[], void *extra) 10634887Schin { 10644887Schin register Namval_t *np; 10654887Schin register int n; 1066*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra); 10674887Schin char *varname; 10684887Schin int fd; 10694887Schin unsigned int numpollfd = 0; 10704887Schin int i; 10714887Schin char *s; 1072*8462SApril.Chin@Sun.COM double timeout = -1.; 10734887Schin char buff[256]; 1074*8462SApril.Chin@Sun.COM char *pollfdcountvarname = NULL; 1075*8462SApril.Chin@Sun.COM long open_max, 1076*8462SApril.Chin@Sun.COM bpoll_max; 1077*8462SApril.Chin@Sun.COM 1078*8462SApril.Chin@Sun.COM if ((open_max = getconf("OPEN_MAX")) <= 0) 1079*8462SApril.Chin@Sun.COM open_max = OPEN_MAX; 1080*8462SApril.Chin@Sun.COM /* |bpoll_max| needs to be larger than |OPEN_MAX| to make sure we 1081*8462SApril.Chin@Sun.COM * can listen to different sets of events per fd. 1082*8462SApril.Chin@Sun.COM */ 1083*8462SApril.Chin@Sun.COM bpoll_max = open_max*2L; 1084*8462SApril.Chin@Sun.COM 10854887Schin while (n = optget(argv, sh_optpoll)) switch (n) 10864887Schin { 10874887Schin case 't': 1088*8462SApril.Chin@Sun.COM case 'T': 10894887Schin errno = 0; 1090*8462SApril.Chin@Sun.COM timeout = strtod(opt_info.arg, (char **)NULL); 10914887Schin if (errno != 0) 10924887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); 1093*8462SApril.Chin@Sun.COM 1094*8462SApril.Chin@Sun.COM /* -t uses seconds, -T milliseconds */ 1095*8462SApril.Chin@Sun.COM if (n == 't') 1096*8462SApril.Chin@Sun.COM timeout *= 1000.; 1097*8462SApril.Chin@Sun.COM break; 1098*8462SApril.Chin@Sun.COM case 'c': 1099*8462SApril.Chin@Sun.COM pollfdcountvarname = opt_info.arg; 11004887Schin break; 11014887Schin case ':': 11024887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 11034887Schin break; 11044887Schin case '?': 11054887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 11064887Schin break; 11074887Schin } 11084887Schin argc -= opt_info.index; 11094887Schin argv += opt_info.index; 11104887Schin if(argc!=1) 11114887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 11124887Schin 11134887Schin varname = argv[0]; 1114*8462SApril.Chin@Sun.COM 1115*8462SApril.Chin@Sun.COM struct pollfd pollfd[bpoll_max]; 11164887Schin 1117*8462SApril.Chin@Sun.COM for(i=0 ; i < bpoll_max ; i++) 11184887Schin { 1119*8462SApril.Chin@Sun.COM np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); 11204887Schin if (!np) 11214887Schin break; 11224887Schin fd = (int)nv_getnum(np); 11234887Schin if (fd < 0 || fd > OPEN_MAX) 1124*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "invalid pollfd fd"); 11254887Schin nv_close(np); 11264887Schin pollfd[i].fd = fd; 11274887Schin 1128*8462SApril.Chin@Sun.COM np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); 1129*8462SApril.Chin@Sun.COM if (!np) 1130*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "missing pollfd events"); 11314887Schin 11324887Schin s = nv_getval(np); 11334887Schin if (!s) 1134*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "missing pollfd events value"); 11354887Schin pollfd[i].events = poll_strtoevents(s); 11364887Schin nv_close(np); 11374887Schin 11384887Schin pollfd[i].revents = 0; 11394887Schin 11404887Schin numpollfd++; 11414887Schin } 11424887Schin 1143*8462SApril.Chin@Sun.COM if (i == bpoll_max) 1144*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "cannot handle more than %d entries.", bpoll_max); 11454887Schin 11464887Schin n = poll(pollfd, numpollfd, timeout); 11474887Schin /* FixMe: EGAIN and EINTR may require extra handling */ 11484887Schin if (n < 0) 1149*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "failure"); 1150*8462SApril.Chin@Sun.COM 1151*8462SApril.Chin@Sun.COM if (pollfdcountvarname) 1152*8462SApril.Chin@Sun.COM { 1153*8462SApril.Chin@Sun.COM int32_t v = n; 1154*8462SApril.Chin@Sun.COM 1155*8462SApril.Chin@Sun.COM np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s", pollfdcountvarname); 1156*8462SApril.Chin@Sun.COM if (!np) 1157*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "couldn't create poll count variable %s", pollfdcountvarname); 1158*8462SApril.Chin@Sun.COM nv_putval(np, (char *)&v, NV_INTEGER); 1159*8462SApril.Chin@Sun.COM nv_close(np); 1160*8462SApril.Chin@Sun.COM } 11614887Schin 11624887Schin for(i=0 ; i < numpollfd ; i++) 11634887Schin { 1164*8462SApril.Chin@Sun.COM np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%d].revents", varname, i); 11654887Schin if (!np) 1166*8462SApril.Chin@Sun.COM errormsg(SH_DICT, ERROR_system(1), "couldn't create pollfd %s[%d].revents", varname, i); 11674887Schin 11684887Schin poll_eventstostr(buff, pollfd[i].revents); 11694887Schin 11704887Schin nv_putval(np, buff, 0); 11714887Schin nv_close(np); 11724887Schin } 11734887Schin 11744887Schin return(0); 11754887Schin } 11764887Schin 11774887Schin static const char sh_optrewind[] = 11784887Schin "[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]" 11794887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 11804887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 11814887Schin "[+NAME? rewind - reset file position indicator in a stream]" 11824887Schin "[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]" 11834887Schin "\n" 11844887Schin "\nfd\n" 11854887Schin "\n" 11864887Schin "[+EXIT STATUS?]{" 11874887Schin "[+0?Success.]" 11884887Schin "[+>0?An error occurred.]" 11894887Schin "}" 11904887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]" 11914887Schin ; 11924887Schin 11934887Schin 11944887Schin extern int b_rewind(int argc, char *argv[], void *extra) 11954887Schin { 1196*8462SApril.Chin@Sun.COM Shell_t *shp = sh_contexttoshell(extra); 11974887Schin int fd = -1; 11984887Schin register int n; 11994887Schin while (n = optget(argv, sh_optrewind)) switch (n) 12004887Schin { 12014887Schin case ':': 12024887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 12034887Schin break; 12044887Schin case '?': 12054887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 12064887Schin break; 12074887Schin } 12084887Schin argc -= opt_info.index; 12094887Schin argv += opt_info.index; 12104887Schin if(argc!=1) 12114887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 12124887Schin 12134887Schin errno = 0; 12144887Schin fd = strtol(argv[0], (char **)NULL, 0); 12154887Schin if (errno != 0 || fd < 0) 12164887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]); 12174887Schin 12184887Schin if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1) 12194887Schin errormsg(SH_DICT, ERROR_system(1), "seek error"); 12204887Schin 12214887Schin return(0); 12224887Schin } 1223