1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2007-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 static const char id[] = "\n@(#)$Id: open (AT&T Research) 1998-07-07 $\0\n";
23 
24 #include	<shell.h>
25 #include	<option.h>
26 #include	<stk.h>
27 #include	<tm.h>
28 #ifndef SH_DICT
29 #   define SH_DICT     "libshell"
30 #endif
31 #ifndef array_elem
32 #  define array_elem(ap)	((ap)->nelem&0xffffff)
33 #endif
34 
35 
36 /*
37  * time formatting related
38 */
39 struct dctime
40 {
41 	Namfun_t	fun;
42 	Namval_t 	*format;
43 };
44 
get_time(Namval_t * np,Namfun_t * nfp)45 static char *get_time(Namval_t* np, Namfun_t* nfp)
46 {
47 	static char buff[256];
48 	struct dctime *dp = (struct dctime*)nfp;
49 	time_t t = nv_getn(np,nfp);
50 	char *format = nv_getval(dp->format);
51 	tmfmt(buff,sizeof(buff),format,(time_t*)0);
52 	return(buff);
53 }
54 
put_time(Namval_t * np,const char * val,int flag,Namfun_t * nfp)55 static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
56 {
57 	struct dctime *dp = (struct dctime*)nfp;
58 	char *last;
59 	if(val)
60 	{
61 		int32_t t;
62 		if(flag&NV_INTEGER)
63 		{
64 			if(flag&NV_LONG)
65 				t = *(Sfdouble_t*)val;
66 			else
67 				t = *(double*)val;
68 		}
69 		else
70 		{
71 			t = tmdate(val, &last, (time_t*)0);
72 			if(*last)
73 				errormsg(SH_DICT,ERROR_exit(1),"%s: invalid date/time string",val);
74 		}
75 		nv_putv(np,(char*)&t,NV_INTEGER,nfp);
76 	}
77 	else
78 	{
79 		nv_unset(dp->format);
80 		free((void*)dp->format);
81 		nv_putv(np,val,flag,nfp);
82 	}
83 }
84 
create_time(Namval_t * np,const char * name,int flags,Namfun_t * nfp)85 static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
86 {
87 	struct dctime *dp = (struct dctime*)nfp;
88 	if(strcmp(name,"format"))
89 		return((Namval_t*)0);
90 	return(dp->format);
91 }
92 
93 static const Namdisc_t timedisc =
94 {
95         sizeof(struct dctime),
96         put_time,
97         get_time,
98         0,
99         0,
100         create_time,
101 };
102 
103 
make_time(Namval_t * np)104 static Namval_t *make_time(Namval_t* np)
105 {
106 	int offset = stktell(stkstd);
107 	char *name = nv_name(np);
108 	struct dctime *dp = newof(NULL,struct dctime,1,0);
109 	if(!dp)
110 		return((Namval_t*)0);
111 	sfprintf(stkstd,"%s.format\0",name);
112 	sfputc(stkstd,0);
113 	dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
114 	dp->fun.disc = &timedisc;
115 	nv_stack(np,&dp->fun);
116 	return(np);
117 }
118 
119 /*
120  * mode formatting related
121 */
get_mode(Namval_t * np,Namfun_t * nfp)122 static char *get_mode(Namval_t* np, Namfun_t* nfp)
123 {
124 	mode_t mode = nv_getn(np,nfp);
125 	return(fmtperm(mode));
126 }
127 
put_mode(Namval_t * np,const char * val,int flag,Namfun_t * nfp)128 static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
129 {
130 	if(val)
131 	{
132 		int32_t mode;
133 		char *last;
134 		if(flag&NV_INTEGER)
135 		{
136 			if(flag&NV_LONG)
137 				mode = *(Sfdouble_t*)val;
138 			else
139 				mode = *(double*)val;
140 		}
141 		else
142 		{
143 			mode = strperm(val, &last,0);
144 			if(*last)
145 				errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val);
146 		}
147 		nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
148 	}
149 	else
150 		nv_putv(np,val,flag,nfp);
151 }
152 
153 static const Namdisc_t modedisc =
154 {
155 	0,
156         put_mode,
157         get_mode,
158 };
159 
make_mode(Namval_t * np)160 static Namval_t *make_mode(Namval_t* np)
161 {
162 	char *name = nv_name(np);
163 	Namfun_t *nfp = newof(NULL,Namfun_t,1,0);
164 	if(!nfp)
165 		return((Namval_t*)0);
166 	nfp->disc = &modedisc;
167 	nv_stack(np,nfp);
168 	return(np);
169 }
170 
171 /*
172  *  field related typese and functions
173  */
174 typedef struct _field_
175 {
176 	char		*name;		/* field name */
177 	int		flags;		/* flags */
178 	short		offset;		/* offset of field into data */
179 	short		size;		/* size of field */
180 	Namval_t	*(*make)(Namval_t*);	/* discipline constructor */
181 } Shfield_t;
182 
183 /*
184  * lookup field in field table
185  */
sh_findfield(Shfield_t * ftable,int nelem,const char * name)186 static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name)
187 {
188 	Shfield_t *fp = ftable;
189 	register int i,n;
190 	register const char *cp;
191 	for(cp=name; *cp; cp++)
192 	{
193 		if(*cp=='.')
194 			break;
195 	}
196 	n = cp-name;
197 	for(i=0; i < nelem; i++,fp++)
198 	{
199 		if(memcmp(fp->name,name,n)==0 && fp->name[n]==0)
200 			return(fp);
201 	}
202 	return(0);
203 }
204 
205 /*
206  * class types and functions
207  */
208 
209 typedef struct _class_
210 {
211 	int		nelem;		/* number of elements */
212 	int		dsize;		/* size for data structure */
213 	Shfield_t 	*fields;	/* field description table */
214 } Shclass_t;
215 
216 struct dcclass
217 {
218 	Namfun_t	fun;
219 	Shclass_t	sclass;
220 };
221 
sh_newnode(register Shfield_t * fp,Namval_t * np)222 static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np)
223 {
224 	char *val = np->nvalue + fp->offset;
225 	char *name = nv_name(np);
226 	register Namval_t *nq;
227 	int offset = stktell(stkstd);
228 	sfprintf(stkstd,"%s.%s\0",name,fp->name);
229 	sfputc(stkstd,0);
230 	nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD);
231 	if(fp->size<0)
232 		val = *(char**)val;
233 	nv_putval(nq,val,fp->flags|NV_NOFREE);
234 	if(fp->make)
235 		(*fp->make)(nq);
236 	return(nq);
237 }
238 
fieldcreate(Namval_t * np,const char * name,int flags,Namfun_t * nfp)239 static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp)
240 {
241 	struct dcclass *dcp = (struct dcclass*)nfp;
242 	Shclass_t *sp = &dcp->sclass;
243 	Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name);
244 	Namval_t *nq,**nodes = (Namval_t**)(dcp+1);
245 	int n = fp-sp->fields;
246 	int len =  strlen(fp->name);
247 	if(!(nq=nodes[n]))
248 	{
249 		nodes[n] = nq = sh_newnode(fp,np);
250 		nfp->last = "";
251 	}
252 	if(name[len]==0)
253 		return(nq);
254 	return(nq);
255 }
256 
genvalue(Sfio_t * out,Shclass_t * sp,int indent,Namval_t * npar)257 static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar)
258 {
259 	Shfield_t *fp = sp->fields;
260 	Namval_t *np, **nodes= (Namval_t**)(sp+1);
261 	register int i,isarray;
262 	if(out)
263 	{
264 		sfwrite(out,"(\n",2);
265 		indent++;
266 	}
267 	for(i=0; i < sp->nelem; i++,fp++)
268 	{
269 #if 0
270 		/* handle recursive case */
271 #endif
272 		if(!(np=nodes[i]) && out)
273 			np = sh_newnode(fp,npar);
274 		if(np)
275 		{
276 			isarray=0;
277 			if(nv_isattr(np,NV_ARRAY))
278 			{
279 				isarray=1;
280 				if(array_elem(nv_arrayptr(np))==0)
281 					isarray=2;
282 				else
283 					nv_putsub(np,(char*)0,ARRAY_SCAN);
284 			}
285 			sfnputc(out,'\t',indent);
286 			sfputr(out,fp->name,(isarray==2?'\n':'='));
287 			if(isarray)
288 			{
289 				if(isarray==2)
290 					continue;
291 				sfwrite(out,"(\n",2);
292 				sfnputc(out,'\t',++indent);
293 			}
294 			while(1)
295 			{
296 				char *fmtq;
297 				if(isarray)
298 				{
299 					sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np)));
300 					sfputc(out,'=');
301 				}
302 				if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq)))
303 					fmtq = "";
304 				sfputr(out,fmtq,'\n');
305 				if(!nv_nextsub(np))
306 					break;
307 				sfnputc(out,'\t',indent);
308 			}
309 			if(isarray)
310 			{
311 				sfnputc(out,'\t',--indent);
312 				sfwrite(out,")\n",2);
313 			}
314 		}
315 	}
316 	if(out)
317 	{
318 		if(indent>1)
319 			sfnputc(out,'\t',indent-1);
320 		sfputc(out,')');
321 	}
322 }
323 
walk_class(register Namval_t * np,int dlete,struct dcclass * dcp)324 static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp)
325 {
326 	static Sfio_t *out;
327 	Sfio_t *outfile;
328 	int savtop = stktell(stkstd);
329 	char *savptr =  stkfreeze(stkstd,0);
330 	if(dlete)
331 		outfile = 0;
332 	else if(!(outfile=out))
333                 outfile = out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
334 	else
335 		sfseek(outfile,0L,SEEK_SET);
336 	genvalue(outfile,&dcp->sclass,0,np);
337 	stkset(stkstd,savptr,savtop);
338 	if(!outfile)
339 		return((char*)0);
340 	sfputc(out,0);
341 	return((char*)out->_data);
342 }
343 
get_classval(Namval_t * np,Namfun_t * nfp)344 static char *get_classval(Namval_t* np, Namfun_t* nfp)
345 {
346 	return(walk_class(np,0,(struct dcclass *)nfp));
347 }
348 
put_classval(Namval_t * np,const char * val,int flag,Namfun_t * nfp)349 static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
350 {
351 	walk_class(np,1,(struct dcclass *)nfp);
352 	if(nfp = nv_stack(np,(Namfun_t*)0))
353 	{
354 		free((void*)nfp);
355 		if(np->nvalue && !nv_isattr(np,NV_NOFREE))
356 			free((void*)np->nvalue);
357 	}
358 	if(val)
359 		nv_putval(np,val,flag);
360 }
361 
362 static const Namdisc_t classdisc =
363 {
364         sizeof(struct dcclass),
365         put_classval,
366         get_classval,
367         0,
368         0,
369 	fieldcreate
370 };
371 
mkclass(Namval_t * np,Shclass_t * sp)372 static int mkclass(Namval_t *np, Shclass_t *sp)
373 {
374 	struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*));
375 	if(!tcp)
376 		return(0);
377 	memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*));
378 	tcp->fun.disc = &classdisc;
379 	tcp->sclass = *sp;
380 	np->nvalue = (char*)calloc(sp->dsize,1);
381 	nv_stack(np,&tcp->fun);
382 	return(1);
383 }
384 
385 /*
386  * ====================from here down is file class specific
387  */
388 static struct stat *Sp;
389 
390 struct filedata
391 {
392 	struct stat	statb;
393 	int		fd;
394 	char		*name;
395 };
396 
397 static Shfield_t filefield[] =
398 {
399 	{ "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time},
400 	{ "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time},
401 	{ "dev",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)},
402 	{ "fd",    NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), 		sizeof(int)},
403 	{ "gid",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)},
404 	{ "ino",   NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)},
405 	{ "mode",  NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode},
406 	{ "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time},
407 	{ "name",   NV_RDONLY, offsetof(struct filedata,name), 	-1 },
408 	{ "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)},
409 	{ "size",  NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)},
410 	{ "uid",   NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)}
411 };
412 
413 static Shclass_t Fileclass =
414 {
415 	sizeof(filefield)/sizeof(*filefield),
416 	sizeof(struct filedata),
417 	filefield
418 };
419 
420 
421 #define letterbit(bit)	(1<<((bit)-'a'))
422 
423 static const char sh_optopen[] =
424 "[-?\n@(#)$Id: open (AT&T Labs Research) 2007-03-11 $\n]"
425 "[-author?David Korn <dgk@research.att.com>]"
426 "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
427 "[+NAME? open - create a shell variable correspnding to a file]"
428 "[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding "
429 	"to the file given by the pathname \afile\a.  The elements of \avar\a "
430 	"are the names of elements in the \astat\a structure with the \bst_\b "
431 	"prefix removed.]"
432 "[+?If the \b-r\b and/or \b-w\b mode is specified, then \afile\a is opened and "
433 	"the variable \avar\a\b.fd\b is the file descriptor.]"
434 "[a:append?Open for append.]"
435 "[b:binary?Open in binary mode.]"
436 "[c:create?Open for create.]"
437 "[i:inherit?Open without the close-on-exec bit set.]"
438 "[r:read?Open with read access.]"
439 "[w:write?Open with write access.]"
440 "[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]"
441 "[x:exclusive?Open exclusive.]"
442 "\n"
443 "\nvar file\n"
444 "\n"
445 "[+EXIT STATUS?]{"
446         "[+0?Success.]"
447         "[+>0?An error occurred.]"
448 "}"
449 "[+SEE ALSO?\bstat\b(2)]"
450 ;
451 
452 
b_open(int argc,char * argv[],Shbltin_t * context)453 extern int b_open(int argc, char *argv[], Shbltin_t *context)
454 {
455 	register Namval_t *np;
456 	register int n,oflag=0;
457 	Shell_t *shp = context->shp;
458 	struct filedata *fdp;
459 	struct stat statb;
460 	mode_t mode = 0666;
461 	long flags = 0;
462 	int fd = -1;
463 	while (n = optget(argv, sh_optopen)) switch (n)
464 	{
465 	    case 'r':
466 	    case 'i':
467 	    case 'w':
468 		flags |= letterbit(n);
469 		break;
470 	    case 'b':
471 #ifdef O_BINARY
472 		oflag |= O_BINARY;
473 #endif
474 		break;
475 	    case 't':
476 #ifdef O_TEXT
477 		oflag |= O_TEXT;
478 #endif
479 		break;
480 	    case 'x':
481 		oflag |= O_EXCL;
482 		break;
483 	    case 'c':
484 		oflag |= O_CREAT;
485 		break;
486 	    case 'a':
487 		oflag |= O_APPEND;
488 		break;
489 	    case 'm':
490 		break;
491 	    case ':':
492 		errormsg(SH_DICT,2, "%s", opt_info.arg);
493 		break;
494 	    case '?':
495 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
496 		break;
497 	}
498 	argc -= opt_info.index;
499 	argv += opt_info.index;
500 	if(argc!=2)
501 		errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
502 	if(!(flags&(letterbit('r')|letterbit('w'))))
503 	{
504 		if(stat(argv[1],&statb)<0)
505 			errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]);
506 	}
507 	else
508 	{
509 		if(flags&letterbit('r'))
510 		{
511 			if(flags&letterbit('w'))
512 				oflag |= O_RDWR;
513 			else
514 				oflag |= O_RDONLY;
515 		}
516 		else if(flags&letterbit('w'))
517 			oflag |= O_WRONLY;
518 		fd = open(argv[1],oflag,mode);
519 		if(fd<0)
520 			errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]);
521 	}
522 	if(!(flags&letterbit('i')))
523 		fcntl(fd,F_SETFL,0);
524 	np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN);
525 	if(!nv_isnull(np))
526 		nv_unset(np);
527 	mkclass(np,&Fileclass);
528 	fdp = (struct filedata*)np->nvalue;
529 	if(!(flags&(letterbit('r')|letterbit('w'))))
530 		fdp->statb = statb;
531 	else
532 		fstat(fd,&fdp->statb);
533 	fdp->fd = fd;
534 	fdp->name = strdup(argv[1]);
535 	return(0);
536 }
537 
538 SHLIB(open)
539