/* native syscall replacements for system functions in l1 */ @include mapfile = @lambda(filename) { @local fd,st,p,r,s; fd=sys_open(filename,unix`O_RDONLY); if(0 > fd) { error("cannot open %s",filename); } st = (struct unix`stat *)malloc(sizeof(struct unix`stat)); if(!st) { error("couldn't allocate stat buf"); } if(0 > sys_fstat(fd,st)) { sys_close(fd); error("couldn't stat %s",filename); } if(S_ISBLK(st)) { @local sb,r; sb=(uint64 *)malloc(8); if(!sb) { error("malloc failure"); } *sb=0; if(looksym(unix,'BLKGETSIZE)) { r=sys_ioctl(fd, unix`BLKGETSIZE, sb); if(r) { error("couldn't determine size of block device %s", filename); } } else if(looksym(unix,'DKIOCGETBLOCKCOUNT)) { r=sys_ioctl(fd, unix`DKIOCGETBLOCKCOUNT, sb); if(r) { error("couldn't determine size of block device %s", filename); } } s=*sb * 512; } else { s = st->st_size; } p = sys_mmap(0, s, unix`PROT_READ|unix`PROT_WRITE, //unix`MAP_NORESERVE|unix`MAP_PRIVATE, fd, 0); unix`MAP_PRIVATE, fd, 0); if(p == -1) { // we can try with noreserve on a platform that supports it if(looksym(unix,'MAP_NORESERVE)) { p = sys_mmap(0, s, unix`PROT_READ|unix`PROT_WRITE, unix`MAP_NORESERVE|unix`MAP_PRIVATE, fd, 0); } } sys_close(fd); if(p == -1) error("could not map %s",filename); r=mkstrm(p, s); finalize(r,@lambda(args ...) { sys_munmap(p,s); nil; }); r; }; @global iohash; iohash=[:]; open = @lambda(filename, mode) { @local flags,fd,newmode,nfd; if(!isstring(filename)) error("open: filename is not a string"); if(!isstring(mode)) error("open: mode is not a string"); if(1 > strlen(mode)) error("open: mode cannot be empty"); if( ( strstr(mode,"r") && strstr(mode,"w") ) || ( strstr(mode,"r") && strstr(mode,"a") ) || ( strstr(mode,"w") && strstr(mode,"a") ) ) error("open: modes \"a\", \"w\", and \"r\" are exclusive"); flags = 0; switch(mode[0]) { case 'r': if(strstr(mode,"+")) flags = unix`O_RDWR; else flags = unix`O_RDONLY; break; case 'w': if(strstr(mode,"+")) flags = unix`O_RDWR | unix`O_CREAT | unix`O_TRUNC; else flags = unix`O_WRONLY | unix`O_CREAT | unix`O_TRUNC; break; case 'a': if(strstr(mode,"+")) flags = unix`O_RDWR | unix`O_CREAT | unix`O_APPEND; else flags = unix`O_WRONLY | unix`O_CREAT | unix`O_APPEND; break; default: error("open: invalid mode: %a",mode); } fd=sys_open(filename,flags,0777); if(0 > fd) { return nil; } newmode=""; if( ((flags & unix`O_WRONLY) == unix`O_WRONLY) || ((flags & unix`O_RDWR) == unix`O_RDWR) || ((flags & unix`O_APPEND) == unix`O_APPEND) ) newmode+="w"; if( ((flags & unix`O_RDONLY) == unix`O_RDONLY) || ((flags & unix`O_RDWR) == unix`O_RDWR) ) newmode+="r"; nfd=fdopen(fd,newmode); if(isnil(nfd)) { return nil; } else { @local k; k=weakcons(nfd,nil); iohash[k]=fd; finalize(nfd,@lambda(args ...) { tabdelete(iohash,k); sys_close(fd); }); return nfd; } }; seek = @lambda(fd,pos,whence) { @local sfd,r; sfd=iohash[cons(fd,nil)]; if(!isnil(sfd)) { r=sys_lseek(sfd,pos,whence); } else { error("seek: seeking a cinquecento fd with no unix fd"); } return r; }; close = @lambda(fd) { @local sfd; sfd=iohash[cons(fd,nil)]; if(!isnil(sfd)) { sys_close(sfd); } else { error("close: closing a cinquecento fd with no unix fd"); } }; unlink = sys_unlink; /* LINUX_REBOOT_CMD_RESTART RB_AUTOBOOT 0x1234567 */ /* LINUX_REBOOT_CMD_HALT RB_HALT_SYSTEM 0xcdef0123 */ /* LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc */ /* LINUX_REBOOT_CMD_RESTART2 0xa1b2c3d4 */ /* LINUX_REBOOT_CMD_CAD_ON RB_ENABLE_CAD 0x89abcdef */ /* LINUX_REBOOT_CMD_CAD_OFF RB_DISABLE_CAD, 0 */ reboot = @lambda(cmd) { return sys_reboot(0xfee1dead,672274793,cmd,0); }; /* why is this mmap so unlike mmap(2)? * why can it not map a file descriptor? * why can it not create a write-only mapping? * why does it not accept regions or offsets? * where is unmap? why does this wrapper not use * the collector strategy in mapfile? * why does it accept symbol modes when the * rest of the library subsystem accepts strings * in the manner of C buffered I/O? * why does it not close the fd if it opened it? * why does it return a zero-based as? * why is there no error checking? * * DSKR's proposal: Kill this function outright. * extend mapfile slightly to accept a string mode * in the manner of open. A new function called mmap * could be created as a convenience wrapper for sys_mmap. */ /* By default the region is mapped private read-only 'w: the region will be mapped writable 'x: the region will be mapped executable 'shared: the region is mapped shared. */ mmap = @lambda(filename,args...) { @local arghash,prot,flags,fd,res,l; //create a hash of the optional arguments for easy lookup arghash = [:]; foreach(@lambda(x) { arghash[x] = 1; },args); //open the fd appropriately fd = sys_open(filename,arghash['w] ? unix`O_RDWR : unix`O_RDONLY); prot = unix`PROT_READ; if (arghash['w]) prot |= unix`PROT_WRITE; if (arghash['x]) prot |= unix`PROT_EXEC; if (arghash['shared]) flags = unix`MAP_SHARED; else flags = unix`MAP_PRIVATE; l=malloc(sizeof(struct unix`stat)); sys_fstat(fd,l); l=(struct unix`stat*)l; res = sys_mmap(0,l->st_size,prot,flags,fd,0); return (void*){mkmas(res,l->st_size)}res; };