1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin 22*4887Schin #include <shell.h> 23*4887Schin #include <stdio.h> 24*4887Schin #include <option.h> 25*4887Schin #include <stk.h> 26*4887Schin #include <tm.h> 27*4887Schin #include "name.h" 28*4887Schin #undef nv_isnull 29*4887Schin #ifndef SH_DICT 30*4887Schin # define SH_DICT "libshell" 31*4887Schin #endif 32*4887Schin #include <poll.h> 33*4887Schin 34*4887Schin /* 35*4887Schin * time formatting related 36*4887Schin */ 37*4887Schin struct dctime 38*4887Schin { 39*4887Schin Namfun_t fun; 40*4887Schin Namval_t *format; 41*4887Schin char buff[256]; /* Must be large enougth for |tmfmt()| */ 42*4887Schin }; 43*4887Schin 44*4887Schin static char *get_time(Namval_t* np, Namfun_t* nfp) 45*4887Schin { 46*4887Schin struct dctime *dp = (struct dctime*)nfp; 47*4887Schin time_t t = nv_getn(np,nfp); 48*4887Schin char *format = nv_getval(dp->format); 49*4887Schin tmfmt(dp->buff,sizeof(dp->buff),format,(time_t*)0); 50*4887Schin return(dp->buff); 51*4887Schin } 52*4887Schin 53*4887Schin static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp) 54*4887Schin { 55*4887Schin struct dctime *dp = (struct dctime*)nfp; 56*4887Schin char *last; 57*4887Schin if(val) 58*4887Schin { 59*4887Schin int32_t t; 60*4887Schin if(flag&NV_INTEGER) 61*4887Schin { 62*4887Schin if(flag&NV_LONG) 63*4887Schin t = *(Sfdouble_t*)val; 64*4887Schin else 65*4887Schin t = *(double*)val; 66*4887Schin } 67*4887Schin else 68*4887Schin { 69*4887Schin t = tmdate(val, &last, (time_t*)0); 70*4887Schin if(*last) 71*4887Schin errormsg(SH_DICT, ERROR_exit(1),"%s: invalid date/time string", val); 72*4887Schin } 73*4887Schin nv_putv(np, (char*)&t,NV_INTEGER, nfp); 74*4887Schin } 75*4887Schin else 76*4887Schin { 77*4887Schin nv_unset(dp->format); 78*4887Schin free((void*)dp->format); 79*4887Schin nv_putv(np, val, flag, nfp); 80*4887Schin } 81*4887Schin } 82*4887Schin 83*4887Schin static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp) 84*4887Schin { 85*4887Schin struct dctime *dp = (struct dctime*)nfp; 86*4887Schin if(strcmp(name, "format")) 87*4887Schin return((Namval_t*)0); 88*4887Schin return(dp->format); 89*4887Schin } 90*4887Schin 91*4887Schin static const Namdisc_t timedisc = 92*4887Schin { 93*4887Schin sizeof(struct dctime), 94*4887Schin put_time, 95*4887Schin get_time, 96*4887Schin 0, 97*4887Schin 0, 98*4887Schin create_time, 99*4887Schin }; 100*4887Schin 101*4887Schin 102*4887Schin static Namval_t *make_time(Namval_t* np) 103*4887Schin { 104*4887Schin int offset = stktell(stkstd); 105*4887Schin char *name = nv_name(np); 106*4887Schin struct dctime *dp = newof(NULL,struct dctime,1,0); 107*4887Schin if(!dp) 108*4887Schin return((Namval_t*)0); 109*4887Schin sfprintf(stkstd,"%s.format\0",name); 110*4887Schin sfputc(stkstd,0); 111*4887Schin dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); 112*4887Schin dp->fun.disc = &timedisc; 113*4887Schin nv_stack(np,&dp->fun); 114*4887Schin return(np); 115*4887Schin } 116*4887Schin 117*4887Schin /* 118*4887Schin * mode formatting related 119*4887Schin */ 120*4887Schin static char *get_mode(Namval_t* np, Namfun_t* nfp) 121*4887Schin { 122*4887Schin mode_t mode = nv_getn(np,nfp); 123*4887Schin return(fmtperm(mode)); 124*4887Schin } 125*4887Schin 126*4887Schin static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) 127*4887Schin { 128*4887Schin if(val) 129*4887Schin { 130*4887Schin int32_t mode; 131*4887Schin char *last; 132*4887Schin if(flag&NV_INTEGER) 133*4887Schin { 134*4887Schin if(flag&NV_LONG) 135*4887Schin mode = *(Sfdouble_t*)val; 136*4887Schin else 137*4887Schin mode = *(double*)val; 138*4887Schin } 139*4887Schin else 140*4887Schin { 141*4887Schin mode = strperm(val, &last,0); 142*4887Schin if(*last) 143*4887Schin errormsg(SH_DICT, ERROR_exit(1),"%s: invalid mode string", val); 144*4887Schin } 145*4887Schin nv_putv(np,(char*)&mode,NV_INTEGER,nfp); 146*4887Schin } 147*4887Schin else 148*4887Schin nv_putv(np,val,flag,nfp); 149*4887Schin } 150*4887Schin 151*4887Schin static const Namdisc_t modedisc = 152*4887Schin { 153*4887Schin 0, 154*4887Schin put_mode, 155*4887Schin get_mode, 156*4887Schin }; 157*4887Schin 158*4887Schin static Namval_t *make_mode(Namval_t* np) 159*4887Schin { 160*4887Schin char *name = nv_name(np); 161*4887Schin Namfun_t *nfp = newof(NULL,Namfun_t,1,0); 162*4887Schin if(!nfp) 163*4887Schin return((Namval_t*)0); 164*4887Schin nfp->disc = &modedisc; 165*4887Schin nv_stack(np,nfp); 166*4887Schin return(np); 167*4887Schin } 168*4887Schin 169*4887Schin /* 170*4887Schin * field related typese and functions 171*4887Schin */ 172*4887Schin typedef struct _field_ 173*4887Schin { 174*4887Schin char *name; /* field name */ 175*4887Schin int flags; /* flags */ 176*4887Schin short offset; /* offset of field into data */ 177*4887Schin short size; /* size of field */ 178*4887Schin Namval_t *(*make)(Namval_t*); /* discipline constructor */ 179*4887Schin } Shfield_t; 180*4887Schin 181*4887Schin /* 182*4887Schin * lookup field in field table 183*4887Schin */ 184*4887Schin static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name) 185*4887Schin { 186*4887Schin Shfield_t *fp = ftable; 187*4887Schin register int i,n; 188*4887Schin register const char *cp; 189*4887Schin for(cp=name; *cp; cp++) 190*4887Schin { 191*4887Schin if(*cp=='.') 192*4887Schin break; 193*4887Schin } 194*4887Schin n = cp-name; 195*4887Schin for(i=0; i < nelem; i++,fp++) 196*4887Schin { 197*4887Schin if(memcmp(fp->name,name,n)==0 && fp->name[n]==0) 198*4887Schin return(fp); 199*4887Schin } 200*4887Schin return(0); 201*4887Schin } 202*4887Schin 203*4887Schin /* 204*4887Schin * class types and functions 205*4887Schin */ 206*4887Schin 207*4887Schin typedef struct _class_ 208*4887Schin { 209*4887Schin int nelem; /* number of elements */ 210*4887Schin int dsize; /* size for data structure */ 211*4887Schin Shfield_t *fields; /* field description table */ 212*4887Schin } Shclass_t; 213*4887Schin 214*4887Schin struct dcclass 215*4887Schin { 216*4887Schin Namfun_t fun; 217*4887Schin Shclass_t sclass; 218*4887Schin }; 219*4887Schin 220*4887Schin static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np) 221*4887Schin { 222*4887Schin char *val = np->nvalue + fp->offset; 223*4887Schin char *name = nv_name(np); 224*4887Schin register Namval_t *nq; 225*4887Schin int offset = stktell(stkstd); 226*4887Schin sfprintf(stkstd,"%s.%s\0",name,fp->name); 227*4887Schin sfputc(stkstd,0); 228*4887Schin nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); 229*4887Schin if(fp->size<0) 230*4887Schin val = *(char**)val; 231*4887Schin nv_putval(nq,val,fp->flags|NV_NOFREE); 232*4887Schin if(fp->make) 233*4887Schin (*fp->make)(nq); 234*4887Schin return(nq); 235*4887Schin } 236*4887Schin 237*4887Schin static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp) 238*4887Schin { 239*4887Schin struct dcclass *dcp = (struct dcclass*)nfp; 240*4887Schin Shclass_t *sp = &dcp->sclass; 241*4887Schin Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name); 242*4887Schin Namval_t *nq,**nodes = (Namval_t**)(dcp+1); 243*4887Schin int n = fp-sp->fields; 244*4887Schin int len = strlen(fp->name); 245*4887Schin void *data = (void*)np->nvalue; 246*4887Schin if(!(nq=nodes[n])) 247*4887Schin { 248*4887Schin nodes[n] = nq = sh_newnode(fp,np); 249*4887Schin nfp->last = ""; 250*4887Schin } 251*4887Schin if(name[len]==0) 252*4887Schin return(nq); 253*4887Schin return(nq); 254*4887Schin } 255*4887Schin 256*4887Schin static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar) 257*4887Schin { 258*4887Schin Shfield_t *fp = sp->fields; 259*4887Schin Namval_t *np, **nodes= (Namval_t**)(sp+1); 260*4887Schin register int i,isarray; 261*4887Schin if(out) 262*4887Schin { 263*4887Schin sfwrite(out,"(\n",2); 264*4887Schin indent++; 265*4887Schin } 266*4887Schin for(i=0; i < sp->nelem; i++,fp++) 267*4887Schin { 268*4887Schin #if 0 269*4887Schin /* handle recursive case */ 270*4887Schin #endif 271*4887Schin if(!(np=nodes[i]) && out) 272*4887Schin np = sh_newnode(fp,npar); 273*4887Schin if(np) 274*4887Schin { 275*4887Schin isarray=0; 276*4887Schin if(nv_isattr(np,NV_ARRAY)) 277*4887Schin { 278*4887Schin isarray=1; 279*4887Schin if(array_elem(nv_arrayptr(np))==0) 280*4887Schin isarray=2; 281*4887Schin else 282*4887Schin nv_putsub(np,(char*)0,ARRAY_SCAN); 283*4887Schin } 284*4887Schin sfnputc(out,'\t',indent); 285*4887Schin sfputr(out,fp->name,(isarray==2?'\n':'=')); 286*4887Schin if(isarray) 287*4887Schin { 288*4887Schin if(isarray==2) 289*4887Schin continue; 290*4887Schin sfwrite(out,"(\n",2); 291*4887Schin sfnputc(out,'\t',++indent); 292*4887Schin } 293*4887Schin while(1) 294*4887Schin { 295*4887Schin char *fmtq; 296*4887Schin if(isarray) 297*4887Schin { 298*4887Schin sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np))); 299*4887Schin sfputc(out,'='); 300*4887Schin } 301*4887Schin if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq))) 302*4887Schin fmtq = ""; 303*4887Schin sfputr(out,fmtq,'\n'); 304*4887Schin if(!nv_nextsub(np)) 305*4887Schin break; 306*4887Schin sfnputc(out,'\t',indent); 307*4887Schin } 308*4887Schin if(isarray) 309*4887Schin { 310*4887Schin sfnputc(out,'\t',--indent); 311*4887Schin sfwrite(out,")\n",2); 312*4887Schin } 313*4887Schin } 314*4887Schin } 315*4887Schin if(out) 316*4887Schin { 317*4887Schin if(indent>1) 318*4887Schin sfnputc(out,'\t',indent-1); 319*4887Schin sfputc(out,')'); 320*4887Schin } 321*4887Schin } 322*4887Schin 323*4887Schin static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp) 324*4887Schin { 325*4887Schin static Sfio_t *out; 326*4887Schin Sfio_t *outfile; 327*4887Schin int savtop = stktell(stkstd); 328*4887Schin char *savptr = stkfreeze(stkstd,0); 329*4887Schin if(dlete) 330*4887Schin outfile = 0; 331*4887Schin else if(!(outfile=out)) 332*4887Schin outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 333*4887Schin else 334*4887Schin sfseek(outfile,0L,SEEK_SET); 335*4887Schin genvalue(outfile,&dcp->sclass,0,np); 336*4887Schin stkset(stkstd,savptr,savtop); 337*4887Schin if(!outfile) 338*4887Schin return((char*)0); 339*4887Schin sfputc(out,0); 340*4887Schin return((char*)out->_data); 341*4887Schin } 342*4887Schin 343*4887Schin static char *get_classval(Namval_t* np, Namfun_t* nfp) 344*4887Schin { 345*4887Schin return(walk_class(np,0,(struct dcclass *)nfp)); 346*4887Schin } 347*4887Schin 348*4887Schin static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp) 349*4887Schin { 350*4887Schin walk_class(np,1,(struct dcclass *)nfp); 351*4887Schin if(nfp = nv_stack(np,(Namfun_t*)0)) 352*4887Schin { 353*4887Schin free((void*)nfp); 354*4887Schin if(np->nvalue && !nv_isattr(np,NV_NOFREE)) 355*4887Schin free((void*)np->nvalue); 356*4887Schin } 357*4887Schin if(val) 358*4887Schin nv_putval(np,val,flag); 359*4887Schin } 360*4887Schin 361*4887Schin static const Namdisc_t classdisc = 362*4887Schin { 363*4887Schin sizeof(struct dcclass), 364*4887Schin put_classval, 365*4887Schin get_classval, 366*4887Schin 0, 367*4887Schin 0, 368*4887Schin fieldcreate 369*4887Schin }; 370*4887Schin 371*4887Schin static int mkclass(Namval_t *np, Shclass_t *sp) 372*4887Schin { 373*4887Schin struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*)); 374*4887Schin if(!tcp) 375*4887Schin return(0); 376*4887Schin memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*)); 377*4887Schin tcp->fun.disc = &classdisc; 378*4887Schin tcp->sclass = *sp; 379*4887Schin np->nvalue = (char*)calloc(sp->dsize,1); 380*4887Schin nv_stack(np,&tcp->fun); 381*4887Schin return(1); 382*4887Schin } 383*4887Schin 384*4887Schin /* 385*4887Schin * ====================from here down is file class specific 386*4887Schin */ 387*4887Schin static struct stat *Sp; 388*4887Schin 389*4887Schin struct filedata 390*4887Schin { 391*4887Schin struct stat statb; 392*4887Schin int fd; 393*4887Schin char *name; 394*4887Schin }; 395*4887Schin 396*4887Schin static Shfield_t filefield[] = 397*4887Schin { 398*4887Schin { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time}, 399*4887Schin { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time}, 400*4887Schin { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)}, 401*4887Schin { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)}, 402*4887Schin { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)}, 403*4887Schin { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)}, 404*4887Schin { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode}, 405*4887Schin { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time}, 406*4887Schin { "name", NV_RDONLY, offsetof(struct filedata,name), -1 }, 407*4887Schin { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)}, 408*4887Schin { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)}, 409*4887Schin { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)} 410*4887Schin }; 411*4887Schin 412*4887Schin static Shclass_t Fileclass = 413*4887Schin { 414*4887Schin sizeof(filefield)/sizeof(*filefield), 415*4887Schin sizeof(struct filedata), 416*4887Schin filefield 417*4887Schin }; 418*4887Schin 419*4887Schin 420*4887Schin #define letterbit(bit) (1<<((bit)-'a')) 421*4887Schin 422*4887Schin static const char sh_optopen[] = 423*4887Schin "[-?\n@(#)$Id: open (AT&T Labs Research) 2007-05-07 $\n]" 424*4887Schin "[-author?David Korn <dgk@research.att.com>]" 425*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 426*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 427*4887Schin "[+NAME? open - create a shell variable correspnding to a file]" 428*4887Schin "[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding " 429*4887Schin "to the file given by the pathname \afile\a. The elements of \avar\a " 430*4887Schin "are the names of elements in the \astat\a structure with the \bst_\b " 431*4887Schin "prefix removed.]" 432*4887Schin "[+?\afile\a is opened (based on \b-r\b and/or \b-w\b) and the variable " 433*4887Schin "\avar\a\b.fd\b is the file descriptor.]" 434*4887Schin "[a:append?Open for append.]" 435*4887Schin "[b:binary?Open in binary mode" 436*4887Schin #ifndef O_BINARY 437*4887Schin " (not supported/ignored on this platform)" 438*4887Schin #endif 439*4887Schin ".]" 440*4887Schin "[t:text?Open in text mode" 441*4887Schin #ifndef O_TEXT 442*4887Schin " (not supported/ignored on this platform)" 443*4887Schin #endif 444*4887Schin ".]" 445*4887Schin "[c:create?Open for create.]" 446*4887Schin "[i:inherit?Open without the close-on-exec bit set.]" 447*4887Schin "[I:noinherit?Open with the close-on-exec bit set.]" 448*4887Schin "[r:read?Open with read access.]" 449*4887Schin "[w:write?Open with write access.]" 450*4887Schin "[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]" 451*4887Schin "[x:exclusive?Open exclusive.]" 452*4887Schin 453*4887Schin "[N:nofollow?If the path names a symbolic link, open fails with ELOOP " 454*4887Schin #ifndef O_NOFOLLOW 455*4887Schin " (not supported/ignored on this platform)" 456*4887Schin #endif 457*4887Schin ".]" 458*4887Schin "[S:sync?Write I/O operations on the file descriptor complete as " 459*4887Schin "defined by synchronized I/O file integrity completion" 460*4887Schin #ifndef O_SYNC 461*4887Schin " (not supported/ignored on this platform)" 462*4887Schin #endif 463*4887Schin ".]" 464*4887Schin "[T:trunc?If the file exists and is a regular file, and the file " 465*4887Schin "is successfully opened read/write or write-only, its length is " 466*4887Schin "truncated to 0 and the mode and owner are unchanged. It " 467*4887Schin "has no effect on FIFO special files or terminal device " 468*4887Schin "files. Its effect on other file types is " 469*4887Schin "implementation-dependent. The result of using -T " 470*4887Schin "with read-only files is undefined" 471*4887Schin #ifndef O_TRUNC 472*4887Schin " (not supported/ignored on this platform)" 473*4887Schin #endif 474*4887Schin ".]" 475*4887Schin "\n" 476*4887Schin "\nvar file\n" 477*4887Schin "\n" 478*4887Schin "[+EXIT STATUS?]{" 479*4887Schin "[+0?Success.]" 480*4887Schin "[+>0?An error occurred.]" 481*4887Schin "}" 482*4887Schin "[+SEE ALSO?\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bpoll\b(1),\bstat\b(2)]" 483*4887Schin ; 484*4887Schin 485*4887Schin 486*4887Schin extern int b_open(int argc, char *argv[], void *extra) 487*4887Schin { 488*4887Schin register Namval_t *np; 489*4887Schin register int n,oflag=0; 490*4887Schin Shell_t *shp = (Shell_t*)extra; 491*4887Schin struct filedata *fdp; 492*4887Schin mode_t mode = 0666; 493*4887Schin long flags = 0; 494*4887Schin int fd = -1; 495*4887Schin char *arg; 496*4887Schin 497*4887Schin while (n = optget(argv, sh_optopen)) switch (n) 498*4887Schin { 499*4887Schin case 'r': 500*4887Schin case 'w': 501*4887Schin case 'i': 502*4887Schin flags |= letterbit(n); 503*4887Schin break; 504*4887Schin case 'I': 505*4887Schin flags &= ~(letterbit('i')); 506*4887Schin break; 507*4887Schin case 'b': 508*4887Schin #ifdef O_BINARY 509*4887Schin oflag |= O_BINARY; 510*4887Schin #endif 511*4887Schin break; 512*4887Schin case 't': 513*4887Schin #ifdef O_TEXT 514*4887Schin oflag |= O_TEXT; 515*4887Schin #endif 516*4887Schin break; 517*4887Schin case 'N': 518*4887Schin #ifdef O_NOFOLLOW 519*4887Schin oflag |= O_NOFOLLOW; 520*4887Schin #endif 521*4887Schin break; 522*4887Schin case 'T': 523*4887Schin #ifdef O_TRUNC 524*4887Schin oflag |= O_TRUNC; 525*4887Schin #endif 526*4887Schin break; 527*4887Schin case 'x': 528*4887Schin oflag |= O_EXCL; 529*4887Schin break; 530*4887Schin case 'c': 531*4887Schin oflag |= O_CREAT; 532*4887Schin break; 533*4887Schin case 'a': 534*4887Schin oflag |= O_APPEND; 535*4887Schin break; 536*4887Schin case 'S': 537*4887Schin #ifdef O_SYNC 538*4887Schin oflag |= O_SYNC; 539*4887Schin #endif 540*4887Schin break; 541*4887Schin case 'm': 542*4887Schin mode = strperm(arg = opt_info.arg, &opt_info.arg, mode); 543*4887Schin if (*opt_info.arg) 544*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid mode", arg); 545*4887Schin break; 546*4887Schin case ':': 547*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 548*4887Schin break; 549*4887Schin case '?': 550*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 551*4887Schin break; 552*4887Schin } 553*4887Schin argc -= opt_info.index; 554*4887Schin argv += opt_info.index; 555*4887Schin if(argc!=2 || !(flags&(letterbit('r')|letterbit('w')))) 556*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 557*4887Schin 558*4887Schin if(flags&letterbit('r')) 559*4887Schin { 560*4887Schin if(flags&letterbit('w')) 561*4887Schin oflag |= O_RDWR; 562*4887Schin else 563*4887Schin oflag |= O_RDONLY; 564*4887Schin } 565*4887Schin else if(flags&letterbit('w')) 566*4887Schin oflag |= O_WRONLY; 567*4887Schin 568*4887Schin fd = sh_open(argv[1], oflag, mode); 569*4887Schin if(fd<0) 570*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: open failed", argv[1]); 571*4887Schin 572*4887Schin if(!(flags&letterbit('i'))) 573*4887Schin fcntl(fd, F_SETFL, 0); 574*4887Schin 575*4887Schin np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN); 576*4887Schin if(!nv_isnull(np)) 577*4887Schin nv_unset(np); 578*4887Schin mkclass(np, &Fileclass); 579*4887Schin fdp = (struct filedata*)np->nvalue; 580*4887Schin fstat(fd, &fdp->statb); 581*4887Schin fdp->fd = fd; 582*4887Schin fdp->name = strdup(argv[1]); 583*4887Schin return(0); 584*4887Schin } 585*4887Schin 586*4887Schin static const char sh_optclose[] = 587*4887Schin "[-?\n@(#)$Id: close (AT&T Labs Research) 2007-04-21 $\n]" 588*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 589*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 590*4887Schin "[+NAME? close - close a file descriptor]" 591*4887Schin "[+DESCRIPTION?\bclose\b closes the file descriptor specified by fd.]" 592*4887Schin "\n" 593*4887Schin "\nfd\n" 594*4887Schin "\n" 595*4887Schin "[+EXIT STATUS?]{" 596*4887Schin "[+0?Success.]" 597*4887Schin "[+>0?An error occurred.]" 598*4887Schin "}" 599*4887Schin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\btmpfile\b(1),\bpoll\b(1),\bstat\b(1)]" 600*4887Schin ; 601*4887Schin 602*4887Schin extern int b_close(int argc, char *argv[], void *extra) 603*4887Schin { 604*4887Schin register int n=0; 605*4887Schin int fd = -1; 606*4887Schin 607*4887Schin while (n = optget(argv, sh_optclose)) switch (n) 608*4887Schin { 609*4887Schin case ':': 610*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 611*4887Schin break; 612*4887Schin case '?': 613*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 614*4887Schin break; 615*4887Schin } 616*4887Schin argc -= opt_info.index; 617*4887Schin argv += opt_info.index; 618*4887Schin if(argc!=1) 619*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 620*4887Schin 621*4887Schin errno = 0; 622*4887Schin fd = strtol(argv[0], (char **)NULL, 0); 623*4887Schin if (errno != 0 || fd < 0) 624*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid descriptor", argv[0]); 625*4887Schin 626*4887Schin n = sh_close(fd); 627*4887Schin 628*4887Schin if (n < 0) 629*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: close error", argv[0]); 630*4887Schin 631*4887Schin return(n==0?0:1); 632*4887Schin } 633*4887Schin 634*4887Schin 635*4887Schin static const char sh_opttmpfile[] = 636*4887Schin "[-?\n@(#)$Id: tmpfile (AT&T Labs Research) 2007-05-07 $\n]" 637*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 638*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 639*4887Schin "[+NAME? tmpfile - create a shell variable correspnding to a temporary file]" 640*4887Schin "[+DESCRIPTION?\btmpfile\b creates the compound variable \avar\a correspinding " 641*4887Schin "to a temporary file. The elements of \avar\a " 642*4887Schin "are the names of elements in the \astat\a structure with the \bst_\b " 643*4887Schin "prefix removed.]" 644*4887Schin "[i:inherit?Open without the close-on-exec bit set.]" 645*4887Schin "[I:noinherit?Open with the close-on-exec bit set.]" 646*4887Schin "\n" 647*4887Schin "\nvar\n" 648*4887Schin "\n" 649*4887Schin "[+EXIT STATUS?]{" 650*4887Schin "[+0?Success.]" 651*4887Schin "[+>0?An error occurred.]" 652*4887Schin "}" 653*4887Schin "[+SEE ALSO?\bopen\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]" 654*4887Schin ; 655*4887Schin 656*4887Schin 657*4887Schin extern int b_tmpfile(int argc, char *argv[], void *extra) 658*4887Schin { 659*4887Schin register Namval_t *np; 660*4887Schin register int n; 661*4887Schin Shell_t *shp = (Shell_t*)extra; 662*4887Schin struct filedata *fdp; 663*4887Schin int inherit = 0; 664*4887Schin FILE *file = NULL; 665*4887Schin int ffd, fd = -1; 666*4887Schin while (n = optget(argv, sh_opttmpfile)) switch (n) 667*4887Schin { 668*4887Schin case 'i': 669*4887Schin inherit = 1; 670*4887Schin break; 671*4887Schin case 'I': 672*4887Schin inherit = 0; 673*4887Schin break; 674*4887Schin case ':': 675*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 676*4887Schin break; 677*4887Schin case '?': 678*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 679*4887Schin break; 680*4887Schin } 681*4887Schin argc -= opt_info.index; 682*4887Schin argv += opt_info.index; 683*4887Schin if(argc!=1) 684*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 685*4887Schin 686*4887Schin file = tmpfile(); 687*4887Schin if(!file) 688*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]); 689*4887Schin ffd = fileno(file); 690*4887Schin fd = sh_dup(ffd); 691*4887Schin if(fd<0) 692*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]); 693*4887Schin fclose(file); 694*4887Schin 695*4887Schin if(!inherit) 696*4887Schin fcntl(fd, F_SETFL, 0); 697*4887Schin 698*4887Schin np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN); 699*4887Schin if(!nv_isnull(np)) 700*4887Schin nv_unset(np); 701*4887Schin mkclass(np,&Fileclass); 702*4887Schin fdp = (struct filedata*)np->nvalue; 703*4887Schin 704*4887Schin fstat(fd, &fdp->statb); 705*4887Schin fdp->fd = fd; 706*4887Schin fdp->name = NULL; 707*4887Schin return(0); 708*4887Schin } 709*4887Schin 710*4887Schin static const char sh_optdup[] = 711*4887Schin "[-?\n@(#)$Id: dup (AT&T Labs Research) 2007-05-07 $\n]" 712*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 713*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 714*4887Schin "[+NAME? dup - duplicate an open file descriptor]" 715*4887Schin "[+DESCRIPTION?The \bdup\b commands returns a new file descriptor having the " 716*4887Schin "following in common with the original open file descriptor " 717*4887Schin "fd: same open file (or pipe), same file pointer (that is, both file descriptors " 718*4887Schin "share one file pointer) same access mode (read, write or read/write). " 719*4887Schin "The file descriptor returned is the lowest one available.]" 720*4887Schin "[i:inherit?Open without the close-on-exec bit set.]" 721*4887Schin "[I:noinherit?Open with the close-on-exec bit set.]" 722*4887Schin "\n" 723*4887Schin "\nvar fd\n" 724*4887Schin "\n" 725*4887Schin "[+EXIT STATUS?]{" 726*4887Schin "[+0?Success.]" 727*4887Schin "[+>0?An error occurred.]" 728*4887Schin "}" 729*4887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(1)]" 730*4887Schin ; 731*4887Schin 732*4887Schin 733*4887Schin extern int b_dup(int argc, char *argv[], void *extra) 734*4887Schin { 735*4887Schin register Namval_t *np; 736*4887Schin register int n; 737*4887Schin Shell_t *shp = (Shell_t*)extra; 738*4887Schin struct filedata *fdp; 739*4887Schin int inherit = 0; 740*4887Schin int ffd, fd = -1; 741*4887Schin while (n = optget(argv, sh_optdup)) switch (n) 742*4887Schin { 743*4887Schin case 'i': 744*4887Schin inherit = 1; 745*4887Schin break; 746*4887Schin case 'I': 747*4887Schin inherit = 0; 748*4887Schin break; 749*4887Schin case ':': 750*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 751*4887Schin break; 752*4887Schin case '?': 753*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 754*4887Schin break; 755*4887Schin } 756*4887Schin argc -= opt_info.index; 757*4887Schin argv += opt_info.index; 758*4887Schin if(argc!=2) 759*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 760*4887Schin 761*4887Schin errno = 0; 762*4887Schin ffd = strtol(argv[1], (char **)NULL, 0); 763*4887Schin if (errno != 0 || ffd < 0) 764*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[1]); 765*4887Schin 766*4887Schin fd = sh_dup(ffd); 767*4887Schin if(fd<0) 768*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: dup failed", argv[1]); 769*4887Schin 770*4887Schin if(!inherit) 771*4887Schin fcntl(fd,F_SETFL,0); 772*4887Schin 773*4887Schin np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); 774*4887Schin if(!nv_isnull(np)) 775*4887Schin nv_unset(np); 776*4887Schin mkclass(np, &Fileclass); 777*4887Schin fdp = (struct filedata*)np->nvalue; 778*4887Schin 779*4887Schin fstat(fd, &fdp->statb); 780*4887Schin fdp->fd = fd; 781*4887Schin fdp->name = NULL; 782*4887Schin return(0); 783*4887Schin } 784*4887Schin 785*4887Schin static const char sh_optstat[] = 786*4887Schin "[-?\n@(#)$Id: stat (AT&T Labs Research) 2007-05-07 $\n]" 787*4887Schin "[-author?David Korn <dgk@research.att.com>]" 788*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 789*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 790*4887Schin "[+NAME? stat - get file status]" 791*4887Schin "[+DESCRIPTION?\bstat\b creates the compound variable \avar\a correspinding " 792*4887Schin "to the file given by the pathname \afile\a. The elements of \avar\a " 793*4887Schin "are the names of elements in the \astat\a structure with the \bst_\b " 794*4887Schin "prefix removed.]" 795*4887Schin "[l:lstat?If the the named file is a symbolic link returns information about " 796*4887Schin "the link itself.]" 797*4887Schin "\n" 798*4887Schin "\nvar file\n" 799*4887Schin "\n" 800*4887Schin "[+EXIT STATUS?]{" 801*4887Schin "[+0?Success.]" 802*4887Schin "[+>0?An error occurred.]" 803*4887Schin "}" 804*4887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(2),\blstat\b(2)]" 805*4887Schin ; 806*4887Schin 807*4887Schin 808*4887Schin extern int b_stat(int argc, char *argv[], void *extra) 809*4887Schin { 810*4887Schin register Namval_t *np; 811*4887Schin register int n; 812*4887Schin Shell_t *shp = (Shell_t*)extra; 813*4887Schin struct filedata *fdp; 814*4887Schin long flags = 0; 815*4887Schin struct stat statb; 816*4887Schin while (n = optget(argv, sh_optstat)) switch (n) 817*4887Schin { 818*4887Schin case 'l': 819*4887Schin flags |= letterbit(n); 820*4887Schin break; 821*4887Schin case ':': 822*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 823*4887Schin break; 824*4887Schin case '?': 825*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 826*4887Schin break; 827*4887Schin } 828*4887Schin argc -= opt_info.index; 829*4887Schin argv += opt_info.index; 830*4887Schin if(argc!=2) 831*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 832*4887Schin 833*4887Schin if(flags&letterbit('l')) 834*4887Schin { 835*4887Schin if(lstat(argv[1], &statb) < 0) 836*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]); 837*4887Schin } 838*4887Schin else 839*4887Schin { 840*4887Schin if(stat(argv[1], &statb) < 0) 841*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]); 842*4887Schin 843*4887Schin } 844*4887Schin 845*4887Schin np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); 846*4887Schin if(!nv_isnull(np)) 847*4887Schin nv_unset(np); 848*4887Schin mkclass(np,&Fileclass); 849*4887Schin fdp = (struct filedata*)np->nvalue; 850*4887Schin fdp->statb = statb; 851*4887Schin fdp->fd = -1; 852*4887Schin fdp->name = strdup(argv[1]); 853*4887Schin return(0); 854*4887Schin } 855*4887Schin 856*4887Schin static const char sh_optpoll[] = 857*4887Schin "[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-05-07 $\n]" 858*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org]" 859*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 860*4887Schin "[+NAME? poll - input/output multiplexing]" 861*4887Schin "[+DESCRIPTION?The poll command provides applications with a mechanism " 862*4887Schin "for multiplexing input/output over a set of file descriptors. " 863*4887Schin "For each member of the array variable \bvar\b, " 864*4887Schin "poll examines the given file descriptor in the subscript \b.fd\b " 865*4887Schin "for the event(s) specified in the subscript \b.events\b." 866*4887Schin "The poll command identifies those file descriptors on which an " 867*4887Schin "application can read or write data, or on which certain events have " 868*4887Schin "occurred.]" 869*4887Schin "[+?The \bvar\b argument specifies the file descriptors to be examined " 870*4887Schin "and the events of interest for each file descriptor. " 871*4887Schin "It is a array of structured variables with one member for each open " 872*4887Schin "file descriptor of interest. The array's members contain the following " 873*4887Schin "subscripts:]{" 874*4887Schin "[+?\b.fd\b # file descriptor]" 875*4887Schin "[+?\b.events\b # requested events]" 876*4887Schin "[+?\b.revents\b # returned event]" 877*4887Schin "}" 878*4887Schin "[+?The \bfd\b variable specifies an open file descriptor and the " 879*4887Schin "\bevents\b and \brevents\b members are strings constructed from " 880*4887Schin "a concaternation of the following event flags, seperated by '|':]" 881*4887Schin "{ " 882*4887Schin "[+POLLIN?Data other than high priority data may be " 883*4887Schin "read without blocking. For STREAMS, this " 884*4887Schin "flag is set in revents even if the message " 885*4887Schin "is of zero length.]" 886*4887Schin "[+POLLRDNORM?Normal data (priority band equals 0) may be " 887*4887Schin "read without blocking. For STREAMS, this " 888*4887Schin "flag is set in revents even if the message " 889*4887Schin "is of zero length.]" 890*4887Schin "[+POLLRDBAND?Data from a non-zero priority band may be " 891*4887Schin "read without blocking. For STREAMS, this " 892*4887Schin "flag is set in revents even if the message " 893*4887Schin "is of zero length.]" 894*4887Schin "[+POLLPRI?High priority data may be received without " 895*4887Schin "blocking. For STREAMS, this flag is set in " 896*4887Schin "revents even if the message is of zero " 897*4887Schin "length.]" 898*4887Schin "[+POLLOUT?Normal data (priority band equals 0) may be " 899*4887Schin "written without blocking.]" 900*4887Schin "[+POLLWRNORM?The same as POLLOUT.]" 901*4887Schin "[+POLLWRBAND?Priority data (priority band > 0) may be " 902*4887Schin "written. This event only examines bands " 903*4887Schin "that have been written to at least once.]" 904*4887Schin "[+POLLERR?An error has occurred on the device or " 905*4887Schin "stream. This flag is only valid in the " 906*4887Schin "revents bitmask; it is not used in the " 907*4887Schin "events member.]" 908*4887Schin "[+POLLHUP?A hangup has occurred on the stream. This " 909*4887Schin "event and POLLOUT are mutually exclusive; a " 910*4887Schin "stream can never be writable if a hangup has " 911*4887Schin "occurred. However, this event and POLLIN, " 912*4887Schin ", POLLRDBAND, or POLLPRI are not " 913*4887Schin "mutually exclusive. This flag is only valid " 914*4887Schin "in the revents bitmask; it is not used in " 915*4887Schin "the events member.]" 916*4887Schin "[+POLLNVAL?The specified fd value does not belong to an " 917*4887Schin "open file. This flag is only valid in the " 918*4887Schin "revents member; it is not used in the events " 919*4887Schin "member.]" 920*4887Schin "}" 921*4887Schin "]" 922*4887Schin 923*4887Schin "[+?If the value fd is less than 0, events is ignored and " 924*4887Schin "revents is set to 0 in that entry on return from poll.]" 925*4887Schin 926*4887Schin "[+?The results of the poll query are stored in the revents " 927*4887Schin "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b " 928*4887Schin "variable to indicate which of the requested events are true. " 929*4887Schin "If none are true, the \brevents\b will be an empty string when " 930*4887Schin "the poll command returns. The event flags " 931*4887Schin "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b " 932*4887Schin "if the conditions they indicate are true; this occurs even " 933*4887Schin "though these flags were not present in events.]" 934*4887Schin 935*4887Schin "[+?If none of the defined events have occurred on any selected " 936*4887Schin "file descriptor, poll waits at least timeout milliseconds " 937*4887Schin "for an event to occur on any of the selected file descriptors. " 938*4887Schin "On a computer where millisecond timing accuracy is not " 939*4887Schin "available, timeout is rounded up to the nearest legal value " 940*4887Schin "available on that system. If the value timeout is 0, poll " 941*4887Schin "returns immediately. If the value of timeout is -1, poll " 942*4887Schin "blocks until a requested event occurs or until the call is " 943*4887Schin "interrupted.]" 944*4887Schin 945*4887Schin "[+?The poll function supports regular files, terminal and " 946*4887Schin "pseudo-terminal devices, STREAMS-based files, FIFOs and " 947*4887Schin "pipes. The behavior of poll on elements of fds that refer " 948*4887Schin "to other types of file is unspecified.]" 949*4887Schin 950*4887Schin "[+?The poll function supports sockets.]" 951*4887Schin 952*4887Schin "[+?A file descriptor for a socket that is listening for connections " 953*4887Schin "will indicate that it is ready for reading, once connections " 954*4887Schin "are available. A file descriptor for a socket that " 955*4887Schin "is connecting asynchronously will indicate that it is ready " 956*4887Schin "for writing, once a connection has been established.]" 957*4887Schin 958*4887Schin "[+?Regular files always poll TRUE for reading and writing.]" 959*4887Schin 960*4887Schin "[t:timeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " 961*4887Schin "poll returns immediately. If the value of timeout is -1, poll " 962*4887Schin "blocks until a requested event occurs or until the call is " 963*4887Schin "interrupted.]" 964*4887Schin "\n" 965*4887Schin "\nvar\n" 966*4887Schin "\n" 967*4887Schin "[+EXIT STATUS?]{" 968*4887Schin "[+0?Success.]" 969*4887Schin "[+>0?An error occurred.]" 970*4887Schin "}" 971*4887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" 972*4887Schin ; 973*4887Schin 974*4887Schin /* 975*4887Schin * |mystpcpy| - like |strcpy()| but returns the end of the buffer 976*4887Schin * 977*4887Schin * Copy string s2 to s1. s1 must be large enough. 978*4887Schin * return s1-1 (position of string terminator ('\0') in destnation buffer). 979*4887Schin */ 980*4887Schin static 981*4887Schin char *mystpcpy(char *s1, const char *s2) 982*4887Schin { 983*4887Schin while (*s1++ = *s2++) 984*4887Schin ; 985*4887Schin return (s1-1); 986*4887Schin } 987*4887Schin 988*4887Schin static 989*4887Schin Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) 990*4887Schin { 991*4887Schin char varnamebuff[PATH_MAX]; 992*4887Schin va_list ap; 993*4887Schin 994*4887Schin va_start(ap, namefmt); 995*4887Schin vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); 996*4887Schin va_end(ap); 997*4887Schin 998*4887Schin return nv_open(varnamebuff, dict, flags); 999*4887Schin } 1000*4887Schin 1001*4887Schin static 1002*4887Schin int poll_strtoevents(const char *str) 1003*4887Schin { 1004*4887Schin int events = 0; 1005*4887Schin 1006*4887Schin if (strstr(str, "POLLIN")) events |= POLLIN; 1007*4887Schin if (strstr(str, "POLLRDNORM")) events |= POLLRDNORM; 1008*4887Schin if (strstr(str, "POLLRDBAND")) events |= POLLRDBAND; 1009*4887Schin if (strstr(str, "POLLPRI")) events |= POLLPRI; 1010*4887Schin if (strstr(str, "POLLOUT")) events |= POLLOUT; 1011*4887Schin if (strstr(str, "POLLWRNORM")) events |= POLLWRNORM; 1012*4887Schin if (strstr(str, "POLLWRBAND")) events |= POLLWRBAND; 1013*4887Schin if (strstr(str, "POLLERR")) events |= POLLERR; 1014*4887Schin if (strstr(str, "POLLHUP")) events |= POLLHUP; 1015*4887Schin if (strstr(str, "POLLNVAL")) events |= POLLNVAL; 1016*4887Schin 1017*4887Schin return events; 1018*4887Schin } 1019*4887Schin 1020*4887Schin 1021*4887Schin static 1022*4887Schin void poll_eventstostr(char *s, int events) 1023*4887Schin { 1024*4887Schin *s='\0'; 1025*4887Schin if (!events) 1026*4887Schin return; 1027*4887Schin 1028*4887Schin if (events & POLLIN) s=mystpcpy(s, "POLLIN|"); 1029*4887Schin if (events & POLLRDNORM) s=mystpcpy(s, "POLLRDNORM|"); 1030*4887Schin if (events & POLLRDBAND) s=mystpcpy(s, "POLLRDBAND|"); 1031*4887Schin if (events & POLLPRI) s=mystpcpy(s, "POLLPRI|"); 1032*4887Schin if (events & POLLOUT) s=mystpcpy(s, "POLLOUT|"); 1033*4887Schin if (events & POLLWRNORM) s=mystpcpy(s, "POLLWRNORM|"); 1034*4887Schin if (events & POLLWRBAND) s=mystpcpy(s, "POLLWRBAND|"); 1035*4887Schin if (events & POLLERR) s=mystpcpy(s, "POLLERR|"); 1036*4887Schin if (events & POLLHUP) s=mystpcpy(s, "POLLHUP|"); 1037*4887Schin if (events & POLLNVAL) s=mystpcpy(s, "POLLNVAL|"); 1038*4887Schin 1039*4887Schin /* Remove trailling '|' */ 1040*4887Schin s--; 1041*4887Schin if(*s=='|') 1042*4887Schin *s='\0'; 1043*4887Schin } 1044*4887Schin 1045*4887Schin extern int b_poll(int argc, char *argv[], void *extra) 1046*4887Schin { 1047*4887Schin register Namval_t *np; 1048*4887Schin register int n; 1049*4887Schin Shell_t *shp = (Shell_t*)extra; 1050*4887Schin char *varname; 1051*4887Schin int fd; 1052*4887Schin /* |BPOLL_MAX| needs to be larger than |OPEN_MAX| to make sure we 1053*4887Schin * can listen to different sets of events per fd. 1054*4887Schin */ 1055*4887Schin #define BPOLL_MAX 512 1056*4887Schin struct pollfd pollfd[BPOLL_MAX]; 1057*4887Schin unsigned int numpollfd = 0; 1058*4887Schin int i; 1059*4887Schin char *s; 1060*4887Schin long timeout = -1; 1061*4887Schin char buff[256]; 1062*4887Schin 1063*4887Schin while (n = optget(argv, sh_optpoll)) switch (n) 1064*4887Schin { 1065*4887Schin case 't': 1066*4887Schin errno = 0; 1067*4887Schin timeout = strtol(opt_info.arg, (char **)NULL, 0); 1068*4887Schin if (errno != 0) 1069*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); 1070*4887Schin break; 1071*4887Schin case ':': 1072*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 1073*4887Schin break; 1074*4887Schin case '?': 1075*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 1076*4887Schin break; 1077*4887Schin } 1078*4887Schin argc -= opt_info.index; 1079*4887Schin argv += opt_info.index; 1080*4887Schin if(argc!=1) 1081*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 1082*4887Schin 1083*4887Schin varname = argv[0]; 1084*4887Schin 1085*4887Schin for(i=0 ; i < BPOLL_MAX ; i++) 1086*4887Schin { 1087*4887Schin np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); 1088*4887Schin if (!np) 1089*4887Schin break; 1090*4887Schin fd = (int)nv_getnum(np); 1091*4887Schin if (fd < 0 || fd > OPEN_MAX) 1092*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: invalid pollfd fd"); 1093*4887Schin nv_close(np); 1094*4887Schin pollfd[i].fd = fd; 1095*4887Schin 1096*4887Schin np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); 1097*4887Schin if (!s) 1098*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events"); 1099*4887Schin 1100*4887Schin s = nv_getval(np); 1101*4887Schin if (!s) 1102*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events value"); 1103*4887Schin pollfd[i].events = poll_strtoevents(s); 1104*4887Schin nv_close(np); 1105*4887Schin 1106*4887Schin pollfd[i].revents = 0; 1107*4887Schin 1108*4887Schin numpollfd++; 1109*4887Schin } 1110*4887Schin 1111*4887Schin if (i == BPOLL_MAX) 1112*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: cannot handle more than %d entries.", BPOLL_MAX); 1113*4887Schin 1114*4887Schin n = poll(pollfd, numpollfd, timeout); 1115*4887Schin /* FixMe: EGAIN and EINTR may require extra handling */ 1116*4887Schin if (n < 0) 1117*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: failure"); 1118*4887Schin 1119*4887Schin for(i=0 ; i < numpollfd ; i++) 1120*4887Schin { 1121*4887Schin np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL, "%s[%d].revents", varname, i); 1122*4887Schin if (!np) 1123*4887Schin errormsg(SH_DICT, ERROR_system(1), "poll: couldn't create pollfd %s[%d].revents", varname, i); 1124*4887Schin 1125*4887Schin poll_eventstostr(buff, pollfd[i].revents); 1126*4887Schin 1127*4887Schin nv_putval(np, buff, 0); 1128*4887Schin nv_close(np); 1129*4887Schin } 1130*4887Schin 1131*4887Schin return(0); 1132*4887Schin } 1133*4887Schin 1134*4887Schin static const char sh_optrewind[] = 1135*4887Schin "[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]" 1136*4887Schin "[-author?Roland Mainz <roland.mainz@nrubsig.org>]" 1137*4887Schin "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" 1138*4887Schin "[+NAME? rewind - reset file position indicator in a stream]" 1139*4887Schin "[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]" 1140*4887Schin "\n" 1141*4887Schin "\nfd\n" 1142*4887Schin "\n" 1143*4887Schin "[+EXIT STATUS?]{" 1144*4887Schin "[+0?Success.]" 1145*4887Schin "[+>0?An error occurred.]" 1146*4887Schin "}" 1147*4887Schin "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]" 1148*4887Schin ; 1149*4887Schin 1150*4887Schin 1151*4887Schin extern int b_rewind(int argc, char *argv[], void *extra) 1152*4887Schin { 1153*4887Schin Shell_t *shp = (Shell_t*)extra; 1154*4887Schin int fd = -1; 1155*4887Schin register int n; 1156*4887Schin while (n = optget(argv, sh_optrewind)) switch (n) 1157*4887Schin { 1158*4887Schin case ':': 1159*4887Schin errormsg(SH_DICT, 2, "%s", opt_info.arg); 1160*4887Schin break; 1161*4887Schin case '?': 1162*4887Schin errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); 1163*4887Schin break; 1164*4887Schin } 1165*4887Schin argc -= opt_info.index; 1166*4887Schin argv += opt_info.index; 1167*4887Schin if(argc!=1) 1168*4887Schin errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); 1169*4887Schin 1170*4887Schin errno = 0; 1171*4887Schin fd = strtol(argv[0], (char **)NULL, 0); 1172*4887Schin if (errno != 0 || fd < 0) 1173*4887Schin errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]); 1174*4887Schin 1175*4887Schin if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1) 1176*4887Schin errormsg(SH_DICT, ERROR_system(1), "seek error"); 1177*4887Schin 1178*4887Schin return(0); 1179*4887Schin } 1180*4887Schin 1181