Size readBootSymbols(char *prog, char *file, Vector<BootEntry *> *entries) { char line[128]; Size num = MAX_REGIONS; Size totalBytes = 0, totalEntries = 0; BootEntry *entry; FILE *fp; ExecutableFormat *format; /* Open configuration file. */ if ((fp = fopen(file, "r")) == NULL) { fprintf(stderr, "%s: failed to open `%s': %s\n", prog, file, strerror(errno)); exit(EXIT_FAILURE); } /* Read out lines. */ while (fgets(line, sizeof(line), fp) != NULL) { /* Clear newline. */ line[strlen(line) - 1] = 0; /* Allocate new boot entry. */ entry = new BootEntry; strncpy(entry->symbol.name, line, BOOTIMAGE_NAMELEN); // Find the file struct stat st; if (stat(line, &st) == -1) { fprintf(stderr, "%s: failed to stat `%s': %s\n", prog, line, strerror(errno)); exit(EXIT_FAILURE); } // Allocate buffer u8 *buffer = new u8[st.st_size]; // Read the file FILE *entry_fd = fopen(line, "r"); if (!entry_fd) { fprintf(stderr, "%s: failed to open `%s': %s\n", prog, line, strerror(errno)); exit(EXIT_FAILURE); } if (fread(buffer, st.st_size, 1, entry_fd) != 1) { fprintf(stderr, "%s: failed to fread `%s': %s\n", prog, line, strerror(errno)); exit(EXIT_FAILURE); } fclose(entry_fd); // Try to parse as BootProgram using libexec. if (ExecutableFormat::find(buffer, st.st_size, &format) == ExecutableFormat::Success) { // Extract memory regions if (format->regions(entry->regions, &num) != ExecutableFormat::Success || num <= 0) { fprintf(stderr, "%s: failed to extract memory regions from `%s': %s\n", prog, line, strerror(errno)); exit(EXIT_FAILURE); } entry->numRegions = num; entry->symbol.type = BootProgram; format->entry((Address *)&entry->symbol.entry); } // BootData else { // Fill BootEntry entry->symbol.type = BootData; entry->numRegions = 1; entry->regions[0].virt = 0; entry->regions[0].access = Memory::User | Memory::Readable | Memory::Writable; entry->regions[0].size = st.st_size; entry->regions[0].data = buffer; } // Insert into Array entries->insert(entry); totalEntries++; /* Debug out memory sections. */ for (Size i = 0; i < entry->numRegions; i++) { printf("%s[%u]: vaddr=%x size=%u\n", line, i, (uint) entry->regions[i].virt, entry->regions[i].size); totalBytes += entry->regions[i].size; } } /* All done. */ printf("%d entries, %d bytes total\n", totalEntries, totalBytes); return totalEntries; }
int forkexec(const char *path, const char *argv[]) { CoreMessage msg; ExecutableFormat *fmt; MemoryRegion regions[16]; Memory::Range range; uint count = 0; pid_t pid = 0; int numRegions = 0; Vector<FileDescriptor> *fds = getFiles(); // Attempt to read executable format if (!(fmt = ExecutableFormat::find(path))) return -1; // Retrieve memory regions if ((numRegions = fmt->regions(regions, 16)) < 0) return -1; // Create new process pid = ProcessCtl(ANY, Spawn, fmt->entry()); // TODO: check the result of ProcessCtl() // TODO: make this much more efficient. perhaps let libexec write directly to the target buffer. // at least Map & copy in one shot. // TODO: move the memory administration updates to coreserver instead. // this process can read the libexec data once, and then let coreserver create a process for it. // Map program regions into virtual memory of the new process for (int i = 0; i < numRegions; i++) { // Copy executable memory from this region range.virt = regions[i].virtualAddress; range.phys = ZERO; range.size = regions[i].size; range.access = Memory::Present | Memory::User | Memory::Readable | Memory::Writable | Memory::Executable; // Create mapping first if (VMCtl(pid, Map, &range) != 0) { // TODO: convert from API::Error to errno. errno = EFAULT; return -1; } // Copy bytes VMCopy(pid, API::Write, (Address) regions[i].data, regions[i].virtualAddress, regions[i].size); } /* Create mapping for command-line arguments. */ range.virt = ARGV_ADDR; range.phys = ZERO; range.size = PAGESIZE; VMCtl(pid, Map, &range); // Allocate arguments char *arguments = new char[PAGESIZE]; memset(arguments, 0, PAGESIZE); // Fill in arguments while (argv[count] && count < PAGESIZE / ARGV_SIZE) { strlcpy(arguments + (ARGV_SIZE * count), argv[count], ARGV_SIZE); count++; } // Copy argc/argv into the new process if ((VMCopy(pid, API::Write, (Address) arguments, (Address) ARGV_ADDR, PAGESIZE)) < 0) { delete arguments; errno = EFAULT; return -1; } // Let the Child begin execution ProcessCtl(pid, Resume); // Send a pointer to our list of file descriptors to the child // TODO: ofcourse, insecure. To be fixed later. msg.type = IPCType; msg.from = SELF; msg.path = (char *) fds->vector(); IPCMessage(pid, API::SendReceive, &msg, sizeof(msg)); // Done. Cleanup. delete arguments; return pid; }
void ProcessServer::spawnProcessHandler(ProcessMessage *msg) { char path[PATHLEN], *tmp; FileSystemMessage fs; ExecutableFormat *fmt; MemoryRegion regions[16]; MemoryRange range; Error numRegions, ret; Size size; ProcessID pid; Shared<FileDescriptor> *parentFd, *childFd; /* Read out the path to the executable. */ if ((msg->result = VMCopy(msg->from, Read, (Address) path, (Address) msg->path, PATHLEN) < 0)) { return; } /* Attempt to read executable format. */ if (!(fmt = ExecutableFormat::find(path))) { msg->result = errno; return; } /* Retrieve memory regions. */ if ((numRegions = fmt->regions(regions, 16)) < 0) { msg->result = errno; return; } /* Create new process. */ pid = ProcessCtl(ANY, Spawn, fmt->entry()); /* Map program regions into virtual memory of the new process. */ for (int i = 0; i < numRegions; i++) { /* Copy executable memory from this region. */ for (Size j = 0; j < regions[i].size; j += PAGESIZE) { range.virtualAddress = regions[i].virtualAddress + j; range.physicalAddress = ZERO; range.bytes = PAGESIZE; /* Create mapping first. */ if ((ret = VMCtl(pid, Map, &range)) != 0) { msg->result = ret; return; } /* Copy bytes. */ VMCopy(pid, Write, (Address) (regions[i].data) + j, regions[i].virtualAddress + j, PAGESIZE); } } /* Create mapping for command-line arguments. */ range.virtualAddress = ARGV_ADDR; range.physicalAddress = ZERO; range.bytes = PAGESIZE; VMCtl(pid, Map, &range); /* Allocate temporary variable. */ tmp = new char[PAGESIZE]; memset(tmp, 0, PAGESIZE); /* Calculate number of bytes to copy. */ size = msg->number * ARGV_SIZE < PAGESIZE ? msg->number * ARGV_SIZE : PAGESIZE; /* Copy arguments into the temporary variable. */ if ((msg->result = VMCopy(msg->from, Read, (Address) tmp, (Address) msg->arguments, size)) < 0) { delete tmp; return; } /* Copy argc/argv into the new process. */ if ((msg->result = VMCopy(pid, Write, (Address) tmp, (Address) ARGV_ADDR, PAGESIZE)) < 0) { delete tmp; return; } /* Set command-line string. */ snprintf(procs[pid]->command, COMMANDLEN, "%s", path); /* Copy the FileDescriptor table. */ parentFd = getFileDescriptors(files, msg->from); childFd = getFileDescriptors(files, pid); memcpy(**childFd, **parentFd, childFd->size()); /* Inherit user and group identities. */ procs[pid]->userID = procs[msg->from]->userID; procs[pid]->groupID = procs[msg->from]->groupID; strncpy(procs[pid]->currentDirectory, procs[msg->from]->currentDirectory, PATHLEN); /* Begin execution. */ ProcessCtl(pid, Resume); /* Success. */ msg->number = pid; msg->result = ESUCCESS; /* Cleanup. */ delete fmt; delete tmp; }