posixmodule.c revision 24f42ac74c360eab36721bb01293940d2a743dd5
1/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
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/* This file is also used for Windows NT.  In that case the module
28   actually calls itself 'nt', not 'posix', and a few functions are
29   either unimplemented or implemented differently.  The source
30   assumes that for Windows NT, the macro 'NT' is defined independent
31   of the compiler used.  Different compilers define their own feature
32   test macro, e.g. '__BORLANDC__' or '_MSCVER'. */
33
34/* For MS-DOS and Windows 3.x, use ../Dos/dosmodule.c */
35
36#include "allobjects.h"
37#include "modsupport.h"
38#include "ceval.h"
39
40#include <string.h>
41#include <errno.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#ifdef HAVE_SYS_WAIT_H
45#include <sys/wait.h>		/* For WNOHANG */
46#endif
47
48#include "mytime.h"		/* For clock_t on some systems */
49
50#ifdef HAVE_FCNTL_H
51#include <fcntl.h>
52#endif /* HAVE_FCNTL_H */
53
54#ifndef NT
55#define HAVE_FORK	1
56#endif
57
58#if !defined(NT) || defined(__BORLANDC__)
59/* Unix functions that the configure script doesn't check for
60   and that aren't easily available under NT except with Borland C */
61#define HAVE_GETEGID	1
62#define HAVE_GETEUID	1
63#define HAVE_GETGID	1
64#define HAVE_GETPPID	1
65#define HAVE_GETUID	1
66#define HAVE_KILL	1
67#define HAVE_WAIT	1
68#define HAVE_OPENDIR	1
69#define HAVE_PIPE	1
70#define HAVE_GETCWD	1
71#endif
72
73#ifndef NT
74
75#ifdef HAVE_UNISTD_H
76#include <unistd.h>
77#endif
78
79#ifdef NeXT
80/* NeXT's <unistd.h> and <utime.h> aren't worth much */
81#undef HAVE_UNISTD_H
82#undef HAVE_UTIME_H
83/* #undef HAVE_GETCWD */
84#endif
85
86#ifdef HAVE_UNISTD_H
87/* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */
88extern int rename();
89extern int pclose();
90extern int lstat();
91extern int symlink();
92#else /* !HAVE_UNISTD_H */
93extern int mkdir PROTO((const char *, mode_t));
94extern int chdir PROTO((const char *));
95extern int rmdir PROTO((const char *));
96extern int chmod PROTO((const char *, mode_t));
97extern int chown PROTO((const char *, uid_t, gid_t));
98extern char *getcwd PROTO((char *, int));
99extern char *strerror PROTO((int));
100extern int link PROTO((const char *, const char *));
101extern int rename PROTO((const char *, const char *));
102extern int stat PROTO((const char *, struct stat *));
103extern int unlink PROTO((const char *));
104extern int pclose PROTO((FILE *));
105#ifdef HAVE_SYMLINK
106extern int symlink PROTO((const char *, const char *));
107#endif /* HAVE_SYMLINK */
108#ifdef HAVE_LSTAT
109extern int lstat PROTO((const char *, struct stat *));
110#endif /* HAVE_LSTAT */
111#endif /* !HAVE_UNISTD_H */
112
113#endif /* !NT */
114
115#ifdef HAVE_UTIME_H
116#include <utime.h>
117#endif /* HAVE_UTIME_H */
118
119#ifdef HAVE_SYS_UTIME_H
120#include <sys/utime.h>
121#define HAVE_UTIME_H /* pretend we do for the rest of this file */
122#endif /* HAVE_SYS_UTIME_H */
123
124#ifdef HAVE_SYS_TIMES_H
125#include <sys/times.h>
126#endif /* HAVE_SYS_TIMES_H */
127
128#ifdef HAVE_SYS_PARAM_H
129#include <sys/param.h>
130#endif /* HAVE_SYS_PARAM_H */
131
132#ifdef HAVE_SYS_UTSNAME_H
133#include <sys/utsname.h>
134#endif /* HAVE_SYS_UTSNAME_H */
135
136#ifndef MAXPATHLEN
137#define MAXPATHLEN 1024
138#endif /* MAXPATHLEN */
139
140#ifdef HAVE_DIRENT_H
141#include <dirent.h>
142#define NAMLEN(dirent) strlen((dirent)->d_name)
143#else
144#define dirent direct
145#define NAMLEN(dirent) (dirent)->d_namlen
146#ifdef HAVE_SYS_NDIR_H
147#include <sys/ndir.h>
148#endif
149#ifdef HAVE_SYS_DIR_H
150#include <sys/dir.h>
151#endif
152#ifdef HAVE_NDIR_H
153#include <ndir.h>
154#endif
155#endif
156
157#ifdef NT
158#include <direct.h>
159#include <io.h>
160#include <process.h>
161#include <windows.h>
162#define popen   _popen
163#define pclose	_pclose
164#endif /* NT */
165
166#ifdef OS2
167#include <io.h>
168#endif /* OS2 */
169
170/* Return a dictionary corresponding to the POSIX environment table */
171
172#ifndef NT
173extern char **environ;
174#endif /* !NT */
175
176static object *
177convertenviron()
178{
179	object *d;
180	char **e;
181	d = newdictobject();
182	if (d == NULL)
183		return NULL;
184	if (environ == NULL)
185		return d;
186	/* XXX This part ignores errors */
187	for (e = environ; *e != NULL; e++) {
188		object *v;
189		char *p = strchr(*e, '=');
190		if (p == NULL)
191			continue;
192		v = newstringobject(p+1);
193		if (v == NULL)
194			continue;
195		*p = '\0';
196		(void) dictinsert(d, *e, v);
197		*p = '=';
198		DECREF(v);
199	}
200	return d;
201}
202
203
204static object *PosixError; /* Exception posix.error */
205
206/* Set a POSIX-specific error from errno, and return NULL */
207
208static object * posix_error()
209{
210	return err_errno(PosixError);
211}
212
213
214/* POSIX generic methods */
215
216static object *
217posix_1str(args, func)
218	object *args;
219	int (*func) FPROTO((const char *));
220{
221	char *path1;
222	int res;
223	if (!getargs(args, "s", &path1))
224		return NULL;
225	BGN_SAVE
226	res = (*func)(path1);
227	END_SAVE
228	if (res < 0)
229		return posix_error();
230	INCREF(None);
231	return None;
232}
233
234static object *
235posix_2str(args, func)
236	object *args;
237	int (*func) FPROTO((const char *, const char *));
238{
239	char *path1, *path2;
240	int res;
241	if (!getargs(args, "(ss)", &path1, &path2))
242		return NULL;
243	BGN_SAVE
244	res = (*func)(path1, path2);
245	END_SAVE
246	if (res < 0)
247		return posix_error();
248	INCREF(None);
249	return None;
250}
251
252static object *
253posix_strint(args, func)
254	object *args;
255	int (*func) FPROTO((const char *, int));
256{
257	char *path;
258	int i;
259	int res;
260	if (!getargs(args, "(si)", &path, &i))
261		return NULL;
262	BGN_SAVE
263	res = (*func)(path, i);
264	END_SAVE
265	if (res < 0)
266		return posix_error();
267	INCREF(None);
268	return None;
269}
270
271static object *
272posix_strintint(args, func)
273	object *args;
274	int (*func) FPROTO((const char *, int, int));
275{
276	char *path;
277	int i,i2;
278	int res;
279	if (!getargs(args, "(sii)", &path, &i, &i2))
280		return NULL;
281	BGN_SAVE
282	res = (*func)(path, i, i2);
283	END_SAVE
284	if (res < 0)
285		return posix_error();
286	INCREF(None);
287	return None;
288}
289
290static object *
291posix_do_stat(self, args, statfunc)
292	object *self;
293	object *args;
294	int (*statfunc) FPROTO((const char *, struct stat *));
295{
296	struct stat st;
297	char *path;
298	int res;
299	if (!getargs(args, "s", &path))
300		return NULL;
301	BGN_SAVE
302	res = (*statfunc)(path, &st);
303	END_SAVE
304	if (res != 0)
305		return posix_error();
306	return mkvalue("(llllllllll)",
307		    (long)st.st_mode,
308		    (long)st.st_ino,
309		    (long)st.st_dev,
310		    (long)st.st_nlink,
311		    (long)st.st_uid,
312		    (long)st.st_gid,
313		    (long)st.st_size,
314		    (long)st.st_atime,
315		    (long)st.st_mtime,
316		    (long)st.st_ctime);
317}
318
319
320/* POSIX methods */
321
322static object *
323posix_chdir(self, args)
324	object *self;
325	object *args;
326{
327	return posix_1str(args, chdir);
328}
329
330static object *
331posix_chmod(self, args)
332	object *self;
333	object *args;
334{
335	return posix_strint(args, chmod);
336}
337
338#ifdef HAVE_CHOWN
339static object *
340posix_chown(self, args)
341	object *self;
342	object *args;
343{
344	return posix_strintint(args, chown);
345}
346#endif /* HAVE_CHOWN */
347
348#ifdef HAVE_GETCWD
349static object *
350posix_getcwd(self, args)
351	object *self;
352	object *args;
353{
354	char buf[1026];
355	char *res;
356	if (!getnoarg(args))
357		return NULL;
358	BGN_SAVE
359	res = getcwd(buf, sizeof buf);
360	END_SAVE
361	if (res == NULL)
362		return posix_error();
363	return newstringobject(buf);
364}
365#endif
366
367#ifdef HAVE_LINK
368static object *
369posix_link(self, args)
370	object *self;
371	object *args;
372{
373	return posix_2str(args, link);
374}
375#endif /* HAVE_LINK */
376
377static object *
378posix_listdir(self, args)
379	object *self;
380	object *args;
381{
382#if defined(NT) && !defined(HAVE_OPENDIR)
383
384	char *name;
385	int len;
386	object *d, *v;
387	HANDLE hFindFile;
388	WIN32_FIND_DATA FileData;
389	char namebuf[MAX_PATH+5];
390
391	if (!getargs(args, "s#", &name, &len))
392		return NULL;
393	if (len >= MAX_PATH) {
394		err_setstr(ValueError, "path too long");
395		return NULL;
396	}
397	strcpy(namebuf, name);
398	if (namebuf[len-1] != '/' && namebuf[len-1] != '\\')
399		namebuf[len++] = '/';
400	strcpy(namebuf + len, "*.*");
401
402	if ((d = newlistobject(0)) == NULL)
403		return NULL;
404
405	hFindFile = FindFirstFile(namebuf, &FileData);
406	if (hFindFile == INVALID_HANDLE_VALUE) {
407		errno = GetLastError();
408		return posix_error();
409	}
410	do {
411		if (FileData.cFileName[0] == '.' &&
412		    (FileData.cFileName[1] == '\0' ||
413		     FileData.cFileName[1] == '.' &&
414		     FileData.cFileName[2] == '\0'))
415			continue;
416		v = newstringobject(FileData.cFileName);
417		if (v == NULL) {
418			DECREF(d);
419			d = NULL;
420			break;
421		}
422		if (addlistitem(d, v) != 0) {
423			DECREF(v);
424			DECREF(d);
425			d = NULL;
426			break;
427		}
428		DECREF(v);
429	} while (FindNextFile(hFindFile, &FileData) == TRUE);
430
431	if (FindClose(hFindFile) == FALSE) {
432		errno = GetLastError();
433		return posix_error();
434	}
435
436	return d;
437
438#else /* !NT */
439
440	char *name;
441	object *d, *v;
442	DIR *dirp;
443	struct dirent *ep;
444	if (!getargs(args, "s", &name))
445		return NULL;
446	BGN_SAVE
447	if ((dirp = opendir(name)) == NULL) {
448		RET_SAVE
449		return posix_error();
450	}
451	if ((d = newlistobject(0)) == NULL) {
452		closedir(dirp);
453		RET_SAVE
454		return NULL;
455	}
456	while ((ep = readdir(dirp)) != NULL) {
457		if (ep->d_name[0] == '.' &&
458		    (NAMLEN(ep) == 1 ||
459		     ep->d_name[1] == '.' && NAMLEN(ep) == 2))
460			continue;
461		v = newsizedstringobject(ep->d_name, NAMLEN(ep));
462		if (v == NULL) {
463			DECREF(d);
464			d = NULL;
465			break;
466		}
467		if (addlistitem(d, v) != 0) {
468			DECREF(v);
469			DECREF(d);
470			d = NULL;
471			break;
472		}
473		DECREF(v);
474	}
475	closedir(dirp);
476	END_SAVE
477
478	return d;
479
480#endif /* !NT */
481}
482
483static object *
484posix_mkdir(self, args)
485	object *self;
486	object *args;
487{
488	return posix_strint(args, mkdir);
489}
490
491#ifdef HAVE_NICE
492static object *
493posix_nice(self, args)
494	object *self;
495	object *args;
496{
497	int increment, value;
498
499	if (!getargs(args, "i", &increment))
500		return NULL;
501	value = nice(increment);
502	if (value == -1)
503		return posix_error();
504	return newintobject((long) value);
505}
506#endif /* HAVE_NICE */
507
508static object *
509posix_rename(self, args)
510	object *self;
511	object *args;
512{
513	return posix_2str(args, rename);
514}
515
516static object *
517posix_rmdir(self, args)
518	object *self;
519	object *args;
520{
521	return posix_1str(args, rmdir);
522}
523
524static object *
525posix_stat(self, args)
526	object *self;
527	object *args;
528{
529	return posix_do_stat(self, args, stat);
530}
531
532static object *
533posix_system(self, args)
534	object *self;
535	object *args;
536{
537	char *command;
538	long sts;
539	if (!getargs(args, "s", &command))
540		return NULL;
541	BGN_SAVE
542	sts = system(command);
543	END_SAVE
544	return newintobject(sts);
545}
546
547static object *
548posix_umask(self, args)
549	object *self;
550	object *args;
551{
552	int i;
553	if (!getintarg(args, &i))
554		return NULL;
555	i = umask(i);
556	if (i < 0)
557		return posix_error();
558	return newintobject((long)i);
559}
560
561static object *
562posix_unlink(self, args)
563	object *self;
564	object *args;
565{
566	return posix_1str(args, unlink);
567}
568
569#ifdef HAVE_UNAME
570static object *
571posix_uname(self, args)
572	object *self;
573	object *args;
574{
575	struct utsname u;
576	object *v;
577	int res;
578	if (!getnoarg(args))
579		return NULL;
580	BGN_SAVE
581	res = uname(&u);
582	END_SAVE
583	if (res < 0)
584		return posix_error();
585	return mkvalue("(sssss)",
586		       u.sysname,
587		       u.nodename,
588		       u.release,
589		       u.version,
590		       u.machine);
591}
592#endif /* HAVE_UNAME */
593
594static object *
595posix_utime(self, args)
596	object *self;
597	object *args;
598{
599	char *path;
600	long atime, mtime;
601	int res;
602
603#ifdef HAVE_UTIME_H
604	struct utimbuf buf;
605#define ATIME buf.actime
606#define MTIME buf.modtime
607#define UTIME_ARG &buf
608#else /* HAVE_UTIME_H */
609	time_t buf[2];
610#define ATIME buf[0]
611#define MTIME buf[1]
612#define UTIME_ARG buf
613#endif /* HAVE_UTIME_H */
614
615	if (!getargs(args, "(s(ll))", &path, &atime, &mtime))
616		return NULL;
617	ATIME = atime;
618	MTIME = mtime;
619	BGN_SAVE
620	res = utime(path, UTIME_ARG);
621	END_SAVE
622	if (res < 0)
623		return posix_error();
624	INCREF(None);
625	return None;
626#undef UTIME_ARG
627#undef ATIME
628#undef MTIME
629}
630
631
632/* Process operations */
633
634static object *
635posix__exit(self, args)
636	object *self;
637	object *args;
638{
639	int sts;
640	if (!getintarg(args, &sts))
641		return NULL;
642	_exit(sts);
643	/* NOTREACHED */
644}
645
646static object *
647posix_execv(self, args)
648	object *self;
649	object *args;
650{
651	char *path;
652	object *argv;
653	char **argvlist;
654	int i, argc;
655	object *(*getitem) PROTO((object *, int));
656
657	/* execv has two arguments: (path, argv), where
658	   argv is a list or tuple of strings. */
659
660	if (!getargs(args, "(sO)", &path, &argv))
661		return NULL;
662	if (is_listobject(argv)) {
663		argc = getlistsize(argv);
664		getitem = getlistitem;
665	}
666	else if (is_tupleobject(argv)) {
667		argc = gettuplesize(argv);
668		getitem = gettupleitem;
669	}
670	else {
671 badarg:
672		err_badarg();
673		return NULL;
674	}
675
676	argvlist = NEW(char *, argc+1);
677	if (argvlist == NULL)
678		return NULL;
679	for (i = 0; i < argc; i++) {
680		if (!getargs((*getitem)(argv, i), "s", &argvlist[i])) {
681			DEL(argvlist);
682			goto badarg;
683		}
684	}
685	argvlist[argc] = NULL;
686
687#ifdef BAD_EXEC_PROTOTYPES
688	execv(path, (const char **) argvlist);
689#else /* BAD_EXEC_PROTOTYPES */
690	execv(path, argvlist);
691#endif /* BAD_EXEC_PROTOTYPES */
692
693	/* If we get here it's definitely an error */
694
695	DEL(argvlist);
696	return posix_error();
697}
698
699static object *
700posix_execve(self, args)
701	object *self;
702	object *args;
703{
704	char *path;
705	object *argv, *env;
706	char **argvlist;
707	char **envlist;
708	object *key, *val;
709	int i, pos, argc, envc;
710	object *(*getitem) PROTO((object *, int));
711
712	/* execve has three arguments: (path, argv, env), where
713	   argv is a list or tuple of strings and env is a dictionary
714	   like posix.environ. */
715
716	if (!getargs(args, "(sOO)", &path, &argv, &env))
717		return NULL;
718	if (is_listobject(argv)) {
719		argc = getlistsize(argv);
720		getitem = getlistitem;
721	}
722	else if (is_tupleobject(argv)) {
723		argc = gettuplesize(argv);
724		getitem = gettupleitem;
725	}
726	else {
727		err_setstr(TypeError, "argv must be tuple or list");
728		return NULL;
729	}
730	if (!is_dictobject(env)) {
731		err_setstr(TypeError, "env must be dictionary");
732		return NULL;
733	}
734
735	argvlist = NEW(char *, argc+1);
736	if (argvlist == NULL) {
737		err_nomem();
738		return NULL;
739	}
740	for (i = 0; i < argc; i++) {
741		if (!getargs((*getitem)(argv, i),
742			     "s;argv must be list of strings",
743			     &argvlist[i])) {
744			goto fail_1;
745		}
746	}
747	argvlist[argc] = NULL;
748
749	i = getmappingsize(env);
750	envlist = NEW(char *, i + 1);
751	if (envlist == NULL) {
752		err_nomem();
753		goto fail_1;
754	}
755	pos = 0;
756	envc = 0;
757	while (mappinggetnext(env, &pos, &key, &val)) {
758		char *p, *k, *v;
759		if (!getargs(key, "s;non-string key in env", &k) ||
760		    !getargs(val, "s;non-string value in env", &v)) {
761			goto fail_2;
762		}
763		p = NEW(char, getstringsize(key) + getstringsize(val) + 2);
764		if (p == NULL) {
765			err_nomem();
766			goto fail_2;
767		}
768		sprintf(p, "%s=%s", k, v);
769		envlist[envc++] = p;
770	}
771	envlist[envc] = 0;
772
773
774#ifdef BAD_EXEC_PROTOTYPES
775	execve(path, (const char **)argvlist, envlist);
776#else /* BAD_EXEC_PROTOTYPES */
777	execve(path, argvlist, envlist);
778#endif /* BAD_EXEC_PROTOTYPES */
779
780	/* If we get here it's definitely an error */
781
782	(void) posix_error();
783
784 fail_2:
785	while (--envc >= 0)
786		DEL(envlist[envc]);
787	DEL(envlist);
788 fail_1:
789	DEL(argvlist);
790
791	return NULL;
792}
793
794#ifdef HAVE_FORK
795static object *
796posix_fork(self, args)
797	object *self;
798	object *args;
799{
800	int pid;
801	if (!getnoarg(args))
802		return NULL;
803	pid = fork();
804	if (pid == -1)
805		return posix_error();
806	return newintobject((long)pid);
807}
808#endif
809
810#ifdef HAVE_GETEGID
811static object *
812posix_getegid(self, args)
813	object *self;
814	object *args;
815{
816	if (!getnoarg(args))
817		return NULL;
818	return newintobject((long)getegid());
819}
820#endif
821
822#ifdef HAVE_GETEUID
823static object *
824posix_geteuid(self, args)
825	object *self;
826	object *args;
827{
828	if (!getnoarg(args))
829		return NULL;
830	return newintobject((long)geteuid());
831}
832#endif
833
834#ifdef HAVE_GETGID
835static object *
836posix_getgid(self, args)
837	object *self;
838	object *args;
839{
840	if (!getnoarg(args))
841		return NULL;
842	return newintobject((long)getgid());
843}
844#endif
845
846static object *
847posix_getpid(self, args)
848	object *self;
849	object *args;
850{
851	if (!getnoarg(args))
852		return NULL;
853	return newintobject((long)getpid());
854}
855
856#ifdef HAVE_GETPGRP
857static object *
858posix_getpgrp(self, args)
859	object *self;
860	object *args;
861{
862	if (!getnoarg(args))
863		return NULL;
864#ifdef GETPGRP_HAVE_ARG
865	return newintobject((long)getpgrp(0));
866#else /* GETPGRP_HAVE_ARG */
867	return newintobject((long)getpgrp());
868#endif /* GETPGRP_HAVE_ARG */
869}
870#endif /* HAVE_GETPGRP */
871
872#ifdef HAVE_SETPGRP
873static object *
874posix_setpgrp(self, args)
875	object *self;
876	object *args;
877{
878	if (!getnoarg(args))
879		return NULL;
880#ifdef SETPGRP_HAVE_ARG
881	if (setpgrp(0, 0) < 0)
882#else /* SETPGRP_HAVE_ARG */
883	if (setpgrp() < 0)
884#endif /* SETPGRP_HAVE_ARG */
885		return posix_error();
886	INCREF(None);
887	return None;
888}
889
890#endif /* HAVE_SETPGRP */
891
892#ifdef HAVE_GETPPID
893static object *
894posix_getppid(self, args)
895	object *self;
896	object *args;
897{
898	if (!getnoarg(args))
899		return NULL;
900	return newintobject((long)getppid());
901}
902#endif
903
904#ifdef HAVE_GETUID
905static object *
906posix_getuid(self, args)
907	object *self;
908	object *args;
909{
910	if (!getnoarg(args))
911		return NULL;
912	return newintobject((long)getuid());
913}
914#endif
915
916#ifdef HAVE_KILL
917static object *
918posix_kill(self, args)
919	object *self;
920	object *args;
921{
922	int pid, sig;
923	if (!getargs(args, "(ii)", &pid, &sig))
924		return NULL;
925	if (kill(pid, sig) == -1)
926		return posix_error();
927	INCREF(None);
928	return None;
929}
930#endif
931
932static object *
933posix_popen(self, args)
934	object *self;
935	object *args;
936{
937	char *name;
938	char *mode = "r";
939	int bufsize = -1;
940	FILE *fp;
941	object *f;
942	if (!newgetargs(args, "s|si", &name, &mode, &bufsize))
943		return NULL;
944	BGN_SAVE
945	fp = popen(name, mode);
946	END_SAVE
947	if (fp == NULL)
948		return posix_error();
949	f = newopenfileobject(fp, name, mode, pclose);
950	if (f != NULL)
951		setfilebufsize(f, bufsize);
952	return f;
953}
954
955#ifdef HAVE_SETUID
956static object *
957posix_setuid(self, args)
958	object *self;
959	object *args;
960{
961	int uid;
962	if (!getargs(args, "i", &uid))
963		return NULL;
964	if (setuid(uid) < 0)
965		return posix_error();
966	INCREF(None);
967	return None;
968}
969#endif /* HAVE_SETUID */
970
971#ifdef HAVE_SETGID
972static object *
973posix_setgid(self, args)
974	object *self;
975	object *args;
976{
977	int gid;
978	if (!getargs(args, "i", &gid))
979		return NULL;
980	if (setgid(gid) < 0)
981		return posix_error();
982	INCREF(None);
983	return None;
984}
985#endif /* HAVE_SETGID */
986
987#ifdef HAVE_WAITPID
988static object *
989posix_waitpid(self, args)
990	object *self;
991	object *args;
992{
993	int pid, options, sts;
994	if (!getargs(args, "(ii)", &pid, &options))
995		return NULL;
996	BGN_SAVE
997	pid = waitpid(pid, &sts, options);
998	END_SAVE
999	if (pid == -1)
1000		return posix_error();
1001	else
1002		return mkvalue("ii", pid, sts);
1003}
1004#endif /* HAVE_WAITPID */
1005
1006#ifdef HAVE_WAIT
1007static object *
1008posix_wait(self, args)
1009	object *self;
1010	object *args;
1011{
1012	int pid, sts;
1013	BGN_SAVE
1014	pid = wait(&sts);
1015	END_SAVE
1016	if (pid == -1)
1017		return posix_error();
1018	else
1019		return mkvalue("ii", pid, sts);
1020}
1021#endif
1022
1023static object *
1024posix_lstat(self, args)
1025	object *self;
1026	object *args;
1027{
1028#ifdef HAVE_LSTAT
1029	return posix_do_stat(self, args, lstat);
1030#else /* !HAVE_LSTAT */
1031	return posix_do_stat(self, args, stat);
1032#endif /* !HAVE_LSTAT */
1033}
1034
1035#ifdef HAVE_READLINK
1036static object *
1037posix_readlink(self, args)
1038	object *self;
1039	object *args;
1040{
1041	char buf[MAXPATHLEN];
1042	char *path;
1043	int n;
1044	if (!getargs(args, "s", &path))
1045		return NULL;
1046	BGN_SAVE
1047	n = readlink(path, buf, (int) sizeof buf);
1048	END_SAVE
1049	if (n < 0)
1050		return posix_error();
1051	return newsizedstringobject(buf, n);
1052}
1053#endif /* HAVE_READLINK */
1054
1055#ifdef HAVE_SYMLINK
1056static object *
1057posix_symlink(self, args)
1058	object *self;
1059	object *args;
1060{
1061	return posix_2str(args, symlink);
1062}
1063#endif /* HAVE_SYMLINK */
1064
1065#ifdef HAVE_TIMES
1066#ifndef HZ
1067#define HZ 60 /* Universal constant :-) */
1068#endif /* HZ */
1069static object *
1070posix_times(self, args)
1071	object *self;
1072	object *args;
1073{
1074	struct tms t;
1075	clock_t c;
1076	if (!getnoarg(args))
1077		return NULL;
1078	errno = 0;
1079	c = times(&t);
1080	if (c == (clock_t) -1)
1081		return posix_error();
1082	return mkvalue("dddd",
1083		       (double)t.tms_utime / HZ,
1084		       (double)t.tms_stime / HZ,
1085		       (double)t.tms_cutime / HZ,
1086		       (double)t.tms_cstime / HZ);
1087}
1088#endif /* HAVE_TIMES */
1089#if defined(NT) && !defined(HAVE_TIMES)
1090#define HAVE_TIMES	/* so the method table will pick it up */
1091static object *
1092posix_times(self, args)
1093	object *self;
1094	object *args;
1095{
1096	FILETIME create, exit, kernel, user;
1097	HANDLE hProc;
1098	if (!getnoarg(args))
1099		return NULL;
1100	hProc = GetCurrentProcess();
1101	GetProcessTimes(hProc,&create, &exit, &kernel, &user);
1102	return mkvalue("dddd",
1103		       (double)(kernel.dwHighDateTime*2E32+kernel.dwLowDateTime) / 2E6,
1104		       (double)(user.dwHighDateTime*2E32+user.dwLowDateTime) / 2E6,
1105		       (double)0,
1106		       (double)0);
1107}
1108#endif /* NT */
1109
1110#ifdef HAVE_SETSID
1111static object *
1112posix_setsid(self, args)
1113	object *self;
1114	object *args;
1115{
1116	if (!getnoarg(args))
1117		return NULL;
1118	if (setsid() < 0)
1119		return posix_error();
1120	INCREF(None);
1121	return None;
1122}
1123#endif /* HAVE_SETSID */
1124
1125#ifdef HAVE_SETPGID
1126static object *
1127posix_setpgid(self, args)
1128	object *self;
1129	object *args;
1130{
1131	int pid, pgrp;
1132	if (!getargs(args, "(ii)", &pid, &pgrp))
1133		return NULL;
1134	if (setpgid(pid, pgrp) < 0)
1135		return posix_error();
1136	INCREF(None);
1137	return None;
1138}
1139#endif /* HAVE_SETPGID */
1140
1141#ifdef HAVE_TCGETPGRP
1142static object *
1143posix_tcgetpgrp(self, args)
1144	object *self;
1145	object *args;
1146{
1147	int fd, pgid;
1148	if (!getargs(args, "i", &fd))
1149		return NULL;
1150	pgid = tcgetpgrp(fd);
1151	if (pgid < 0)
1152		return posix_error();
1153	return newintobject((long)pgid);
1154}
1155#endif /* HAVE_TCGETPGRP */
1156
1157#ifdef HAVE_TCSETPGRP
1158static object *
1159posix_tcsetpgrp(self, args)
1160	object *self;
1161	object *args;
1162{
1163	int fd, pgid;
1164	if (!getargs(args, "(ii)", &fd, &pgid))
1165		return NULL;
1166	if (tcsetpgrp(fd, pgid) < 0)
1167		return posix_error();
1168       INCREF(None);
1169	return None;
1170}
1171#endif /* HAVE_TCSETPGRP */
1172
1173/* Functions acting on file descriptors */
1174
1175static object *
1176posix_open(self, args)
1177	object *self;
1178	object *args;
1179{
1180	char *file;
1181	int flag;
1182	int mode = 0777;
1183	int fd;
1184	if (!getargs(args, "(si)", &file, &flag)) {
1185		err_clear();
1186		if (!getargs(args, "(sii)", &file, &flag, &mode))
1187			return NULL;
1188	}
1189	BGN_SAVE
1190	fd = open(file, flag, mode);
1191	END_SAVE
1192	if (fd < 0)
1193		return posix_error();
1194	return newintobject((long)fd);
1195}
1196
1197static object *
1198posix_close(self, args)
1199	object *self;
1200	object *args;
1201{
1202	int fd, res;
1203	if (!getargs(args, "i", &fd))
1204		return NULL;
1205	BGN_SAVE
1206	res = close(fd);
1207	END_SAVE
1208	if (res < 0)
1209		return posix_error();
1210	INCREF(None);
1211	return None;
1212}
1213
1214static object *
1215posix_dup(self, args)
1216	object *self;
1217	object *args;
1218{
1219	int fd;
1220	if (!getargs(args, "i", &fd))
1221		return NULL;
1222	BGN_SAVE
1223	fd = dup(fd);
1224	END_SAVE
1225	if (fd < 0)
1226		return posix_error();
1227	return newintobject((long)fd);
1228}
1229
1230static object *
1231posix_dup2(self, args)
1232	object *self;
1233	object *args;
1234{
1235	int fd, fd2, res;
1236	if (!getargs(args, "(ii)", &fd, &fd2))
1237		return NULL;
1238	BGN_SAVE
1239	res = dup2(fd, fd2);
1240	END_SAVE
1241	if (res < 0)
1242		return posix_error();
1243	INCREF(None);
1244	return None;
1245}
1246
1247static object *
1248posix_lseek(self, args)
1249	object *self;
1250	object *args;
1251{
1252	int fd, how;
1253	long pos, res;
1254	if (!getargs(args, "(ili)", &fd, &pos, &how))
1255		return NULL;
1256#ifdef SEEK_SET
1257	/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
1258	switch (how) {
1259	case 0: how = SEEK_SET; break;
1260	case 1: how = SEEK_CUR; break;
1261	case 2: how = SEEK_END; break;
1262	}
1263#endif /* SEEK_END */
1264	BGN_SAVE
1265	res = lseek(fd, pos, how);
1266	END_SAVE
1267	if (res < 0)
1268		return posix_error();
1269	return newintobject(res);
1270}
1271
1272static object *
1273posix_read(self, args)
1274	object *self;
1275	object *args;
1276{
1277	int fd, size;
1278	object *buffer;
1279	if (!getargs(args, "(ii)", &fd, &size))
1280		return NULL;
1281	buffer = newsizedstringobject((char *)NULL, size);
1282	if (buffer == NULL)
1283		return NULL;
1284	BGN_SAVE
1285	size = read(fd, getstringvalue(buffer), size);
1286	END_SAVE
1287	if (size < 0) {
1288		DECREF(buffer);
1289		return posix_error();
1290	}
1291	resizestring(&buffer, size);
1292	return buffer;
1293}
1294
1295static object *
1296posix_write(self, args)
1297	object *self;
1298	object *args;
1299{
1300	int fd, size;
1301	char *buffer;
1302	if (!getargs(args, "(is#)", &fd, &buffer, &size))
1303		return NULL;
1304	BGN_SAVE
1305	size = write(fd, buffer, size);
1306	END_SAVE
1307	if (size < 0)
1308		return posix_error();
1309	return newintobject((long)size);
1310}
1311
1312static object *
1313posix_fstat(self, args)
1314	object *self;
1315	object *args;
1316{
1317	int fd;
1318	struct stat st;
1319	int res;
1320	if (!getargs(args, "i", &fd))
1321		return NULL;
1322	BGN_SAVE
1323	res = fstat(fd, &st);
1324	END_SAVE
1325	if (res != 0)
1326		return posix_error();
1327	return mkvalue("(llllllllll)",
1328		    (long)st.st_mode,
1329		    (long)st.st_ino,
1330		    (long)st.st_dev,
1331		    (long)st.st_nlink,
1332		    (long)st.st_uid,
1333		    (long)st.st_gid,
1334		    (long)st.st_size,
1335		    (long)st.st_atime,
1336		    (long)st.st_mtime,
1337		    (long)st.st_ctime);
1338}
1339
1340static object *
1341posix_fdopen(self, args)
1342	object *self;
1343	object *args;
1344{
1345	extern int fclose PROTO((FILE *));
1346	int fd;
1347	char *mode = "r";
1348	int bufsize = -1;
1349	FILE *fp;
1350	object *f;
1351	if (!newgetargs(args, "i|si", &fd, &mode, &bufsize))
1352		return NULL;
1353	BGN_SAVE
1354	fp = fdopen(fd, mode);
1355	END_SAVE
1356	if (fp == NULL)
1357		return posix_error();
1358	f = newopenfileobject(fp, "(fdopen)", mode, fclose);
1359	if (f != NULL)
1360		setfilebufsize(f, bufsize);
1361	return f;
1362}
1363
1364static object *
1365posix_pipe(self, args)
1366	object *self;
1367	object *args;
1368{
1369#if !defined(NT) || defined(HAVE_PIPE)
1370	int fds[2];
1371	int res;
1372	if (!getargs(args, ""))
1373		return NULL;
1374	BGN_SAVE
1375	res = pipe(fds);
1376	END_SAVE
1377	if (res != 0)
1378		return posix_error();
1379	return mkvalue("(ii)", fds[0], fds[1]);
1380#else /* NT */
1381	HANDLE read, write;
1382	BOOL ok;
1383	if (!getargs(args, ""))
1384		return NULL;
1385	BGN_SAVE
1386	ok = CreatePipe( &read, &write, NULL, 0);
1387	END_SAVE
1388	if (!ok)
1389		return posix_error();
1390	return mkvalue("(ii)", read, write);
1391#endif /* NT */
1392}
1393
1394static struct methodlist posix_methods[] = {
1395	{"chdir",	posix_chdir},
1396	{"chmod",	posix_chmod},
1397#ifdef HAVE_CHOWN
1398	{"chown",	posix_chown},
1399#endif /* HAVE_CHOWN */
1400#ifdef HAVE_GETCWD
1401	{"getcwd",	posix_getcwd},
1402#endif
1403#ifdef HAVE_LINK
1404	{"link",	posix_link},
1405#endif /* HAVE_LINK */
1406	{"listdir",	posix_listdir},
1407	{"lstat",	posix_lstat},
1408	{"mkdir",	posix_mkdir},
1409#ifdef HAVE_NICE
1410	{"nice",	posix_nice},
1411#endif /* HAVE_NICE */
1412#ifdef HAVE_READLINK
1413	{"readlink",	posix_readlink},
1414#endif /* HAVE_READLINK */
1415	{"rename",	posix_rename},
1416	{"rmdir",	posix_rmdir},
1417	{"stat",	posix_stat},
1418#ifdef HAVE_SYMLINK
1419	{"symlink",	posix_symlink},
1420#endif /* HAVE_SYMLINK */
1421	{"system",	posix_system},
1422	{"umask",	posix_umask},
1423#ifdef HAVE_UNAME
1424	{"uname",	posix_uname},
1425#endif /* HAVE_UNAME */
1426	{"unlink",	posix_unlink},
1427	{"utime",	posix_utime},
1428#ifdef HAVE_TIMES
1429	{"times",	posix_times},
1430#endif /* HAVE_TIMES */
1431	{"_exit",	posix__exit},
1432	{"execv",	posix_execv},
1433	{"execve",	posix_execve},
1434#ifdef HAVE_FORK
1435	{"fork",	posix_fork},
1436#endif /* HAVE_FORK */
1437#ifdef HAVE_GETEGID
1438	{"getegid",	posix_getegid},
1439#endif /* HAVE_GETEGID */
1440#ifdef HAVE_GETEUID
1441	{"geteuid",	posix_geteuid},
1442#endif /* HAVE_GETEUID */
1443#ifdef HAVE_GETGID
1444	{"getgid",	posix_getgid},
1445#endif /* HAVE_GETGID */
1446	{"getpid",	posix_getpid},
1447#ifdef HAVE_GETPGRP
1448	{"getpgrp",	posix_getpgrp},
1449#endif /* HAVE_GETPGRP */
1450#ifdef HAVE_GETPPID
1451	{"getppid",	posix_getppid},
1452#endif /* HAVE_GETPPID */
1453#ifdef HAVE_GETUID
1454	{"getuid",	posix_getuid},
1455#endif /* HAVE_GETUID */
1456#ifdef HAVE_KILL
1457	{"kill",	posix_kill},
1458#endif /* HAVE_KILL */
1459	{"popen",	posix_popen,	1},
1460#ifdef HAVE_SETUID
1461	{"setuid",	posix_setuid},
1462#endif /* HAVE_SETUID */
1463#ifdef HAVE_SETGID
1464	{"setgid",	posix_setgid},
1465#endif /* HAVE_SETGID */
1466#ifdef HAVE_SETPGRP
1467	{"setpgrp",	posix_setpgrp},
1468#endif /* HAVE_SETPGRP */
1469#ifdef HAVE_WAIT
1470	{"wait",	posix_wait},
1471#endif /* HAVE_WAIT */
1472#ifdef HAVE_WAITPID
1473	{"waitpid",	posix_waitpid},
1474#endif /* HAVE_WAITPID */
1475#ifdef HAVE_SETSID
1476	{"setsid",	posix_setsid},
1477#endif /* HAVE_SETSID */
1478#ifdef HAVE_SETPGID
1479	{"setpgid",	posix_setpgid},
1480#endif /* HAVE_SETPGID */
1481#ifdef HAVE_TCGETPGRP
1482	{"tcgetpgrp",	posix_tcgetpgrp},
1483#endif /* HAVE_TCGETPGRP */
1484#ifdef HAVE_TCSETPGRP
1485	{"tcsetpgrp",	posix_tcsetpgrp},
1486#endif /* HAVE_TCSETPGRP */
1487	{"open",	posix_open},
1488	{"close",	posix_close},
1489	{"dup",		posix_dup},
1490	{"dup2",	posix_dup2},
1491	{"lseek",	posix_lseek},
1492	{"read",	posix_read},
1493	{"write",	posix_write},
1494	{"fstat",	posix_fstat},
1495	{"fdopen",	posix_fdopen,	1},
1496	{"pipe",	posix_pipe},
1497	{NULL,		NULL}		 /* Sentinel */
1498};
1499
1500
1501#ifdef NT
1502void
1503initnt()
1504{
1505	object *m, *d, *v;
1506
1507	m = initmodule("nt", posix_methods);
1508	d = getmoduledict(m);
1509
1510	/* Initialize nt.environ dictionary */
1511	v = convertenviron();
1512	if (v == NULL || dictinsert(d, "environ", v) != 0)
1513		fatal("can't define nt.environ");
1514	DECREF(v);
1515
1516	/* Initialize nt.error exception */
1517	PosixError = newstringobject("nt.error");
1518	if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
1519		fatal("can't define nt.error");
1520}
1521#else /* !NT */
1522void
1523initposix()
1524{
1525	object *m, *d, *v;
1526
1527	m = initmodule("posix", posix_methods);
1528	d = getmoduledict(m);
1529
1530	/* Initialize posix.environ dictionary */
1531	v = convertenviron();
1532	if (v == NULL || dictinsert(d, "environ", v) != 0)
1533		fatal("can't define posix.environ");
1534	DECREF(v);
1535
1536#ifdef WNOHANG
1537	/* Export WNOHANG symbol */
1538	v = newintobject((long)WNOHANG);
1539	if (v == NULL || dictinsert(d, "WNOHANG", v) != 0)
1540		fatal("can't define posix.WNOHANG");
1541	DECREF(v);
1542#endif
1543
1544	/* Initialize posix.error exception */
1545	PosixError = newstringobject("posix.error");
1546	if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
1547		fatal("can't define posix.error");
1548}
1549#endif /* !NT */
1550