1 /***********************************************************
2 Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* POSIX module implementation */
44 #include <sys/types.h>
48 #include <sys/times.h>
49 #include <sys/param.h>
55 #define UTIME_STRUCT 1
69 #include <unistd.h> /* Take this out and hope the best if it doesn't exist */
72 #include "allobjects.h"
73 #include "modsupport.h"
79 /* XXX Aren't these always declared in unistd.h? */
80 extern int mkdir
PROTO((const char *, mode_t
));
81 extern int chdir
PROTO((const char *));
82 extern int rmdir
PROTO((const char *));
83 extern int chmod
PROTO((const char *, mode_t
));
84 extern char *getcwd(); /* No PROTO((char *, int)) -- non portable */
85 extern char *strerror
PROTO((int));
86 extern int link
PROTO((const char *, const char *));
87 extern int rename
PROTO((const char *, const char *));
88 extern int stat
PROTO((const char *, struct stat
*));
89 extern int unlink
PROTO((const char *));
90 extern int pclose
PROTO((FILE *));
91 #endif /* !_SEQUENT_ */
95 extern int lstat
PROTO((const char *, struct stat
*));
96 extern int symlink
PROTO((const char *, const char *));
100 /* Return a dictionary corresponding to the POSIX environment table */
102 extern char **environ
;
114 /* XXX This part ignores errors */
115 for (e
= environ
; *e
!= NULL
; e
++) {
117 char *p
= strchr(*e
, '=');
120 v
= newstringobject(p
+1);
124 (void) dictinsert(d
, *e
, v
);
132 static object
*PosixError
; /* Exception posix.error */
134 /* Set a POSIX-specific error from errno, and return NULL */
136 static object
* posix_error() { return err_errno(PosixError
);
140 /* POSIX generic methods */
143 posix_1str(args
, func
)
145 int (*func
) FPROTO((const char *));
149 if (!getargs(args
, "s", &path1
))
152 res
= (*func
)(path1
);
155 return posix_error();
161 posix_2str(args
, func
)
163 int (*func
) FPROTO((const char *, const char *));
167 if (!getargs(args
, "(ss)", &path1
, &path2
))
170 res
= (*func
)(path1
, path2
);
173 return posix_error();
179 posix_strint(args
, func
)
181 int (*func
) FPROTO((const char *, int));
186 if (!getargs(args
, "(si)", &path
, &i
))
189 res
= (*func
)(path
, i
);
192 return posix_error();
198 posix_do_stat(self
, args
, statfunc
)
201 int (*statfunc
) FPROTO((const char *, struct stat
*));
206 if (!getargs(args
, "s", &path
))
209 res
= (*statfunc
)(path
, &st
);
212 return posix_error();
213 return mkvalue("(llllllllll)",
230 posix_chdir(self
, args
)
234 return posix_1str(args
, chdir
);
238 posix_chmod(self
, args
)
242 return posix_strint(args
, chmod
);
246 posix_getcwd(self
, args
)
255 res
= getcwd(buf
, sizeof buf
);
258 return posix_error();
259 return newstringobject(buf
);
263 posix_link(self
, args
)
267 return posix_2str(args
, link
);
271 posix_listdir(self
, args
)
279 if (!getargs(args
, "s", &name
))
282 if ((dirp
= opendir(name
)) == NULL
) {
284 return posix_error();
286 if ((d
= newlistobject(0)) == NULL
) {
291 while ((ep
= readdir(dirp
)) != NULL
) {
292 v
= newstringobject(ep
->d_name
);
298 if (addlistitem(d
, v
) != 0) {
313 posix_mkdir(self
, args
)
317 return posix_strint(args
, mkdir
);
321 posix_nice(self
, args
)
325 int increment
, value
;
327 if (!getargs(args
, "i", &increment
))
329 value
= nice(increment
);
331 return posix_error();
332 return newintobject((long) value
);
335 #if i386 && ! _SEQUENT_
342 /* XXX Shouldn't this unlink the destination first? */
343 status
= link(from
, to
);
348 #endif /* i386 && ! _SEQUENT_ */
351 posix_rename(self
, args
)
355 return posix_2str(args
, rename
);
359 posix_rmdir(self
, args
)
363 return posix_1str(args
, rmdir
);
367 posix_stat(self
, args
)
371 return posix_do_stat(self
, args
, stat
);
375 posix_system(self
, args
)
381 if (!getargs(args
, "s", &command
))
384 sts
= system(command
);
386 return newintobject(sts
);
390 posix_umask(self
, args
)
395 if (!getintarg(args
, &i
))
399 return posix_error();
400 return newintobject((long)i
);
404 posix_unlink(self
, args
)
408 return posix_1str(args
, unlink
);
412 #include <sys/utsname.h>
414 extern int uname
PROTO((struct utsname
*));
417 posix_uname(self
, args
)
430 return posix_error();
431 return mkvalue("(sssss)",
438 #endif /* NO_UNAME */
445 posix_utime(self
, args
)
454 #define ATIME buf.actime
455 #define MTIME buf.modtime
456 #define UTIME_ARG &buf
462 #define UTIME_ARG buf
465 if (!getargs(args
, "(s(ll))", &path
, &ATIME
, &MTIME
))
468 res
= utime(path
, UTIME_ARG
);
471 return posix_error();
480 /* Process operations */
483 posix__exit(self
, args
)
488 if (!getintarg(args
, &sts
))
495 posix_execv(self
, args
)
503 object
*(*getitem
) PROTO((object
*, int));
505 /* execv has two arguments: (path, argv), where
506 argv is a list or tuple of strings. */
508 if (!getargs(args
, "(sO)", &path
, &argv
))
510 if (is_listobject(argv
)) {
511 argc
= getlistsize(argv
);
512 getitem
= getlistitem
;
514 else if (is_tupleobject(argv
)) {
515 argc
= gettuplesize(argv
);
516 getitem
= gettupleitem
;
524 argvlist
= NEW(char *, argc
+1);
525 if (argvlist
== NULL
)
527 for (i
= 0; i
< argc
; i
++) {
528 if (!getargs((*getitem
)(argv
, i
), "s", &argvlist
[i
])) {
533 argvlist
[argc
] = NULL
;
535 execv(path
, argvlist
);
537 /* If we get here it's definitely an error */
540 return posix_error();
544 posix_execve(self
, args
)
553 int i
, pos
, argc
, envc
;
554 object
*(*getitem
) PROTO((object
*, int));
556 /* execve has three arguments: (path, argv, env), where
557 argv is a list or tuple of strings and env is a dictionary
558 like posix.environ. */
560 if (!getargs(args
, "(sOO)", &path
, &argv
, &env
))
562 if (is_listobject(argv
)) {
563 argc
= getlistsize(argv
);
564 getitem
= getlistitem
;
566 else if (is_tupleobject(argv
)) {
567 argc
= gettuplesize(argv
);
568 getitem
= gettupleitem
;
571 err_setstr(TypeError
, "argv must be tuple or list");
574 if (!is_dictobject(env
)) {
575 err_setstr(TypeError
, "env must be dictionary");
579 argvlist
= NEW(char *, argc
+1);
580 if (argvlist
== NULL
) {
584 for (i
= 0; i
< argc
; i
++) {
585 if (!getargs((*getitem
)(argv
, i
),
586 "s;argv must be list of strings",
591 argvlist
[argc
] = NULL
;
593 i
= getmappingsize(env
);
594 envlist
= NEW(char *, i
+ 1);
595 if (envlist
== NULL
) {
601 while (mappinggetnext(env
, &pos
, &key
, &val
)) {
603 if (!getargs(key
, "s;non-string key in env", &k
) ||
604 !getargs(val
, "s;non-string value in env", &v
)) {
607 p
= NEW(char, getstringsize(key
) + getstringsize(val
) + 2);
612 sprintf(p
, "%s=%s", k
, v
);
617 execve(path
, argvlist
, envlist
);
619 /* If we get here it's definitely an error */
621 (void) posix_error();
634 posix_fork(self
, args
)
643 return posix_error();
644 return newintobject((long)pid
);
648 posix_getegid(self
, args
)
654 return newintobject((long)getegid());
658 posix_geteuid(self
, args
)
664 return newintobject((long)geteuid());
668 posix_getgid(self
, args
)
674 return newintobject((long)getgid());
678 posix_getpid(self
, args
)
684 return newintobject((long)getpid());
688 posix_getpgrp(self
, args
)
695 return newintobject((long)getpgrp());
697 return newintobject((long)getpgrp(0));
702 posix_setpgrp(self
, args
)
711 if (setpgrp(0, 0) < 0)
713 return posix_error();
719 posix_getppid(self
, args
)
725 return newintobject((long)getppid());
729 posix_getuid(self
, args
)
735 return newintobject((long)getuid());
739 posix_kill(self
, args
)
744 if (!getargs(args
, "(ii)", &pid
, &sig
))
746 if (kill(pid
, sig
) == -1)
747 return posix_error();
753 posix_popen(self
, args
)
759 if (!getargs(args
, "(ss)", &name
, &mode
))
762 fp
= popen(name
, mode
);
765 return posix_error();
766 /* From now on, ignore SIGPIPE and let the error checking
768 (void) signal(SIGPIPE
, SIG_IGN
);
769 return newopenfileobject(fp
, name
, mode
, pclose
);
773 posix_setuid(self
, args
)
778 if (!getargs(args
, "i", &uid
))
781 return posix_error();
787 posix_setgid(self
, args
)
792 if (!getargs(args
, "i", &gid
))
795 return posix_error();
801 posix_waitpid(self
, args
)
806 err_setstr(PosixError
,
807 "posix.waitpid() not supported on this system");
810 int pid
, options
, sts
;
811 if (!getargs(args
, "(ii)", &pid
, &options
))
814 pid
= waitpid(pid
, &sts
, options
);
817 return posix_error();
819 return mkvalue("ii", pid
, sts
);
824 posix_wait(self
, args
)
830 return posix_waitpid(self
, args
); /* BW compat */
835 return posix_error();
837 return mkvalue("ii", pid
, sts
);
841 posix_lstat(self
, args
)
845 return posix_do_stat(self
, args
, lstat
);
849 posix_readlink(self
, args
)
854 err_setstr(PosixError
, "readlink not implemented on this system");
857 char buf
[1024]; /* XXX Should use MAXPATHLEN */
860 if (!getargs(args
, "s", &path
))
863 n
= readlink(path
, buf
, (int) sizeof buf
);
866 return posix_error();
867 return newsizedstringobject(buf
, n
);
872 posix_symlink(self
, args
)
877 err_setstr(PosixError
, "symlink not implemented on this system");
880 return posix_2str(args
, symlink
);
888 posix_times(self
, args
)
898 if (c
== (clock_t) -1)
899 return posix_error();
900 return mkvalue("dddd",
901 (double)t
.tms_utime
/ HZ
,
902 (double)t
.tms_stime
/ HZ
,
903 (double)t
.tms_cutime
/ HZ
,
904 (double)t
.tms_cstime
/ HZ
);
907 #endif /* DO_TIMES */
912 posix_setsid(self
, args
)
919 return posix_error();
925 posix_setpgid(self
, args
)
930 if (!getargs(args
, "(ii)", &pid
, &pgrp
))
932 if (setpgid(pid
, pgrp
) < 0)
933 return posix_error();
939 posix_tcgetpgrp(self
, args
)
944 if (!getargs(args
, "i", &fd
))
946 pgid
= tcgetpgrp(fd
);
948 return posix_error();
949 return newintobject((long)pgid
);
953 posix_tcsetpgrp(self
, args
)
958 if (!getargs(args
, "(ii)", &fd
, &pgid
))
960 if (tcsetpgrp(fd
, pgid
) < 0)
961 return posix_error();
968 /* Functions acting on file descriptors */
971 posix_open(self
, args
)
979 if (!getargs(args
, "(si)", &file
, &flag
)) {
981 if (!getargs(args
, "(sii)", &file
, &flag
, &mode
))
985 fd
= open(file
, flag
, mode
);
988 return posix_error();
989 return newintobject((long)fd
);
993 posix_close(self
, args
)
998 if (!getargs(args
, "i", &fd
))
1004 return posix_error();
1010 posix_dup(self
, args
)
1015 if (!getargs(args
, "i", &fd
))
1021 return posix_error();
1022 return newintobject((long)fd
);
1026 posix_dup2(self
, args
)
1031 if (!getargs(args
, "(ii)", &fd
, &fd2
))
1034 res
= dup2(fd
, fd2
);
1037 return posix_error();
1043 posix_lseek(self
, args
)
1049 if (!getargs(args
, "(ili)", &fd
, &pos
, &how
))
1052 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
1054 case 0: how
= SEEK_SET
; break;
1055 case 1: how
= SEEK_CUR
; break;
1056 case 2: how
= SEEK_END
; break;
1060 res
= lseek(fd
, pos
, how
);
1063 return posix_error();
1064 return newintobject(res
);
1068 posix_read(self
, args
)
1074 if (!getargs(args
, "(ii)", &fd
, &size
))
1076 buffer
= newsizedstringobject((char *)NULL
, size
);
1080 size
= read(fd
, getstringvalue(buffer
), size
);
1084 return posix_error();
1086 resizestring(&buffer
, size
);
1091 posix_write(self
, args
)
1097 if (!getargs(args
, "(is#)", &fd
, &buffer
, &size
))
1100 size
= write(fd
, buffer
, size
);
1103 return posix_error();
1104 return newintobject((long)size
);
1108 posix_fstat(self
, args
)
1115 if (!getargs(args
, "i", &fd
))
1118 res
= fstat(fd
, &st
);
1121 return posix_error();
1122 return mkvalue("(llllllllll)",
1136 posix_fdopen(self
, args
)
1140 extern int fclose
PROTO((FILE *));
1144 if (!getargs(args
, "(is)", &fd
, &mode
))
1147 fp
= fdopen(fd
, mode
);
1150 return posix_error();
1151 /* From now on, ignore SIGPIPE and let the error checking
1153 (void) signal(SIGPIPE
, SIG_IGN
);
1154 return newopenfileobject(fp
, "(fdopen)", mode
, fclose
);
1158 posix_pipe(self
, args
)
1164 if (!getargs(args
, ""))
1170 return posix_error();
1171 return mkvalue("(ii)", fds
[0], fds
[1]);
1174 static struct methodlist posix_methods
[] = {
1175 {"chdir", posix_chdir
},
1176 {"chmod", posix_chmod
},
1177 {"getcwd", posix_getcwd
},
1178 {"link", posix_link
},
1179 {"listdir", posix_listdir
},
1180 {"lstat", posix_lstat
},
1181 {"mkdir", posix_mkdir
},
1182 {"nice", posix_nice
},
1183 {"readlink", posix_readlink
},
1184 {"rename", posix_rename
},
1185 {"rmdir", posix_rmdir
},
1186 {"stat", posix_stat
},
1187 {"symlink", posix_symlink
},
1188 {"system", posix_system
},
1189 {"umask", posix_umask
},
1191 {"uname", posix_uname
},
1193 {"unlink", posix_unlink
},
1194 {"utime", posix_utime
},
1196 {"times", posix_times
},
1198 {"_exit", posix__exit
},
1199 {"execv", posix_execv
},
1200 {"execve", posix_execve
},
1201 {"fork", posix_fork
},
1202 {"getegid", posix_getegid
},
1203 {"geteuid", posix_geteuid
},
1204 {"getgid", posix_getgid
},
1205 {"getpid", posix_getpid
},
1206 {"getpgrp", posix_getpgrp
},
1207 {"getppid", posix_getppid
},
1208 {"getuid", posix_getuid
},
1209 {"kill", posix_kill
},
1210 {"popen", posix_popen
},
1211 {"setuid", posix_setuid
},
1212 {"setgid", posix_setgid
},
1213 {"setpgrp", posix_setpgrp
},
1214 {"wait", posix_wait
},
1215 {"waitpid", posix_waitpid
},
1217 {"setsid", posix_setsid
},
1218 {"setpgid", posix_setpgid
},
1219 {"tcgetpgrp", posix_tcgetpgrp
},
1220 {"tcsetpgrp", posix_tcsetpgrp
},
1222 {"open", posix_open
},
1223 {"close", posix_close
},
1225 {"dup2", posix_dup2
},
1226 {"lseek", posix_lseek
},
1227 {"read", posix_read
},
1228 {"write", posix_write
},
1229 {"fstat", posix_fstat
},
1230 {"fdopen", posix_fdopen
},
1231 {"pipe", posix_pipe
},
1233 {NULL
, NULL
} /* Sentinel */
1242 m
= initmodule("posix", posix_methods
);
1243 d
= getmoduledict(m
);
1245 /* Initialize posix.environ dictionary */
1246 v
= convertenviron();
1247 if (v
== NULL
|| dictinsert(d
, "environ", v
) != 0)
1248 fatal("can't define posix.environ");
1251 /* Initialize posix.error exception */
1252 PosixError
= newstringobject("posix.error");
1253 if (PosixError
== NULL
|| dictinsert(d
, "error", PosixError
) != 0)
1254 fatal("can't define posix.error");
1258 /* Function used elsewhere to get a file's modification time */
1265 if (stat(path
, &st
) != 0)