blob: 0c1a487dba1b0c2e13afb29f5d4c2a6bebf9a28f [file] [log] [blame]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001/* POSIX module implementation */
2
3#include <stdio.h>
4#include <signal.h>
5#include <string.h>
6#include <setjmp.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <sys/time.h>
10#ifdef SYSV
11#include <dirent.h>
12#define direct dirent
13#else
14#include <sys/dir.h>
15#endif
16
17#include "PROTO.h"
18#include "object.h"
19#include "intobject.h"
20#include "stringobject.h"
21#include "tupleobject.h"
22#include "listobject.h"
23#include "dictobject.h"
24#include "methodobject.h"
25#include "moduleobject.h"
26#include "objimpl.h"
27#include "import.h"
28#include "sigtype.h"
29#include "modsupport.h"
30#include "errors.h"
31
32extern char *strerror();
33
34#ifdef AMOEBA
35#define NO_LSTAT
36#endif
37
38
39/* Return a dictionary corresponding to the POSIX environment table */
40
41extern char **environ;
42
43static object *
44convertenviron()
45{
46 object *d;
47 char **e;
48 d = newdictobject();
49 if (d == NULL)
50 return NULL;
51 if (environ == NULL)
52 return d;
53 /* XXX This part ignores errors */
54 for (e = environ; *e != NULL; e++) {
55 object *v;
56 char *p = strchr(*e, '=');
57 if (p == NULL)
58 continue;
59 v = newstringobject(p+1);
60 if (v == NULL)
61 continue;
62 *p = '\0';
63 (void) dictinsert(d, *e, v);
64 *p = '=';
65 DECREF(v);
66 }
67 return d;
68}
69
70
71static object *PosixError; /* Exception posix.error */
72
73/* Set a POSIX-specific error from errno, and return NULL */
74
75static object *
76posix_error()
77{
78 object *v = newtupleobject(2);
79 if (v != NULL) {
80 settupleitem(v, 0, newintobject((long)errno));
81 settupleitem(v, 1, newstringobject(strerror(errno)));
82 }
83 err_setval(PosixError, v);
84 if (v != NULL)
85 DECREF(v);
86 return NULL;
87}
88
89
90/* POSIX generic methods */
91
92static object *
93posix_1str(args, func)
94 object *args;
95 int (*func) FPROTO((const char *));
96{
97 object *path1;
98 if (!getstrarg(args, &path1))
99 return NULL;
100 if ((*func)(getstringvalue(path1)) < 0)
101 return posix_error();
102 INCREF(None);
103 return None;
104}
105
106static object *
107posix_2str(args, func)
108 object *args;
109 int (*func) FPROTO((const char *, const char *));
110{
111 object *path1, *path2;
112 if (!getstrstrarg(args, &path1, &path2))
113 return NULL;
114 if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0)
115 return posix_error();
116 INCREF(None);
117 return None;
118}
119
120static object *
121posix_strint(args, func)
122 object *args;
123 int (*func) FPROTO((const char *, int));
124{
125 object *path1;
126 int i;
127 if (!getstrintarg(args, &path1, &i))
128 return NULL;
129 if ((*func)(getstringvalue(path1), i) < 0)
130 return posix_error();
131 INCREF(None);
132 return None;
133}
134
135static object *
136posix_do_stat(self, args, statfunc)
137 object *self;
138 object *args;
139 int (*statfunc) FPROTO((const char *, struct stat *));
140{
141 struct stat st;
142 object *path;
143 object *v;
144 if (!getstrarg(args, &path))
145 return NULL;
146 if ((*statfunc)(getstringvalue(path), &st) != 0)
147 return posix_error();
148 v = newtupleobject(10);
149 if (v == NULL)
150 return NULL;
151 errno = 0;
152#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member))
153 SET(0, st_mode);
154 SET(1, st_ino);
155 SET(2, st_dev);
156 SET(3, st_nlink);
157 SET(4, st_uid);
158 SET(5, st_gid);
159 SET(6, st_size);
160 SET(7, st_atime);
161 SET(8, st_mtime);
162 SET(9, st_ctime);
163#undef SET
164 if (errno != 0) {
165 DECREF(v);
166 return err_nomem();
167 }
168 return v;
169}
170
171
172/* POSIX methods */
173
174static object *
175posix_chdir(self, args)
176 object *self;
177 object *args;
178{
179 extern int chdir PROTO((const char *));
180 return posix_1str(args, chdir);
181}
182
183static object *
184posix_chmod(self, args)
185 object *self;
186 object *args;
187{
188 extern int chmod PROTO((const char *, mode_t));
189 return posix_strint(args, chmod);
190}
191
192static object *
193posix_getcwd(self, args)
194 object *self;
195 object *args;
196{
197 char buf[1026];
198 extern char *getcwd PROTO((char *, int));
199 if (!getnoarg(args))
200 return NULL;
201 if (getcwd(buf, sizeof buf) == NULL)
202 return posix_error();
203 return newstringobject(buf);
204}
205
206static object *
207posix_link(self, args)
208 object *self;
209 object *args;
210{
211 extern int link PROTO((const char *, const char *));
212 return posix_2str(args, link);
213}
214
215static object *
216posix_listdir(self, args)
217 object *self;
218 object *args;
219{
220 object *name, *d, *v;
221 DIR *dirp;
222 struct direct *ep;
223 if (!getstrarg(args, &name))
224 return NULL;
225 if ((dirp = opendir(getstringvalue(name))) == NULL)
226 return posix_error();
227 if ((d = newlistobject(0)) == NULL) {
228 closedir(dirp);
229 return NULL;
230 }
231 while ((ep = readdir(dirp)) != NULL) {
232 v = newstringobject(ep->d_name);
233 if (v == NULL) {
234 DECREF(d);
235 d = NULL;
236 break;
237 }
238 if (addlistitem(d, v) != 0) {
239 DECREF(v);
240 DECREF(d);
241 d = NULL;
242 break;
243 }
244 DECREF(v);
245 }
246 closedir(dirp);
247 return d;
248}
249
250static object *
251posix_mkdir(self, args)
252 object *self;
253 object *args;
254{
255 extern int mkdir PROTO((const char *, mode_t));
256 return posix_strint(args, mkdir);
257}
258
259static object *
260posix_rename(self, args)
261 object *self;
262 object *args;
263{
264 extern int rename PROTO((const char *, const char *));
265 return posix_2str(args, rename);
266}
267
268static object *
269posix_rmdir(self, args)
270 object *self;
271 object *args;
272{
273 extern int rmdir PROTO((const char *));
274 return posix_1str(args, rmdir);
275}
276
277static object *
278posix_stat(self, args)
279 object *self;
280 object *args;
281{
282 extern int stat PROTO((const char *, struct stat *));
283 return posix_do_stat(self, args, stat);
284}
285
286static object *
287posix_system(self, args)
288 object *self;
289 object *args;
290{
291 object *command;
292 int sts;
293 if (!getstrarg(args, &command))
294 return NULL;
295 sts = system(getstringvalue(command));
296 return newintobject((long)sts);
297}
298
299static object *
300posix_umask(self, args)
301 object *self;
302 object *args;
303{
304 int i;
305 if (!getintarg(args, &i))
306 return NULL;
307 i = umask(i);
308 if (i < 0)
309 return posix_error();
310 return newintobject((long)i);
311}
312
313static object *
314posix_unlink(self, args)
315 object *self;
316 object *args;
317{
318 extern int unlink PROTO((const char *));
319 return posix_1str(args, unlink);
320}
321
322static object *
323posix_utimes(self, args)
324 object *self;
325 object *args;
326{
327 object *path;
328 struct timeval tv[2];
329 if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
330 err_badarg();
331 return NULL;
332 }
333 if (!getstrarg(gettupleitem(args, 0), &path) ||
334 !getlonglongargs(gettupleitem(args, 1),
335 &tv[0].tv_sec, &tv[1].tv_sec))
336 return NULL;
337 tv[0].tv_usec = tv[1].tv_usec = 0;
338 if (utimes(getstringvalue(path), tv) < 0)
339 return posix_error();
340 INCREF(None);
341 return None;
342}
343
344#ifdef NO_GETCWD
345
346/* Quick hack to get posix.getcwd() working for pure BSD 4.3 */
347/* XXX This assumes MAXPATHLEN = 1024 !!! */
348
349static char *
350getcwd(buf, size)
351 char *buf;
352 int size;
353{
354 extern char *getwd PROTO((char *));
355 register char *ret = getwd(buf);
356 if (ret == NULL)
357 errno = EACCES; /* Most likely error */
358 return ret;
359}
360
361#endif /* NO_GETCWD */
362
363
364#ifndef NO_LSTAT
365
366static object *
367posix_lstat(self, args)
368 object *self;
369 object *args;
370{
371 extern int lstat PROTO((const char *, struct stat *));
372 return posix_do_stat(self, args, lstat);
373}
374
375static object *
376posix_readlink(self, args)
377 object *self;
378 object *args;
379{
380 char buf[1024]; /* XXX Should use MAXPATHLEN */
381 object *path;
382 int n;
383 if (!getstrarg(args, &path))
384 return NULL;
385 n = readlink(getstringvalue(path), buf, sizeof buf);
386 if (n < 0)
387 return posix_error();
388 return newsizedstringobject(buf, n);
389}
390
391static object *
392posix_symlink(self, args)
393 object *self;
394 object *args;
395{
396 extern int symlink PROTO((const char *, const char *));
397 return posix_2str(args, symlink);
398}
399
400#endif /* NO_LSTAT */
401
402
403static struct methodlist posix_methods[] = {
404 {"chdir", posix_chdir},
405 {"chmod", posix_chmod},
406 {"getcwd", posix_getcwd},
407 {"link", posix_link},
408 {"listdir", posix_listdir},
409 {"mkdir", posix_mkdir},
410 {"rename", posix_rename},
411 {"rmdir", posix_rmdir},
412 {"stat", posix_stat},
413 {"system", posix_system},
414 {"umask", posix_umask},
415 {"unlink", posix_unlink},
416 {"utimes", posix_utimes},
417#ifndef NO_LSTAT
418 {"lstat", posix_lstat},
419 {"readlink", posix_readlink},
420 {"symlink", posix_symlink},
421#endif
422 {NULL, NULL} /* Sentinel */
423};
424
425
426void
427initposix()
428{
429 object *m, *d, *v;
430
431 m = initmodule("posix", posix_methods);
432 d = getmoduledict(m);
433
434 /* Initialize posix.environ dictionary */
435 v = convertenviron();
436 if (v == NULL || dictinsert(d, "environ", v) != 0)
437 fatal("can't define posix.environ");
438 DECREF(v);
439
440 /* Initialize posix.error exception */
441 PosixError = newstringobject("posix.error");
442 if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
443 fatal("can't define posix.error");
444}