Esempio n. 1
0
// Open a directory for scanning.
// For simplicity, DIR is simply a filedesc like other file descriptors,
// except we interpret fd->ofs as an inode number for scanning,
// instead of as a byte offset as in a regular file.
DIR *opendir(const char *path)
{
	filedesc *fd = filedesc_open(NULL, path, O_RDONLY, 0);
	if (fd == NULL)
		return NULL;

	// Make sure it's a directory
	assert(fileino_exists(fd->ino));
	fileinode *fi = &files->fi[fd->ino];
	if (!S_ISDIR(fi->mode)) {
		filedesc_close(fd);
		errno = ENOTDIR;
		return NULL;
	}

	return fd;
}
Esempio n. 2
0
int
open(const char *path, int flags, ...)
{
	// Get the optional mode argument, which applies only with O_CREAT.
	mode_t mode = 0;
	if (flags & O_CREAT) {
		va_list ap;
		va_start(ap, flags);
		mode = va_arg(ap, mode_t);
		va_end(ap);
	}

	filedesc *fd = filedesc_open(NULL, path, flags, mode);
	if (fd == NULL)
		return -1;

	return fd - files->fd;
}
Esempio n. 3
0
FILE *
freopen(const char *path, const char *mode, FILE *fd)
{
	assert(filedesc_isvalid(fd));
	if (filedesc_isopen(fd))
		fclose(fd);

	// Parse the open mode string
	int flags;
	switch (*mode++) {
	case 'r':	flags = O_RDONLY; break;
	case 'w':	flags = O_WRONLY | O_CREAT | O_TRUNC; break;
	case 'a':	flags = O_WRONLY | O_CREAT | O_APPEND; break;
	default:	panic("freopen: unknown file mode '%c'\n", *--mode);
	}
	if (*mode == 'b')	// binary flag - compatibility only
		mode++;
	if (*mode == '+')
		flags |= O_RDWR;

	if (filedesc_open(fd, path, flags, 0666) != fd)
		return NULL;
	return fd;
}
Esempio n. 4
0
int
exec_readelf(const char *path)
{
	// We'll load the ELF image into a scratch area in our address space.
	sys_get(SYS_ZERO, 0, NULL, NULL, (void*)VM_SCRATCHLO, EXEMAX);

	// Open the ELF image to load.
	filedesc *fd = filedesc_open(NULL, path, O_RDONLY, 0);
	if (fd == NULL)
		return -1;
	void *imgdata = FILEDATA(fd->ino);
	size_t imgsize = files->fi[fd->ino].size;

	// Make sure it looks like an ELF image.
	elfhdr *eh = imgdata;
	if (imgsize < sizeof(*eh) || eh->e_magic != ELF_MAGIC) {
		warn("exec_readelf: ELF header not found");
		goto err;
	}

	// Load each program segment into the scratch area
	proghdr *ph = imgdata + eh->e_phoff;
	proghdr *eph = ph + eh->e_phnum;
	if (imgsize < (void*)eph - imgdata) {
		warn("exec_readelf: ELF program header truncated");
		goto err;
	}
	for (; ph < eph; ph++) {
		if (ph->p_type != ELF_PROG_LOAD)
			continue;

		// The executable should fit in the first 4MB of user space.
		intptr_t valo = ph->p_va;
		intptr_t vahi = valo + ph->p_memsz;
		if (valo < VM_USERLO || valo > VM_USERLO+EXEMAX ||
				vahi < valo || vahi > VM_USERLO+EXEMAX) {
			warn("exec_readelf: executable image too large "
				"(%d bytes > %d max)", vahi-valo, EXEMAX);
			goto err;
		}

		// Map all pages the segment touches in our scratch region.
		// They've already been zeroed by the SYS_ZERO above.
		intptr_t scratchofs = VM_SCRATCHLO - VM_USERLO;
		intptr_t pagelo = ROUNDDOWN(valo, PAGESIZE);
		intptr_t pagehi = ROUNDUP(vahi, PAGESIZE);
		sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL,
			(void*)pagelo + scratchofs, pagehi - pagelo);

		// Initialize the file-loaded part of the ELF image.
		// (We could use copy-on-write if SYS_COPY
		// supports copying at arbitrary page boundaries.)
		intptr_t filelo = ph->p_offset;
		intptr_t filehi = filelo + ph->p_filesz;
		if (filelo < 0 || filelo > imgsize
				|| filehi < filelo || filehi > imgsize) {
			warn("exec_readelf: loaded section out of bounds");
			goto err;
		}
		memcpy((void*)valo + scratchofs, imgdata + filelo,
			filehi - filelo);

		// Finally, remove write permissions on read-only segments.
		if (!(ph->p_flags & ELF_PROG_FLAG_WRITE))
			sys_get(SYS_PERM | SYS_READ, 0, NULL, NULL,
				(void*)pagelo + scratchofs, pagehi - pagelo);
	}

	// Copy the ELF image into its correct position in child 0.
	sys_put(SYS_COPY, 0, NULL, (void*)VM_SCRATCHLO,
		(void*)VM_USERLO, EXEMAX);

	// The new program should have the same entrypoint as we do!
	if (eh->e_entry != (intptr_t)start) {
		warn("exec_readelf: executable has a different start address");
		goto err;
	}

	filedesc_close(fd);	// Done with the ELF file
	return 0;

err:
	filedesc_close(fd);
	return -1;
}