posixmodule.c revision 3b06619e1cbb2dfc4da4992bc648304e48af1701
1/*********************************************************** 2Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The 3Netherlands. 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#ifdef AMOEBA 28#define NO_LSTAT 29#define SYSV 30#endif 31 32#ifdef MSDOS 33#define NO_LSTAT 34#endif 35 36#include <signal.h> 37#include <string.h> 38#include <setjmp.h> 39#include <sys/types.h> 40#include <sys/stat.h> 41 42#ifdef SYSV 43 44#define UTIME_STRUCT 45#include <dirent.h> 46#define direct dirent 47#ifdef i386 48#define mode_t int 49#endif 50 51#else /* !SYSV */ 52 53#ifndef MSDOS 54#include <sys/dir.h> 55#endif 56 57#endif /* !SYSV */ 58 59#include "allobjects.h" 60#include "modsupport.h" 61 62extern char *strerror PROTO((int)); 63 64 65/* Return a dictionary corresponding to the POSIX environment table */ 66 67extern char **environ; 68 69static object * 70convertenviron() 71{ 72 object *d; 73 char **e; 74 d = newdictobject(); 75 if (d == NULL) 76 return NULL; 77 if (environ == NULL) 78 return d; 79 /* XXX This part ignores errors */ 80 for (e = environ; *e != NULL; e++) { 81 object *v; 82 char *p = strchr(*e, '='); 83 if (p == NULL) 84 continue; 85 v = newstringobject(p+1); 86 if (v == NULL) 87 continue; 88 *p = '\0'; 89 (void) dictinsert(d, *e, v); 90 *p = '='; 91 DECREF(v); 92 } 93 return d; 94} 95 96 97static object *PosixError; /* Exception posix.error */ 98 99/* Set a POSIX-specific error from errno, and return NULL */ 100 101static object * 102posix_error() 103{ 104 return err_errno(PosixError); 105} 106 107 108/* POSIX generic methods */ 109 110static object * 111posix_1str(args, func) 112 object *args; 113 int (*func) FPROTO((const char *)); 114{ 115 object *path1; 116 if (!getstrarg(args, &path1)) 117 return NULL; 118 if ((*func)(getstringvalue(path1)) < 0) 119 return posix_error(); 120 INCREF(None); 121 return None; 122} 123 124static object * 125posix_2str(args, func) 126 object *args; 127 int (*func) FPROTO((const char *, const char *)); 128{ 129 object *path1, *path2; 130 if (!getstrstrarg(args, &path1, &path2)) 131 return NULL; 132 if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0) 133 return posix_error(); 134 INCREF(None); 135 return None; 136} 137 138static object * 139posix_strint(args, func) 140 object *args; 141 int (*func) FPROTO((const char *, int)); 142{ 143 object *path1; 144 int i; 145 if (!getstrintarg(args, &path1, &i)) 146 return NULL; 147 if ((*func)(getstringvalue(path1), i) < 0) 148 return posix_error(); 149 INCREF(None); 150 return None; 151} 152 153static object * 154posix_do_stat(self, args, statfunc) 155 object *self; 156 object *args; 157 int (*statfunc) FPROTO((const char *, struct stat *)); 158{ 159 struct stat st; 160 object *path; 161 object *v; 162 if (!getstrarg(args, &path)) 163 return NULL; 164 if ((*statfunc)(getstringvalue(path), &st) != 0) 165 return posix_error(); 166 v = newtupleobject(10); 167 if (v == NULL) 168 return NULL; 169#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) 170 SET(0, st_mode); 171 SET(1, st_ino); 172 SET(2, st_dev); 173 SET(3, st_nlink); 174 SET(4, st_uid); 175 SET(5, st_gid); 176 SET(6, st_size); 177 SET(7, st_atime); 178 SET(8, st_mtime); 179 SET(9, st_ctime); 180#undef SET 181 if (err_occurred()) { 182 DECREF(v); 183 return NULL; 184 } 185 return v; 186} 187 188 189/* POSIX methods */ 190 191static object * 192posix_chdir(self, args) 193 object *self; 194 object *args; 195{ 196 extern int chdir PROTO((const char *)); 197 return posix_1str(args, chdir); 198} 199 200static object * 201posix_chmod(self, args) 202 object *self; 203 object *args; 204{ 205 extern int chmod PROTO((const char *, mode_t)); 206 return posix_strint(args, chmod); 207} 208 209static object * 210posix_getcwd(self, args) 211 object *self; 212 object *args; 213{ 214 char buf[1026]; 215 extern char *getcwd PROTO((char *, int)); 216 if (!getnoarg(args)) 217 return NULL; 218 if (getcwd(buf, sizeof buf) == NULL) 219 return posix_error(); 220 return newstringobject(buf); 221} 222 223#ifndef MSDOS 224static object * 225posix_link(self, args) 226 object *self; 227 object *args; 228{ 229 extern int link PROTO((const char *, const char *)); 230 return posix_2str(args, link); 231} 232#endif /* !MSDOS */ 233 234static object * 235posix_listdir(self, args) 236 object *self; 237 object *args; 238{ 239 object *name, *d, *v; 240 241#ifdef MSDOS 242 struct ffblk ep; 243 int rv; 244 if (!getstrarg(args, &name)) 245 return NULL; 246 247 if (findfirst((char *) getstringvalue(name), &ep, 0) == -1) 248 return posix_error(); 249 if ((d = newlistobject(0)) == NULL) 250 return NULL; 251 do { 252 v = newstringobject(ep.ff_name); 253 if (v == NULL) { 254 DECREF(d); 255 d = NULL; 256 break; 257 } 258 if (addlistitem(d, v) != 0) { 259 DECREF(v); 260 DECREF(d); 261 d = NULL; 262 break; 263 } 264 DECREF(v); 265 } while ((rv = findnext(&ep)) == 0); 266#else /* !MSDOS */ 267 DIR *dirp; 268 struct direct *ep; 269 if (!getstrarg(args, &name)) 270 return NULL; 271 if ((dirp = opendir(getstringvalue(name))) == NULL) 272 return posix_error(); 273 if ((d = newlistobject(0)) == NULL) { 274 closedir(dirp); 275 return NULL; 276 } 277 while ((ep = readdir(dirp)) != NULL) { 278 v = newstringobject(ep->d_name); 279 if (v == NULL) { 280 DECREF(d); 281 d = NULL; 282 break; 283 } 284 if (addlistitem(d, v) != 0) { 285 DECREF(v); 286 DECREF(d); 287 d = NULL; 288 break; 289 } 290 DECREF(v); 291 } 292 closedir(dirp); 293#endif /* !MSDOS */ 294 295 return d; 296} 297 298static object * 299posix_mkdir(self, args) 300 object *self; 301 object *args; 302{ 303 extern int mkdir PROTO((const char *, mode_t)); 304 return posix_strint(args, mkdir); 305} 306 307#ifdef i386 308int 309rename(from, to) 310 char *from; 311 char *to; 312{ 313 int status; 314 /* XXX Shouldn't this unlink the destination first? */ 315 status = link(from, to); 316 if (status != 0) 317 return status; 318 return unlink(from); 319} 320#endif /* i386 */ 321 322static object * 323posix_rename(self, args) 324 object *self; 325 object *args; 326{ 327 extern int rename PROTO((const char *, const char *)); 328 return posix_2str(args, rename); 329} 330 331static object * 332posix_rmdir(self, args) 333 object *self; 334 object *args; 335{ 336 extern int rmdir PROTO((const char *)); 337 return posix_1str(args, rmdir); 338} 339 340static object * 341posix_stat(self, args) 342 object *self; 343 object *args; 344{ 345 extern int stat PROTO((const char *, struct stat *)); 346 return posix_do_stat(self, args, stat); 347} 348 349static object * 350posix_system(self, args) 351 object *self; 352 object *args; 353{ 354 object *command; 355 int sts; 356 if (!getstrarg(args, &command)) 357 return NULL; 358 sts = system(getstringvalue(command)); 359 return newintobject((long)sts); 360} 361 362#ifndef MSDOS 363static object * 364posix_umask(self, args) 365 object *self; 366 object *args; 367{ 368 int i; 369 if (!getintarg(args, &i)) 370 return NULL; 371 i = umask(i); 372 if (i < 0) 373 return posix_error(); 374 return newintobject((long)i); 375} 376#endif /* !MSDOS */ 377 378static object * 379posix_unlink(self, args) 380 object *self; 381 object *args; 382{ 383 extern int unlink PROTO((const char *)); 384 return posix_1str(args, unlink); 385} 386 387#ifdef UTIME_STRUCT 388#include <utime.h> 389#endif 390 391static object * 392posix_utime(self, args) 393 object *self; 394 object *args; 395{ 396 object *path; 397 398#ifdef UTIME_STRUCT 399 struct utimbuf buf; 400#define ATIME buf.actime 401#define MTIME buf.modtime 402#define UTIME_ARG &buf 403 404#else 405 time_t buf[2]; 406#define ATIME buf[0] 407#define MTIME buf[1] 408#define UTIME_ARG buf 409#endif 410 411 if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { 412 err_badarg(); 413 return NULL; 414 } 415 if (!getstrarg(gettupleitem(args, 0), &path) || 416 !getlonglongargs(gettupleitem(args, 1), &ATIME, &MTIME)) 417 return NULL; 418 if (utime(getstringvalue(path), UTIME_ARG) < 0) 419 return posix_error(); 420 INCREF(None); 421 return None; 422#undef UTIME_ARG 423#undef ATIME 424#undef MTIME 425} 426 427 428#ifndef MSDOS 429 430/* Process operations */ 431 432static object * 433posix__exit(self, args) 434 object *self; 435 object *args; 436{ 437 int sts; 438 if (!getintarg(args, &sts)) 439 return NULL; 440 _exit(sts); 441 /* NOTREACHED */ 442} 443 444/* XXX To do: exece, execp */ 445 446static object * 447posix_exec(self, args) 448 object *self; 449 object *args; 450{ 451 object *path, *argv; 452 char **argvlist; 453 int i, argc; 454 object *(*getitem) PROTO((object *, int)); 455 456 /* exec has two arguments: (path, argv), where 457 argv is a list or tuple of strings. */ 458 459 if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { 460 badarg: 461 err_badarg(); 462 return NULL; 463 } 464 if (!getstrarg(gettupleitem(args, 0), &path)) 465 return NULL; 466 argv = gettupleitem(args, 1); 467 if (argv == NULL) 468 goto badarg; 469 if (is_listobject(argv)) { 470 argc = getlistsize(argv); 471 getitem = getlistitem; 472 } 473 else if (is_tupleobject(argv)) { 474 argc = gettuplesize(argv); 475 getitem = gettupleitem; 476 } 477 else 478 goto badarg; 479 480 argvlist = NEW(char *, argc+1); 481 if (argvlist == NULL) 482 return NULL; 483 for (i = 0; i < argc; i++) { 484 object *arg; 485 if (!getstrarg((*getitem)(argv, i), &arg)) { 486 DEL(argvlist); 487 goto badarg; 488 } 489 argvlist[i] = getstringvalue(arg); 490 } 491 argvlist[argc] = NULL; 492 493 execv(getstringvalue(path), argvlist); 494 495 /* If we get here it's definitely an error */ 496 497 DEL(argvlist); 498 return posix_error(); 499} 500 501static object * 502posix_fork(self, args) 503 object *self; 504 object *args; 505{ 506 int pid; 507 pid = fork(); 508 if (pid == -1) 509 return posix_error(); 510 return newintobject((long)pid); 511} 512 513static object * 514posix_getpid(self, args) 515 object *self; 516 object *args; 517{ 518 if (!getnoarg()) 519 return NULL; 520 return newintobject((long)getpid()); 521} 522 523static object * 524posix_getppid(self, args) 525 object *self; 526 object *args; 527{ 528 if (!getnoarg()) 529 return NULL; 530 return newintobject((long)getppid()); 531} 532 533static object * 534posix_kill(self, args) 535 object *self; 536 object *args; 537{ 538 int pid, sig; 539 if (!getintintarg(args, &pid, &sig)) 540 return NULL; 541 if (kill(pid, sig) == -1) 542 return posix_error(); 543 INCREF(None); 544 return None; 545} 546 547static object * 548posix_popen(self, args) 549 object *self; 550 object *args; 551{ 552 extern int pclose PROTO((FILE *)); 553 object *name, *mode; 554 FILE *fp; 555 if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2 || 556 !is_stringobject(name = gettupleitem(args, 0)) || 557 !is_stringobject(mode = gettupleitem(args, 1))) { 558 err_setstr(TypeError, "open() requires 2 string arguments"); 559 return NULL; 560 } 561 fp = popen(getstringvalue(name), getstringvalue(mode)); 562 if (fp == NULL) 563 return posix_error(); 564 return newopenfileobject(fp, name, mode, pclose); 565} 566 567static object * 568posix_wait(self, args) /* Also waitpid() */ 569 object *self; 570 object *args; 571{ 572 object *v; 573 int pid, sts; 574 if (args == NULL) 575 pid = wait(&sts); 576 else { 577#ifdef NO_WAITPID 578 err_setstr(RuntimeError, 579 "posix.wait(pid, options) not supported on this system"); 580#else 581 int options; 582 if (!getintintarg(args, &pid, &options)) 583 return NULL; 584 pid = waitpid(pid, &sts, options); 585#endif 586 } 587 if (pid == -1) 588 return posix_error(); 589 v = newtupleobject(2); 590 if (v != NULL) { 591 settupleitem(v, 0, newintobject((long)pid)); 592 settupleitem(v, 1, newintobject((long)sts)); 593 if (err_occurred()) { 594 DECREF(v); 595 v = NULL; 596 } 597 } 598 return v; 599} 600 601#endif /* MSDOS */ 602 603#ifndef NO_LSTAT 604 605static object * 606posix_lstat(self, args) 607 object *self; 608 object *args; 609{ 610 extern int lstat PROTO((const char *, struct stat *)); 611 return posix_do_stat(self, args, lstat); 612} 613 614static object * 615posix_readlink(self, args) 616 object *self; 617 object *args; 618{ 619 char buf[1024]; /* XXX Should use MAXPATHLEN */ 620 object *path; 621 int n; 622 if (!getstrarg(args, &path)) 623 return NULL; 624 n = readlink(getstringvalue(path), buf, sizeof buf); 625 if (n < 0) 626 return posix_error(); 627 return newsizedstringobject(buf, n); 628} 629 630static object * 631posix_symlink(self, args) 632 object *self; 633 object *args; 634{ 635 extern int symlink PROTO((const char *, const char *)); 636 return posix_2str(args, symlink); 637} 638 639#endif /* NO_LSTAT */ 640 641 642static struct methodlist posix_methods[] = { 643 {"chdir", posix_chdir}, 644 {"chmod", posix_chmod}, 645 {"getcwd", posix_getcwd}, 646#ifndef MSDOS 647 {"link", posix_link}, 648#endif 649 {"listdir", posix_listdir}, 650 {"mkdir", posix_mkdir}, 651 {"rename", posix_rename}, 652 {"rmdir", posix_rmdir}, 653 {"stat", posix_stat}, 654 {"system", posix_system}, 655#ifndef MSDOS 656 {"umask", posix_umask}, 657#endif 658 {"unlink", posix_unlink}, 659 {"utime", posix_utime}, 660#ifndef MSDOS 661 {"_exit", posix__exit}, 662 {"exec", posix_exec}, 663 {"fork", posix_fork}, 664 {"getpid", posix_getpid}, 665 {"getppid", posix_getppid}, 666 {"kill", posix_kill}, 667 {"popen", posix_popen}, 668 {"wait", posix_wait}, 669#endif 670#ifndef NO_LSTAT 671 {"lstat", posix_lstat}, 672 {"readlink", posix_readlink}, 673 {"symlink", posix_symlink}, 674#endif 675 {NULL, NULL} /* Sentinel */ 676}; 677 678 679void 680initposix() 681{ 682 object *m, *d, *v; 683 684 m = initmodule("posix", posix_methods); 685 d = getmoduledict(m); 686 687 /* Initialize posix.environ dictionary */ 688 v = convertenviron(); 689 if (v == NULL || dictinsert(d, "environ", v) != 0) 690 fatal("can't define posix.environ"); 691 DECREF(v); 692 693 /* Initialize posix.error exception */ 694 PosixError = newstringobject("posix.error"); 695 if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0) 696 fatal("can't define posix.error"); 697} 698 699 700/* Function used elsewhere to get a file's modification time */ 701 702long 703getmtime(path) 704 char *path; 705{ 706 struct stat st; 707 if (stat(path, &st) != 0) 708 return -1; 709 else 710 return st.st_mtime; 711} 712 713 714#ifdef MSDOS 715 716/* A small "compatibility library" for TurboC under MS-DOS */ 717 718#include <sir.h> 719#include <io.h> 720#include <dos.h> 721#include <fcntl.h> 722 723int 724chmod(path, mode) 725 char *path; 726 int mode; 727{ 728 return _chmod(path, 1, mode); 729} 730 731int 732utime(path, times) 733 char *path; 734 time_t times[2]; 735{ 736 struct date dt; 737 struct time tm; 738 struct ftime dft; 739 int fh; 740 unixtodos(tv[0].tv_sec,&dt,&tm); 741 dft.ft_tsec = tm.ti_sec; dft.ft_min = tm.ti_min; 742 dft.ft_hour = tm.ti_hour; dft.ft_day = dt.da_day; 743 dft.ft_month = dt.da_mon; 744 dft.ft_year = (dt.da_year - 1980); /* this is for TC library */ 745 746 if ((fh = open(getstringvalue(path),O_RDWR)) < 0) 747 return posix_error(); /* can't open file to set time */ 748 if (setftime(fh,&dft) < 0) 749 { 750 close(fh); 751 return posix_error(); 752 } 753 close(fh); /* close the temp handle */ 754} 755 756#endif /* MSDOS */ 757