posixmodule.c revision 85e3b01f3b2c4cf8b217b5238d1ee4e9269969d0
1/***********************************************************
2Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
3Netherlands.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* POSIX module implementation */
26
27#ifdef AMOEBA
28#define NO_LSTAT
29#define SYSV
30#endif
31
32#ifdef MSDOS
33#define NO_LSTAT
34#endif
35
36#include <signal.h>
37#include <string.h>
38#include <setjmp.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41
42#ifdef SYSV
43
44#define UTIME_STRUCT
45#include <dirent.h>
46#define direct dirent
47#ifdef i386
48#define mode_t int
49#endif
50
51#else /* !SYSV */
52
53#ifndef MSDOS
54#include <sys/dir.h>
55#endif
56
57#endif /* !SYSV */
58
59#include "allobjects.h"
60#include "modsupport.h"
61
62extern char *strerror PROTO((int));
63
64
65/* Return a dictionary corresponding to the POSIX environment table */
66
67extern char **environ;
68
69static object *
70convertenviron()
71{
72	object *d;
73	char **e;
74	d = newdictobject();
75	if (d == NULL)
76		return NULL;
77	if (environ == NULL)
78		return d;
79	/* XXX This part ignores errors */
80	for (e = environ; *e != NULL; e++) {
81		object *v;
82		char *p = strchr(*e, '=');
83		if (p == NULL)
84			continue;
85		v = newstringobject(p+1);
86		if (v == NULL)
87			continue;
88		*p = '\0';
89		(void) dictinsert(d, *e, v);
90		*p = '=';
91		DECREF(v);
92	}
93	return d;
94}
95
96
97static object *PosixError; /* Exception posix.error */
98
99/* Set a POSIX-specific error from errno, and return NULL */
100
101static object *
102posix_error()
103{
104	return err_errno(PosixError);
105}
106
107
108/* POSIX generic methods */
109
110static object *
111posix_1str(args, func)
112	object *args;
113	int (*func) FPROTO((const char *));
114{
115	object *path1;
116	if (!getstrarg(args, &path1))
117		return NULL;
118	if ((*func)(getstringvalue(path1)) < 0)
119		return posix_error();
120	INCREF(None);
121	return None;
122}
123
124static object *
125posix_2str(args, func)
126	object *args;
127	int (*func) FPROTO((const char *, const char *));
128{
129	object *path1, *path2;
130	if (!getstrstrarg(args, &path1, &path2))
131		return NULL;
132	if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0)
133		return posix_error();
134	INCREF(None);
135	return None;
136}
137
138static object *
139posix_strint(args, func)
140	object *args;
141	int (*func) FPROTO((const char *, int));
142{
143	object *path1;
144	int i;
145	if (!getstrintarg(args, &path1, &i))
146		return NULL;
147	if ((*func)(getstringvalue(path1), i) < 0)
148		return posix_error();
149	INCREF(None);
150	return None;
151}
152
153static object *
154posix_do_stat(self, args, statfunc)
155	object *self;
156	object *args;
157	int (*statfunc) FPROTO((const char *, struct stat *));
158{
159	struct stat st;
160	object *path;
161	object *v;
162	if (!getstrarg(args, &path))
163		return NULL;
164	if ((*statfunc)(getstringvalue(path), &st) != 0)
165		return posix_error();
166	v = newtupleobject(10);
167	if (v == NULL)
168		return NULL;
169#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member))
170	SET(0, st_mode);
171	SET(1, st_ino);
172	SET(2, st_dev);
173	SET(3, st_nlink);
174	SET(4, st_uid);
175	SET(5, st_gid);
176	SET(6, st_size);
177	SET(7, st_atime);
178	SET(8, st_mtime);
179	SET(9, st_ctime);
180#undef SET
181	if (err_occurred()) {
182		DECREF(v);
183		return NULL;
184	}
185	return v;
186}
187
188
189/* POSIX methods */
190
191static object *
192posix_chdir(self, args)
193	object *self;
194	object *args;
195{
196	extern int chdir PROTO((const char *));
197	return posix_1str(args, chdir);
198}
199
200static object *
201posix_chmod(self, args)
202	object *self;
203	object *args;
204{
205	extern int chmod PROTO((const char *, mode_t));
206	return posix_strint(args, chmod);
207}
208
209static object *
210posix_getcwd(self, args)
211	object *self;
212	object *args;
213{
214	char buf[1026];
215	extern char *getcwd PROTO((char *, int));
216	if (!getnoarg(args))
217		return NULL;
218	if (getcwd(buf, sizeof buf) == NULL)
219		return posix_error();
220	return newstringobject(buf);
221}
222
223#ifndef MSDOS
224static object *
225posix_link(self, args)
226	object *self;
227	object *args;
228{
229	extern int link PROTO((const char *, const char *));
230	return posix_2str(args, link);
231}
232#endif /* !MSDOS */
233
234static object *
235posix_listdir(self, args)
236	object *self;
237	object *args;
238{
239	object *name, *d, *v;
240
241#ifdef MSDOS
242	struct ffblk ep;
243	int rv;
244	if (!getstrarg(args, &name))
245		return NULL;
246
247	if (findfirst((char *) getstringvalue(name), &ep, 0) == -1)
248		return posix_error();
249	if ((d = newlistobject(0)) == NULL)
250		return NULL;
251	do {
252		v = newstringobject(ep.ff_name);
253		if (v == NULL) {
254			DECREF(d);
255			d = NULL;
256			break;
257		}
258		if (addlistitem(d, v) != 0) {
259			DECREF(v);
260			DECREF(d);
261			d = NULL;
262			break;
263		}
264		DECREF(v);
265	} while ((rv = findnext(&ep)) == 0);
266#else /* !MSDOS */
267	DIR *dirp;
268	struct direct *ep;
269	if (!getstrarg(args, &name))
270		return NULL;
271	if ((dirp = opendir(getstringvalue(name))) == NULL)
272		return posix_error();
273	if ((d = newlistobject(0)) == NULL) {
274		closedir(dirp);
275		return NULL;
276	}
277	while ((ep = readdir(dirp)) != NULL) {
278		v = newstringobject(ep->d_name);
279		if (v == NULL) {
280			DECREF(d);
281			d = NULL;
282			break;
283		}
284		if (addlistitem(d, v) != 0) {
285			DECREF(v);
286			DECREF(d);
287			d = NULL;
288			break;
289		}
290		DECREF(v);
291	}
292	closedir(dirp);
293#endif /* !MSDOS */
294
295	return d;
296}
297
298static object *
299posix_mkdir(self, args)
300	object *self;
301	object *args;
302{
303	extern int mkdir PROTO((const char *, mode_t));
304	return posix_strint(args, mkdir);
305}
306
307#ifdef i386
308int
309rename(from, to)
310	char *from;
311	char *to;
312{
313	int status;
314	/* XXX Shouldn't this unlink the destination first? */
315	status = link(from, to);
316	if (status != 0)
317		return status;
318	return unlink(from);
319}
320#endif /* i386 */
321
322static object *
323posix_rename(self, args)
324	object *self;
325	object *args;
326{
327	extern int rename PROTO((const char *, const char *));
328	return posix_2str(args, rename);
329}
330
331static object *
332posix_rmdir(self, args)
333	object *self;
334	object *args;
335{
336	extern int rmdir PROTO((const char *));
337	return posix_1str(args, rmdir);
338}
339
340static object *
341posix_stat(self, args)
342	object *self;
343	object *args;
344{
345	extern int stat PROTO((const char *, struct stat *));
346	return posix_do_stat(self, args, stat);
347}
348
349static object *
350posix_system(self, args)
351	object *self;
352	object *args;
353{
354	object *command;
355	int sts;
356	if (!getstrarg(args, &command))
357		return NULL;
358	sts = system(getstringvalue(command));
359	return newintobject((long)sts);
360}
361
362#ifndef MSDOS
363static object *
364posix_umask(self, args)
365	object *self;
366	object *args;
367{
368	int i;
369	if (!getintarg(args, &i))
370		return NULL;
371	i = umask(i);
372	if (i < 0)
373		return posix_error();
374	return newintobject((long)i);
375}
376#endif /* !MSDOS */
377
378static object *
379posix_unlink(self, args)
380	object *self;
381	object *args;
382{
383	extern int unlink PROTO((const char *));
384	return posix_1str(args, unlink);
385}
386
387#ifdef UTIME_STRUCT
388#include <utime.h>
389#endif
390
391static object *
392posix_utime(self, args)
393	object *self;
394	object *args;
395{
396	object *path;
397
398#ifdef UTIME_STRUCT
399	struct utimbuf buf;
400#define ATIME buf.actime
401#define MTIME buf.modtime
402#define UTIME_ARG &buf
403
404#else
405	time_t buf[2];
406#define ATIME buf[0]
407#define MTIME buf[1]
408#define UTIME_ARG buf
409#endif
410
411	if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
412		err_badarg();
413		return NULL;
414	}
415	if (!getstrarg(gettupleitem(args, 0), &path) ||
416	    !getlonglongargs(gettupleitem(args, 1), &ATIME, &MTIME))
417		return NULL;
418	if (utime(getstringvalue(path), UTIME_ARG) < 0)
419		return posix_error();
420	INCREF(None);
421	return None;
422#undef UTIME_ARG
423#undef ATIME
424#undef MTIME
425}
426
427
428#ifndef MSDOS
429
430/* Process Primitives */
431
432static object *
433posix__exit(self, args)
434	object *self;
435	object *args;
436{
437	int sts;
438	if (!getintarg(args, &sts))
439		return NULL;
440	_exit(sts);
441	/* NOTREACHED */
442}
443
444/* XXX To do: exece, execp */
445
446static object *
447posix_exec(self, args)
448	object *self;
449	object *args;
450{
451	object *path, *argv;
452	char **argvlist;
453	int i, argc;
454	object *(*getitem) PROTO((object *, int));
455
456	/* exec has two arguments: (path, argv), where
457	   argv is a list or tuple of strings. */
458
459	if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
460 badarg:
461		err_badarg();
462		return NULL;
463	}
464	if (!getstrarg(gettupleitem(args, 0), &path))
465		return NULL;
466	argv = gettupleitem(args, 1);
467	if (argv == NULL)
468		goto badarg;
469	if (is_listobject(argv)) {
470		argc = getlistsize(argv);
471		getitem = getlistitem;
472	}
473	else if (is_tupleobject(argv)) {
474		argc = gettuplesize(argv);
475		getitem = gettupleitem;
476	}
477	else
478		goto badarg;
479
480	argvlist = NEW(char *, argc+1);
481	if (argvlist == NULL)
482		return NULL;
483	for (i = 0; i < argc; i++) {
484		object *arg;
485		if (!getstrarg((*getitem)(argv, i), &arg)) {
486			DEL(argvlist);
487			goto badarg;
488		}
489		argvlist[i] = getstringvalue(arg);
490	}
491	argvlist[argc] = NULL;
492
493	execv(getstringvalue(path), argvlist);
494
495	/* If we get here it's definitely an error */
496
497	DEL(argvlist);
498	return posix_error();
499}
500
501static object *
502posix_fork(self, args)
503	object *self;
504	object *args;
505{
506	int pid;
507	pid = fork();
508	if (pid == -1)
509		return posix_error();
510	return newintobject((long)pid);
511}
512
513static object *
514posix_getpid(self, args)
515	object *self;
516	object *args;
517{
518	if (!getnoarg())
519		return NULL;
520	return newintobject((long)getpid());
521}
522
523static object *
524posix_getppid(self, args)
525	object *self;
526	object *args;
527{
528	if (!getnoarg())
529		return NULL;
530	return newintobject((long)getppid());
531}
532
533static object *
534posix_kill(self, args)
535	object *self;
536	object *args;
537{
538	int pid, sig;
539	if (!getintintarg(args, &pid, &sig))
540		return NULL;
541	if (kill(pid, sig) == -1)
542		return posix_error();
543	INCREF(None);
544	return None;
545}
546
547static object *
548posix_wait(self, args) /* Also waitpid() */
549	object *self;
550	object *args;
551{
552	object *v;
553	int pid, sts;
554	if (args == NULL)
555		pid = wait(&sts);
556	else {
557#ifdef NO_WAITPID
558		err_setstr(RuntimeError,
559		"posix.wait(pid, options) not supported on this system");
560#else
561		int options;
562		if (!getintintarg(args, &pid, &options))
563			return NULL;
564		pid = waitpid(pid, &sts, options);
565#endif
566	}
567	if (pid == -1)
568		return posix_error();
569	v = newtupleobject(2);
570	if (v != NULL) {
571		settupleitem(v, 0, newintobject((long)pid));
572		settupleitem(v, 1, newintobject((long)sts));
573		if (err_occurred()) {
574			DECREF(v);
575			v = NULL;
576		}
577	}
578	return v;
579}
580
581#endif /* MSDOS */
582
583#ifndef NO_LSTAT
584
585static object *
586posix_lstat(self, args)
587	object *self;
588	object *args;
589{
590	extern int lstat PROTO((const char *, struct stat *));
591	return posix_do_stat(self, args, lstat);
592}
593
594static object *
595posix_readlink(self, args)
596	object *self;
597	object *args;
598{
599	char buf[1024]; /* XXX Should use MAXPATHLEN */
600	object *path;
601	int n;
602	if (!getstrarg(args, &path))
603		return NULL;
604	n = readlink(getstringvalue(path), buf, sizeof buf);
605	if (n < 0)
606		return posix_error();
607	return newsizedstringobject(buf, n);
608}
609
610static object *
611posix_symlink(self, args)
612	object *self;
613	object *args;
614{
615	extern int symlink PROTO((const char *, const char *));
616	return posix_2str(args, symlink);
617}
618
619#endif /* NO_LSTAT */
620
621
622static struct methodlist posix_methods[] = {
623	{"chdir",	posix_chdir},
624	{"chmod",	posix_chmod},
625	{"getcwd",	posix_getcwd},
626#ifndef MSDOS
627	{"link",	posix_link},
628#endif
629	{"listdir",	posix_listdir},
630	{"mkdir",	posix_mkdir},
631	{"rename",	posix_rename},
632	{"rmdir",	posix_rmdir},
633	{"stat",	posix_stat},
634	{"system",	posix_system},
635#ifndef MSDOS
636	{"umask",	posix_umask},
637#endif
638	{"unlink",	posix_unlink},
639	{"utime",	posix_utime},
640#ifndef MSDOS
641	{"_exit",	posix__exit},
642	{"exec",	posix_exec},
643	{"fork",	posix_fork},
644	{"getpid",	posix_getpid},
645	{"getppid",	posix_getppid},
646	{"kill",	posix_kill},
647	{"wait",	posix_wait},
648#endif
649#ifndef NO_LSTAT
650	{"lstat",	posix_lstat},
651	{"readlink",	posix_readlink},
652	{"symlink",	posix_symlink},
653#endif
654	{NULL,		NULL}		 /* Sentinel */
655};
656
657
658void
659initposix()
660{
661	object *m, *d, *v;
662
663	m = initmodule("posix", posix_methods);
664	d = getmoduledict(m);
665
666	/* Initialize posix.environ dictionary */
667	v = convertenviron();
668	if (v == NULL || dictinsert(d, "environ", v) != 0)
669		fatal("can't define posix.environ");
670	DECREF(v);
671
672	/* Initialize posix.error exception */
673	PosixError = newstringobject("posix.error");
674	if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
675		fatal("can't define posix.error");
676}
677
678#ifdef MSDOS
679
680/* A small "compatibility library" for TurboC under MS-DOS */
681
682#include <sir.h>
683#include <io.h>
684#include <dos.h>
685#include <fcntl.h>
686
687int
688chmod(path, mode)
689	char *path;
690	int mode;
691{
692	return _chmod(path, 1, mode);
693}
694
695int
696utime(path, times)
697	char *path;
698	time_t times[2];
699{
700	struct date dt;
701	struct time tm;
702	struct ftime dft;
703	int	fh;
704	unixtodos(tv[0].tv_sec,&dt,&tm);
705	dft.ft_tsec = tm.ti_sec; dft.ft_min = tm.ti_min;
706	dft.ft_hour = tm.ti_hour; dft.ft_day = dt.da_day;
707	dft.ft_month = dt.da_mon;
708	dft.ft_year = (dt.da_year - 1980);	/* this is for TC library */
709
710	if ((fh = open(getstringvalue(path),O_RDWR)) < 0)
711		return posix_error();	/* can't open file to set time */
712	if (setftime(fh,&dft) < 0)
713	{
714		close(fh);
715		return posix_error();
716	}
717	close(fh);				/* close the temp handle */
718}
719
720#endif /* MSDOS */
721