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