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