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