1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1982-2007 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A
1N/A#include <shell.h>
1N/A#include <stdio.h>
1N/A#include <stdbool.h>
1N/A#include <option.h>
1N/A#include <stk.h>
1N/A#include <tm.h>
1N/A#include "name.h"
1N/A#undef nv_isnull
1N/A#ifndef SH_DICT
1N/A# define SH_DICT "libshell"
1N/A#endif
1N/A#include <poll.h>
1N/A
1N/A#define sh_contexttoshb(context) ((Shbltin_t*)(context))
1N/A#define sh_contexttoshell(context) ((context)?(sh_contexttoshb(context)->shp):(NULL))
1N/A
1N/A/*
1N/A * time formatting related
1N/A*/
1N/Astruct dctime
1N/A{
1N/A Namfun_t fun;
1N/A Namval_t *format;
1N/A char buff[256]; /* Must be large enougth for |tmfmt()| */
1N/A};
1N/A
1N/Astatic char *get_time(Namval_t* np, Namfun_t* nfp)
1N/A{
1N/A struct dctime *dp = (struct dctime*)nfp;
1N/A time_t t = nv_getn(np,nfp);
1N/A char *format = nv_getval(dp->format);
1N/A tmfmt(dp->buff,sizeof(dp->buff),format,(time_t*)0);
1N/A return(dp->buff);
1N/A}
1N/A
1N/Astatic void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1N/A{
1N/A struct dctime *dp = (struct dctime*)nfp;
1N/A char *last;
1N/A if(val)
1N/A {
1N/A int32_t t;
1N/A if(flag&NV_INTEGER)
1N/A {
1N/A if(flag&NV_LONG)
1N/A t = *(Sfdouble_t*)val;
1N/A else
1N/A t = *(double*)val;
1N/A }
1N/A else
1N/A {
1N/A t = tmdate(val, &last, (time_t*)0);
1N/A if(*last)
1N/A errormsg(SH_DICT, ERROR_exit(1),"%s: invalid date/time string", val);
1N/A }
1N/A nv_putv(np, (char*)&t,NV_INTEGER, nfp);
1N/A }
1N/A else
1N/A {
1N/A nv_unset(dp->format);
1N/A free((void*)dp->format);
1N/A nv_putv(np, val, flag, nfp);
1N/A }
1N/A}
1N/A
1N/Astatic Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
1N/A{
1N/A struct dctime *dp = (struct dctime*)nfp;
1N/A if(strcmp(name, "format"))
1N/A return((Namval_t*)0);
1N/A return(dp->format);
1N/A}
1N/A
1N/Astatic const Namdisc_t timedisc =
1N/A{
1N/A sizeof(struct dctime),
1N/A put_time,
1N/A get_time,
1N/A 0,
1N/A 0,
1N/A create_time,
1N/A};
1N/A
1N/A
1N/Astatic Namval_t *make_time(Namval_t* np)
1N/A{
1N/A int offset = stktell(stkstd);
1N/A char *name = nv_name(np);
1N/A struct dctime *dp = newof(NULL,struct dctime,1,0);
1N/A if(!dp)
1N/A return((Namval_t*)0);
1N/A sfprintf(stkstd,"%s.format\0",name);
1N/A sfputc(stkstd,0);
1N/A dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
1N/A dp->fun.disc = &timedisc;
1N/A nv_stack(np,&dp->fun);
1N/A return(np);
1N/A}
1N/A
1N/A/*
1N/A * mode formatting related
1N/A*/
1N/Astatic char *get_mode(Namval_t* np, Namfun_t* nfp)
1N/A{
1N/A mode_t mode = nv_getn(np,nfp);
1N/A return(fmtperm(mode));
1N/A}
1N/A
1N/Astatic void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1N/A{
1N/A if(val)
1N/A {
1N/A int32_t mode;
1N/A char *last;
1N/A if(flag&NV_INTEGER)
1N/A {
1N/A if(flag&NV_LONG)
1N/A mode = *(Sfdouble_t*)val;
1N/A else
1N/A mode = *(double*)val;
1N/A }
1N/A else
1N/A {
1N/A mode = strperm(val, &last,0);
1N/A if(*last)
1N/A errormsg(SH_DICT, ERROR_exit(1),"%s: invalid mode string", val);
1N/A }
1N/A nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
1N/A }
1N/A else
1N/A nv_putv(np,val,flag,nfp);
1N/A}
1N/A
1N/Astatic const Namdisc_t modedisc =
1N/A{
1N/A 0,
1N/A put_mode,
1N/A get_mode,
1N/A};
1N/A
1N/Astatic Namval_t *make_mode(Namval_t* np)
1N/A{
1N/A char *name = nv_name(np);
1N/A Namfun_t *nfp = newof(NULL,Namfun_t,1,0);
1N/A if(!nfp)
1N/A return((Namval_t*)0);
1N/A nfp->disc = &modedisc;
1N/A nv_stack(np,nfp);
1N/A return(np);
1N/A}
1N/A
1N/A/*
1N/A * field related typese and functions
1N/A */
1N/Atypedef struct _field_
1N/A{
1N/A char *name; /* field name */
1N/A int flags; /* flags */
1N/A short offset; /* offset of field into data */
1N/A short size; /* size of field */
1N/A Namval_t *(*make)(Namval_t*); /* discipline constructor */
1N/A} Shfield_t;
1N/A
1N/A/*
1N/A * lookup field in field table
1N/A */
1N/Astatic Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name)
1N/A{
1N/A Shfield_t *fp = ftable;
1N/A register int i,n;
1N/A register const char *cp;
1N/A for(cp=name; *cp; cp++)
1N/A {
1N/A if(*cp=='.')
1N/A break;
1N/A }
1N/A n = cp-name;
1N/A for(i=0; i < nelem; i++,fp++)
1N/A {
1N/A if(memcmp(fp->name,name,n)==0 && fp->name[n]==0)
1N/A return(fp);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/A/*
1N/A * class types and functions
1N/A */
1N/A
1N/Atypedef struct _class_
1N/A{
1N/A int nelem; /* number of elements */
1N/A int dsize; /* size for data structure */
1N/A Shfield_t *fields; /* field description table */
1N/A} Shclass_t;
1N/A
1N/Astruct dcclass
1N/A{
1N/A Namfun_t fun;
1N/A Shclass_t sclass;
1N/A};
1N/A
1N/Astatic Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np)
1N/A{
1N/A char *val = np->nvalue + fp->offset;
1N/A char *name = nv_name(np);
1N/A register Namval_t *nq;
1N/A int offset = stktell(stkstd);
1N/A sfprintf(stkstd,"%s.%s\0",name,fp->name);
1N/A sfputc(stkstd,0);
1N/A nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
1N/A if(fp->size<0)
1N/A val = *(char**)val;
1N/A nv_putval(nq,val,fp->flags|NV_NOFREE);
1N/A if(fp->make)
1N/A (*fp->make)(nq);
1N/A return(nq);
1N/A}
1N/A
1N/Astatic Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
1N/A{
1N/A struct dcclass *dcp = (struct dcclass*)nfp;
1N/A Shclass_t *sp = &dcp->sclass;
1N/A Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name);
1N/A Namval_t *nq,**nodes = (Namval_t**)(dcp+1);
1N/A int n = fp-sp->fields;
1N/A int len = strlen(fp->name);
1N/A void *data = (void*)np->nvalue;
1N/A if(!(nq=nodes[n]))
1N/A {
1N/A nodes[n] = nq = sh_newnode(fp,np);
1N/A nfp->last = "";
1N/A }
1N/A if(name[len]==0)
1N/A return(nq);
1N/A return(nq);
1N/A}
1N/A
1N/Astatic void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar)
1N/A{
1N/A Shfield_t *fp = sp->fields;
1N/A Namval_t *np, **nodes= (Namval_t**)(sp+1);
1N/A register int i,isarray;
1N/A if(out)
1N/A {
1N/A sfwrite(out,"(\n",2);
1N/A indent++;
1N/A }
1N/A for(i=0; i < sp->nelem; i++,fp++)
1N/A {
1N/A#if 0
1N/A /* handle recursive case */
1N/A#endif
1N/A if(!(np=nodes[i]) && out)
1N/A np = sh_newnode(fp,npar);
1N/A if(np)
1N/A {
1N/A isarray=0;
1N/A if(nv_isattr(np,NV_ARRAY))
1N/A {
1N/A isarray=1;
1N/A if(array_elem(nv_arrayptr(np))==0)
1N/A isarray=2;
1N/A else
1N/A nv_putsub(np,(char*)0,ARRAY_SCAN);
1N/A }
1N/A sfnputc(out,'\t',indent);
1N/A sfputr(out,fp->name,(isarray==2?'\n':'='));
1N/A if(isarray)
1N/A {
1N/A if(isarray==2)
1N/A continue;
1N/A sfwrite(out,"(\n",2);
1N/A sfnputc(out,'\t',++indent);
1N/A }
1N/A while(1)
1N/A {
1N/A char *fmtq;
1N/A if(isarray)
1N/A {
1N/A sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np)));
1N/A sfputc(out,'=');
1N/A }
1N/A if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq)))
1N/A fmtq = "";
1N/A sfputr(out,fmtq,'\n');
1N/A if(!nv_nextsub(np))
1N/A break;
1N/A sfnputc(out,'\t',indent);
1N/A }
1N/A if(isarray)
1N/A {
1N/A sfnputc(out,'\t',--indent);
1N/A sfwrite(out,")\n",2);
1N/A }
1N/A }
1N/A }
1N/A if(out)
1N/A {
1N/A if(indent>1)
1N/A sfnputc(out,'\t',indent-1);
1N/A sfputc(out,')');
1N/A }
1N/A}
1N/A
1N/Astatic char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp)
1N/A{
1N/A static Sfio_t *out;
1N/A Sfio_t *outfile;
1N/A int savtop = stktell(stkstd);
1N/A char *savptr = stkfreeze(stkstd,0);
1N/A if(dlete)
1N/A outfile = 0;
1N/A else if(!(outfile=out))
1N/A outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1N/A else
1N/A sfseek(outfile,0L,SEEK_SET);
1N/A genvalue(outfile,&dcp->sclass,0,np);
1N/A stkset(stkstd,savptr,savtop);
1N/A if(!outfile)
1N/A return((char*)0);
1N/A sfputc(out,0);
1N/A return((char*)out->_data);
1N/A}
1N/A
1N/Astatic char *get_classval(Namval_t* np, Namfun_t* nfp)
1N/A{
1N/A return(walk_class(np,0,(struct dcclass *)nfp));
1N/A}
1N/A
1N/Astatic void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1N/A{
1N/A walk_class(np,1,(struct dcclass *)nfp);
1N/A if(nfp = nv_stack(np,(Namfun_t*)0))
1N/A {
1N/A free((void*)nfp);
1N/A if(np->nvalue && !nv_isattr(np,NV_NOFREE))
1N/A free((void*)np->nvalue);
1N/A }
1N/A if(val)
1N/A nv_putval(np,val,flag);
1N/A}
1N/A
1N/Astatic const Namdisc_t classdisc =
1N/A{
1N/A sizeof(struct dcclass),
1N/A put_classval,
1N/A get_classval,
1N/A 0,
1N/A 0,
1N/A fieldcreate
1N/A};
1N/A
1N/Astatic int mkclass(Namval_t *np, Shclass_t *sp)
1N/A{
1N/A struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*));
1N/A if(!tcp)
1N/A return(0);
1N/A memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*));
1N/A tcp->fun.disc = &classdisc;
1N/A tcp->sclass = *sp;
1N/A np->nvalue = (char*)calloc(sp->dsize,1);
1N/A nv_stack(np,&tcp->fun);
1N/A return(1);
1N/A}
1N/A
1N/A/*
1N/A * ====================from here down is file class specific
1N/A */
1N/Astatic struct stat *Sp;
1N/A
1N/Astruct filedata
1N/A{
1N/A struct stat statb;
1N/A int fd;
1N/A char *name;
1N/A};
1N/A
1N/Astatic Shfield_t filefield[] =
1N/A{
1N/A { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time},
1N/A { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time},
1N/A { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)},
1N/A { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)},
1N/A { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)},
1N/A { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)},
1N/A { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode},
1N/A { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time},
1N/A { "name", NV_RDONLY, offsetof(struct filedata,name), -1 },
1N/A { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)},
1N/A { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)},
1N/A { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)}
1N/A};
1N/A
1N/Astatic Shclass_t Fileclass =
1N/A{
1N/A sizeof(filefield)/sizeof(*filefield),
1N/A sizeof(struct filedata),
1N/A filefield
1N/A};
1N/A
1N/A
1N/A#define letterbit(bit) (1<<((bit)-'a'))
1N/A
1N/Astatic const char sh_optopen[] =
1N/A"[-?\n@(#)$Id: open (AT&T Labs Research) 2007-05-07 $\n]"
1N/A"[-author?David Korn <dgk@research.att.com>]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? open - create a shell variable correspnding to a file]"
1N/A"[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding "
1N/A "to the file given by the pathname \afile\a. The elements of \avar\a "
1N/A "are the names of elements in the \astat\a structure with the \bst_\b "
1N/A "prefix removed.]"
1N/A"[+?\afile\a is opened (based on \b-r\b and/or \b-w\b) and the variable "
1N/A "\avar\a\b.fd\b is the file descriptor.]"
1N/A"[a:append?Open for append.]"
1N/A"[b:binary?Open in binary mode"
1N/A#ifndef O_BINARY
1N/A " (not supported/ignored on this platform)"
1N/A#endif
1N/A ".]"
1N/A"[t:text?Open in text mode"
1N/A#ifndef O_TEXT
1N/A " (not supported/ignored on this platform)"
1N/A#endif
1N/A ".]"
1N/A"[c:create?Open for create.]"
1N/A"[i:inherit?Open without the close-on-exec bit set.]"
1N/A"[I:noinherit?Open with the close-on-exec bit set.]"
1N/A"[r:read?Open with read access.]"
1N/A"[w:write?Open with write access.]"
1N/A"[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]"
1N/A"[x:exclusive?Open exclusive.]"
1N/A
1N/A"[N:nofollow?If the path names a symbolic link, open fails with ELOOP "
1N/A#ifndef O_NOFOLLOW
1N/A " (not supported/ignored on this platform)"
1N/A#endif
1N/A ".]"
1N/A"[S:sync?Write I/O operations on the file descriptor complete as "
1N/A "defined by synchronized I/O file integrity completion"
1N/A#ifndef O_SYNC
1N/A " (not supported/ignored on this platform)"
1N/A#endif
1N/A ".]"
1N/A"[T:trunc?If the file exists and is a regular file, and the file "
1N/A "is successfully opened read/write or write-only, its length is "
1N/A "truncated to 0 and the mode and owner are unchanged. It "
1N/A "has no effect on FIFO special files or terminal device "
1N/A "files. Its effect on other file types is "
1N/A "implementation-dependent. The result of using -T "
1N/A "with read-only files is undefined"
1N/A#ifndef O_TRUNC
1N/A " (not supported/ignored on this platform)"
1N/A#endif
1N/A ".]"
1N/A"\n"
1N/A"\nvar file\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bpoll\b(1),\bstat\b(2)]"
1N/A;
1N/A
1N/A
1N/Aextern int b_open(int argc, char *argv[], void *extra)
1N/A{
1N/A register Namval_t *np;
1N/A register int n,oflag=0;
1N/A Shell_t *shp = sh_contexttoshell(extra);
1N/A struct filedata *fdp;
1N/A mode_t mode = 0666;
1N/A long flags = 0;
1N/A int fd = -1;
1N/A char *arg;
1N/A
1N/A while (n = optget(argv, sh_optopen)) switch (n)
1N/A {
1N/A case 'r':
1N/A case 'w':
1N/A case 'i':
1N/A flags |= letterbit(n);
1N/A break;
1N/A case 'I':
1N/A flags &= ~(letterbit('i'));
1N/A break;
1N/A case 'b':
1N/A#ifdef O_BINARY
1N/A oflag |= O_BINARY;
1N/A#endif
1N/A break;
1N/A case 't':
1N/A#ifdef O_TEXT
1N/A oflag |= O_TEXT;
1N/A#endif
1N/A break;
1N/A case 'N':
1N/A#ifdef O_NOFOLLOW
1N/A oflag |= O_NOFOLLOW;
1N/A#endif
1N/A break;
1N/A case 'T':
1N/A#ifdef O_TRUNC
1N/A oflag |= O_TRUNC;
1N/A#endif
1N/A break;
1N/A case 'x':
1N/A oflag |= O_EXCL;
1N/A break;
1N/A case 'c':
1N/A oflag |= O_CREAT;
1N/A break;
1N/A case 'a':
1N/A oflag |= O_APPEND;
1N/A break;
1N/A case 'S':
1N/A#ifdef O_SYNC
1N/A oflag |= O_SYNC;
1N/A#endif
1N/A break;
1N/A case 'm':
1N/A mode = strperm(arg = opt_info.arg, &opt_info.arg, mode);
1N/A if (*opt_info.arg)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: invalid mode", arg);
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=2 || !(flags&(letterbit('r')|letterbit('w'))))
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A if(flags&letterbit('r'))
1N/A {
1N/A if(flags&letterbit('w'))
1N/A oflag |= O_RDWR;
1N/A else
1N/A oflag |= O_RDONLY;
1N/A }
1N/A else if(flags&letterbit('w'))
1N/A oflag |= O_WRONLY;
1N/A
1N/A fd = sh_open(argv[1], oflag, mode);
1N/A if(fd<0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: open failed", argv[1]);
1N/A
1N/A if(!(flags&letterbit('i')))
1N/A fcntl(fd, F_SETFL, 0);
1N/A
1N/A np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
1N/A if(!nv_isnull(np))
1N/A nv_unset(np);
1N/A mkclass(np, &Fileclass);
1N/A fdp = (struct filedata*)np->nvalue;
1N/A fstat(fd, &fdp->statb);
1N/A fdp->fd = fd;
1N/A fdp->name = strdup(argv[1]);
1N/A return(0);
1N/A}
1N/A
1N/Astatic const char sh_optclose[] =
1N/A"[-?\n@(#)$Id: close (AT&T Labs Research) 2007-04-21 $\n]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? close - close a file descriptor]"
1N/A"[+DESCRIPTION?\bclose\b closes the file descriptor specified by fd.]"
1N/A"\n"
1N/A"\nfd\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\bopen\b(1),\bdup\b(1),\btmpfile\b(1),\bpoll\b(1),\bstat\b(1)]"
1N/A;
1N/A
1N/Aextern int b_close(int argc, char *argv[], void *extra)
1N/A{
1N/A register int n=0;
1N/A int fd = -1;
1N/A
1N/A while (n = optget(argv, sh_optclose)) switch (n)
1N/A {
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=1)
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A errno = 0;
1N/A fd = strtol(argv[0], (char **)NULL, 0);
1N/A if (errno != 0 || fd < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: invalid descriptor", argv[0]);
1N/A
1N/A n = sh_close(fd);
1N/A
1N/A if (n < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: close error", argv[0]);
1N/A
1N/A return(n==0?0:1);
1N/A}
1N/A
1N/A
1N/Astatic const char sh_opttmpfile[] =
1N/A"[-?\n@(#)$Id: tmpfile (AT&T Labs Research) 2007-05-07 $\n]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? tmpfile - create a shell variable correspnding to a temporary file]"
1N/A"[+DESCRIPTION?\btmpfile\b creates the compound variable \avar\a correspinding "
1N/A "to a temporary file. The elements of \avar\a "
1N/A "are the names of elements in the \astat\a structure with the \bst_\b "
1N/A "prefix removed.]"
1N/A"[i:inherit?Open without the close-on-exec bit set.]"
1N/A"[I:noinherit?Open with the close-on-exec bit set.]"
1N/A"\n"
1N/A"\nvar\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\bopen\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
1N/A;
1N/A
1N/A
1N/Aextern int b_tmpfile(int argc, char *argv[], void *extra)
1N/A{
1N/A register Namval_t *np;
1N/A register int n;
1N/A Shell_t *shp = sh_contexttoshell(extra);
1N/A struct filedata *fdp;
1N/A bool inherit = false;
1N/A FILE *file = NULL;
1N/A int ffd, fd = -1;
1N/A while (n = optget(argv, sh_opttmpfile)) switch (n)
1N/A {
1N/A case 'i':
1N/A inherit = true;
1N/A break;
1N/A case 'I':
1N/A inherit = false;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=1)
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A file = tmpfile();
1N/A if(!file)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
1N/A ffd = fileno(file);
1N/A fd = sh_dup(ffd);
1N/A if(fd<0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]);
1N/A fclose(file);
1N/A
1N/A if(!inherit)
1N/A fcntl(fd, F_SETFL, 0);
1N/A
1N/A np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
1N/A if(!nv_isnull(np))
1N/A nv_unset(np);
1N/A mkclass(np,&Fileclass);
1N/A fdp = (struct filedata*)np->nvalue;
1N/A
1N/A fstat(fd, &fdp->statb);
1N/A fdp->fd = fd;
1N/A fdp->name = NULL;
1N/A return(0);
1N/A}
1N/A
1N/Astatic const char sh_optdup[] =
1N/A"[-?\n@(#)$Id: dup (AT&T Labs Research) 2007-05-07 $\n]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? dup - duplicate an open file descriptor]"
1N/A"[+DESCRIPTION?The \bdup\b commands returns a new file descriptor having the "
1N/A "following in common with the original open file descriptor "
1N/A "fd: same open file (or pipe), same file pointer (that is, both file descriptors "
1N/A "share one file pointer) same access mode (read, write or read/write). "
1N/A "The file descriptor returned is the lowest one available.]"
1N/A"[i:inherit?Open without the close-on-exec bit set.]"
1N/A"[I:noinherit?Open with the close-on-exec bit set.]"
1N/A"\n"
1N/A"\nvar fd\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(1)]"
1N/A;
1N/A
1N/A
1N/Aextern int b_dup(int argc, char *argv[], void *extra)
1N/A{
1N/A register Namval_t *np;
1N/A register int n;
1N/A Shell_t *shp = sh_contexttoshell(extra);
1N/A struct filedata *fdp;
1N/A bool inherit = false;
1N/A int ffd, fd = -1;
1N/A while (n = optget(argv, sh_optdup)) switch (n)
1N/A {
1N/A case 'i':
1N/A inherit = true;
1N/A break;
1N/A case 'I':
1N/A inherit = false;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=2)
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A errno = 0;
1N/A ffd = strtol(argv[1], (char **)NULL, 0);
1N/A if (errno != 0 || ffd < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[1]);
1N/A
1N/A fd = sh_dup(ffd);
1N/A if(fd<0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: dup failed", argv[1]);
1N/A
1N/A if(!inherit)
1N/A fcntl(fd,F_SETFL,0);
1N/A
1N/A np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
1N/A if(!nv_isnull(np))
1N/A nv_unset(np);
1N/A mkclass(np, &Fileclass);
1N/A fdp = (struct filedata*)np->nvalue;
1N/A
1N/A fstat(fd, &fdp->statb);
1N/A fdp->fd = fd;
1N/A fdp->name = NULL;
1N/A return(0);
1N/A}
1N/A
1N/Astatic const char sh_optstat[] =
1N/A"[-?\n@(#)$Id: stat (AT&T Labs Research) 2007-05-07 $\n]"
1N/A"[-author?David Korn <dgk@research.att.com>]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? stat - get file status]"
1N/A"[+DESCRIPTION?\bstat\b creates the compound variable \avar\a correspinding "
1N/A "to the file given by the pathname \afile\a. The elements of \avar\a "
1N/A "are the names of elements in the \astat\a structure with the \bst_\b "
1N/A "prefix removed.]"
1N/A"[l:lstat?If the the named file is a symbolic link returns information about "
1N/A "the link itself.]"
1N/A"\n"
1N/A"\nvar file\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(2),\blstat\b(2)]"
1N/A;
1N/A
1N/A
1N/Aextern int b_stat(int argc, char *argv[], void *extra)
1N/A{
1N/A register Namval_t *np;
1N/A register int n;
1N/A Shell_t *shp = sh_contexttoshell(extra);
1N/A struct filedata *fdp;
1N/A long flags = 0;
1N/A struct stat statb;
1N/A while (n = optget(argv, sh_optstat)) switch (n)
1N/A {
1N/A case 'l':
1N/A flags |= letterbit(n);
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=2)
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A if(flags&letterbit('l'))
1N/A {
1N/A if(lstat(argv[1], &statb) < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
1N/A }
1N/A else
1N/A {
1N/A if(stat(argv[1], &statb) < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]);
1N/A
1N/A }
1N/A
1N/A np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
1N/A if(!nv_isnull(np))
1N/A nv_unset(np);
1N/A mkclass(np,&Fileclass);
1N/A fdp = (struct filedata*)np->nvalue;
1N/A fdp->statb = statb;
1N/A fdp->fd = -1;
1N/A fdp->name = strdup(argv[1]);
1N/A return(0);
1N/A}
1N/A
1N/A
1N/Astatic const char sh_optrewind[] =
1N/A"[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]"
1N/A"[-author?Roland Mainz <roland.mainz@nrubsig.org>]"
1N/A"[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
1N/A"[+NAME? rewind - reset file position indicator in a stream]"
1N/A"[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]"
1N/A"\n"
1N/A"\nfd\n"
1N/A"\n"
1N/A"[+EXIT STATUS?]{"
1N/A "[+0?Success.]"
1N/A "[+>0?An error occurred.]"
1N/A"}"
1N/A"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]"
1N/A;
1N/A
1N/A
1N/Aextern int b_rewind(int argc, char *argv[], void *extra)
1N/A{
1N/A Shell_t *shp = sh_contexttoshell(extra);
1N/A int fd = -1;
1N/A register int n;
1N/A while (n = optget(argv, sh_optrewind)) switch (n)
1N/A {
1N/A case ':':
1N/A errormsg(SH_DICT, 2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(argc!=1)
1N/A errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0));
1N/A
1N/A errno = 0;
1N/A fd = strtol(argv[0], (char **)NULL, 0);
1N/A if (errno != 0 || fd < 0)
1N/A errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]);
1N/A
1N/A if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1)
1N/A errormsg(SH_DICT, ERROR_system(1), "seek error");
1N/A
1N/A return(0);
1N/A}