posixmodule.c revision 3b06619e1cbb2dfc4da4992bc648304e48af1701
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 operations */
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_popen(self, args)
549	object *self;
550	object *args;
551{
552	extern int pclose PROTO((FILE *));
553	object *name, *mode;
554	FILE *fp;
555	if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2 ||
556		!is_stringobject(name = gettupleitem(args, 0)) ||
557		!is_stringobject(mode = gettupleitem(args, 1))) {
558		err_setstr(TypeError, "open() requires 2 string arguments");
559		return NULL;
560	}
561	fp = popen(getstringvalue(name), getstringvalue(mode));
562	if (fp == NULL)
563		return posix_error();
564	return newopenfileobject(fp, name, mode, pclose);
565}
566
567static object *
568posix_wait(self, args) /* Also waitpid() */
569	object *self;
570	object *args;
571{
572	object *v;
573	int pid, sts;
574	if (args == NULL)
575		pid = wait(&sts);
576	else {
577#ifdef NO_WAITPID
578		err_setstr(RuntimeError,
579		"posix.wait(pid, options) not supported on this system");
580#else
581		int options;
582		if (!getintintarg(args, &pid, &options))
583			return NULL;
584		pid = waitpid(pid, &sts, options);
585#endif
586	}
587	if (pid == -1)
588		return posix_error();
589	v = newtupleobject(2);
590	if (v != NULL) {
591		settupleitem(v, 0, newintobject((long)pid));
592		settupleitem(v, 1, newintobject((long)sts));
593		if (err_occurred()) {
594			DECREF(v);
595			v = NULL;
596		}
597	}
598	return v;
599}
600
601#endif /* MSDOS */
602
603#ifndef NO_LSTAT
604
605static object *
606posix_lstat(self, args)
607	object *self;
608	object *args;
609{
610	extern int lstat PROTO((const char *, struct stat *));
611	return posix_do_stat(self, args, lstat);
612}
613
614static object *
615posix_readlink(self, args)
616	object *self;
617	object *args;
618{
619	char buf[1024]; /* XXX Should use MAXPATHLEN */
620	object *path;
621	int n;
622	if (!getstrarg(args, &path))
623		return NULL;
624	n = readlink(getstringvalue(path), buf, sizeof buf);
625	if (n < 0)
626		return posix_error();
627	return newsizedstringobject(buf, n);
628}
629
630static object *
631posix_symlink(self, args)
632	object *self;
633	object *args;
634{
635	extern int symlink PROTO((const char *, const char *));
636	return posix_2str(args, symlink);
637}
638
639#endif /* NO_LSTAT */
640
641
642static struct methodlist posix_methods[] = {
643	{"chdir",	posix_chdir},
644	{"chmod",	posix_chmod},
645	{"getcwd",	posix_getcwd},
646#ifndef MSDOS
647	{"link",	posix_link},
648#endif
649	{"listdir",	posix_listdir},
650	{"mkdir",	posix_mkdir},
651	{"rename",	posix_rename},
652	{"rmdir",	posix_rmdir},
653	{"stat",	posix_stat},
654	{"system",	posix_system},
655#ifndef MSDOS
656	{"umask",	posix_umask},
657#endif
658	{"unlink",	posix_unlink},
659	{"utime",	posix_utime},
660#ifndef MSDOS
661	{"_exit",	posix__exit},
662	{"exec",	posix_exec},
663	{"fork",	posix_fork},
664	{"getpid",	posix_getpid},
665	{"getppid",	posix_getppid},
666	{"kill",	posix_kill},
667	{"popen",	posix_popen},
668	{"wait",	posix_wait},
669#endif
670#ifndef NO_LSTAT
671	{"lstat",	posix_lstat},
672	{"readlink",	posix_readlink},
673	{"symlink",	posix_symlink},
674#endif
675	{NULL,		NULL}		 /* Sentinel */
676};
677
678
679void
680initposix()
681{
682	object *m, *d, *v;
683
684	m = initmodule("posix", posix_methods);
685	d = getmoduledict(m);
686
687	/* Initialize posix.environ dictionary */
688	v = convertenviron();
689	if (v == NULL || dictinsert(d, "environ", v) != 0)
690		fatal("can't define posix.environ");
691	DECREF(v);
692
693	/* Initialize posix.error exception */
694	PosixError = newstringobject("posix.error");
695	if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
696		fatal("can't define posix.error");
697}
698
699
700/* Function used elsewhere to get a file's modification time */
701
702long
703getmtime(path)
704	char *path;
705{
706	struct stat st;
707	if (stat(path, &st) != 0)
708		return -1;
709	else
710		return st.st_mtime;
711}
712
713
714#ifdef MSDOS
715
716/* A small "compatibility library" for TurboC under MS-DOS */
717
718#include <sir.h>
719#include <io.h>
720#include <dos.h>
721#include <fcntl.h>
722
723int
724chmod(path, mode)
725	char *path;
726	int mode;
727{
728	return _chmod(path, 1, mode);
729}
730
731int
732utime(path, times)
733	char *path;
734	time_t times[2];
735{
736	struct date dt;
737	struct time tm;
738	struct ftime dft;
739	int	fh;
740	unixtodos(tv[0].tv_sec,&dt,&tm);
741	dft.ft_tsec = tm.ti_sec; dft.ft_min = tm.ti_min;
742	dft.ft_hour = tm.ti_hour; dft.ft_day = dt.da_day;
743	dft.ft_month = dt.da_mon;
744	dft.ft_year = (dt.da_year - 1980);	/* this is for TC library */
745
746	if ((fh = open(getstringvalue(path),O_RDWR)) < 0)
747		return posix_error();	/* can't open file to set time */
748	if (setftime(fh,&dft) < 0)
749	{
750		close(fh);
751		return posix_error();
752	}
753	close(fh);				/* close the temp handle */
754}
755
756#endif /* MSDOS */
757