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