/** \brief Argument parser for argp. * * \note See argp parser documentation for detailed information about the * structure and functionality of function. */ static error_t parse_arguments(int key, char *arg, struct argp_state *state) { switch (key) { case 'c': setenv("PNMPI_CONF", arg, 1); break; case 'd': set_dbglevel(state, arg); break; case 'm': appendenv("PNMPI_LIB_PATH", arg, 1); break; case 'n': setenv("PNMPI_DBGNODE", arg, 1); break; case 'q': case 's': setenv("PNMPI_BE_SILENT", "1", 1); break; #ifdef ENABLE_FORTRAN case 'f': preload_library(PNMPI_FORTRAN_LIBRARY_NAME); pnmpi_library_loaded = 1; break; #endif /* If we have parsed all options, iterate through all non-options in argv. * If at there are no non-options in our arguments (argv), the user * specified no utility to call, so we'll print the argp usage here, which * will exit pnmpize immediately after printing the usage message. */ case ARGP_KEY_END: if (state->arg_num == 0) argp_usage(state); break; default: return ARGP_ERR_UNKNOWN; } return 0; }
int main(int argc, char **argv) { /* Parse our arguments: Options will be parsed until the first non-option is * found. Parsed arguments will manipulate the current environment to * initialize it for use with P^nMPI. If there are no additional non-options * in our arguments, argp_parse will print the usage message and exit * immediately, no extra evaluation is required here. The index of the first * non-option will be stored in ind. */ int ind; argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &ind, NULL); /* Load the PnMPI core (i.e. the C-interface and the configuration logic). * * NOTE: If PnMPI gets splitted into a core implementation (i.e. the current C * interface) and additional language-specific wrappers redirecting to * the C-interface only, just remove the if-clause and everything should * be fine.*/ if (!pnmpi_library_loaded) { preload_library(PNMPI_LIBRARY_NAME); pnmpi_library_loaded = 1; } /* Execute the utility. If the utility could be started, PnMPIze will exit * here. In any other case, the following error processing will be called. */ if (execvp(argv[ind], argv + ind) < 0) { fprintf(stderr, "Could not execute %s: %s\n", argv[ind], strerror(errno)); return EXIT_FAILURE; } }
static int load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok) { COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */ COFF_SCNHDR *sect_bufr; /* Pointer to section table */ COFF_SCNHDR *text_sect; /* Pointer to the text section */ COFF_SCNHDR *data_sect; /* Pointer to the data section */ COFF_SCNHDR *bss_sect; /* Pointer to the bss section */ int text_count; /* Number of text sections */ int data_count; /* Number of data sections */ int bss_count; /* Number of bss sections */ int lib_count; /* Number of lib sections */ unsigned int start_addr = 0;/* Starting location for program */ int status = 0; /* Result status register */ int fd = -1; /* Open file descriptor */ struct file *fp = NULL; /* Pointer to the file at "fd" */ short int sections = 0; /* Number of sections in the file */ short int aout_size = 0; /* Size of the a.out header area */ short int flags; /* Flag bits from the COFF header */ #ifdef COFF_DEBUG printk ("binfmt_coff entry: %s\n", bprm->filename); #endif /* * Validate the magic value for the object file. */ do { if (COFF_I386BADMAG (*coff_hdr)) { #ifdef COFF_DEBUG printk ("bad filehdr magic\n"); #endif status = -ENOEXEC; break; } /* * The object file should have 32 BIT little endian format. Do not allow * it to have the 16 bit object file flag set as Linux is not able to run * on the 80286/80186/8086. */ flags = COFF_SHORT (coff_hdr->f_flags); if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) { #ifdef COFF_DEBUG printk ("invalid f_flags bits\n"); #endif status = -ENOEXEC; break; } /* * Extract the header information which we need. */ sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */ aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */ /* * If the file is not executable then reject the execution. This means * that there must not be external references. */ if ((flags & COFF_F_EXEC) == 0) { #ifdef COFF_DEBUG printk ("not executable bit\n"); #endif status = -ENOEXEC; break; } /* * There must be at least one section. */ if (sections == 0) { #ifdef COFF_DEBUG printk ("no sections\n"); #endif status = -ENOEXEC; break; } /* * Do some additional consistency checks. * The system requires mapping for this loader. If you try * to use a file system with no mapping, the format is not valid. */ if (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops->mmap) { #ifdef COFF_DEBUG printk ("no mmap in fs\n"); #endif status = -ENOEXEC; } } while (0); /* * Allocate a buffer to hold the entire coff section list. */ if (status >= 0) { int nbytes = sections * COFF_SCNHSZ; sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL); if (0 == sect_bufr) { #ifdef COFF_DEBUG printk ("kmalloc failed\n"); #endif status = -ENOEXEC; } /* * Read the section list from the disk file. */ else { int old_fs = get_fs (); set_fs (get_ds ()); /* Make it point to the proper location */ status = read_exec (bprm->inode, /* INODE for file */ aout_size + COFF_FILHSZ, /* Offset in the file */ (char *) sect_bufr, /* Buffer for read */ nbytes); /* Byte count reqd. */ set_fs (old_fs); /* Restore the selector */ #ifdef COFF_DEBUG if (status < 0) printk ("read aout hdr, status = %d\n", status); #endif } } else sect_bufr = NULL; /* Errors do not have a section buffer */ /* * Count the number of sections for the required types and store the location * of the last section for the three primary types. */ text_count = 0; data_count = 0; bss_count = 0; lib_count = 0; text_sect = NULL; data_sect = NULL; bss_sect = NULL; /* * Loop through the sections and find the various types */ if (status >= 0) { int nIndex; COFF_SCNHDR *sect_ptr = sect_bufr; for (nIndex = 0; nIndex < sections; ++nIndex) { long int sect_flags = COFF_LONG (sect_ptr->s_flags); switch (sect_flags) { case COFF_STYP_TEXT: text_sect = sect_ptr; ++text_count; status = is_properly_aligned (sect_ptr); break; case COFF_STYP_DATA: data_sect = sect_ptr; ++data_count; status = is_properly_aligned (sect_ptr); break; case COFF_STYP_BSS: bss_sect = sect_ptr; ++bss_count; break; case COFF_STYP_LIB: #ifdef COFF_DEBUG printk (".lib section found\n"); #endif ++lib_count; break; default: break; } sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ]; } /* * Ensure that there are the required sections. There must be one text * sections and one each of the data and bss sections for an executable. * A library may or may not have a data / bss section. */ if (text_count != 1) { status = -ENOEXEC; #ifdef COFF_DEBUG printk ("no text sections\n"); #endif } else { if (lib_ok) { if (data_count != 1 || bss_count != 1) { status = -ENOEXEC; #ifdef COFF_DEBUG printk ("no .data nor .bss sections\n"); #endif } } } } /* * If there is no additional header then assume the file starts at * the first byte of the text section. This may not be the proper place, * so the best solution is to include the optional header. A shared library * __MUST__ have an optional header to indicate that it is a shared library. */ if (status >= 0) { if (aout_size == 0) { if (!lib_ok) { status = -ENOEXEC; #ifdef COFF_DEBUG printk ("no header in library\n"); #endif } start_addr = COFF_LONG (text_sect->s_vaddr); } /* * There is some header. Ensure that it is sufficient. */ else { if (aout_size < COFF_AOUTSZ) { status = -ENOEXEC; #ifdef COFF_DEBUG printk ("header too small\n"); #endif } else { COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */ (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ]; short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */ /* * Validate the magic number in the a.out header. If it is valid then * update the starting symbol location. Do not accept these file formats * when loading a shared library. */ switch (aout_magic) { case COFF_OMAGIC: case COFF_ZMAGIC: case COFF_STMAGIC: if (!lib_ok) { status = -ENOEXEC; #ifdef COFF_DEBUG printk ("wrong a.out header magic\n"); #endif } start_addr = (unsigned int) COFF_LONG (aout_hdr->entry); break; /* * Magic value for a shared library. This is valid only when loading a * shared library. (There is no need for a start_addr. It won't be used.) */ case COFF_SHMAGIC: if (lib_ok) { #ifdef COFF_DEBUG printk ("wrong a.out header magic\n"); #endif status = -ENOEXEC; } break; default: #ifdef COFF_DEBUG printk ("wrong a.out header magic\n"); #endif status = -ENOEXEC; break; } } } } /* * Fetch a file pointer to the executable. */ if (status >= 0) { fd = open_inode (bprm->inode, O_RDONLY); if (fd < 0) { #ifdef COFF_DEBUG printk ("can not open inode, result = %d\n", fd); #endif status = fd; } else fp = current->files->fd[fd]; } else fd = -1; /* Invalidate the open file descriptor */ /* * Generate the proper values for the text fields * * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD. */ if (status >= 0) { long text_scnptr = COFF_LONG (text_sect->s_scnptr); long text_size = COFF_LONG (text_sect->s_size); long text_vaddr = COFF_LONG (text_sect->s_vaddr); long data_scnptr; long data_size; long data_vaddr; long bss_size; long bss_vaddr; /* * Generate the proper values for the data fields */ if (data_sect != NULL) { data_scnptr = COFF_LONG (data_sect->s_scnptr); data_size = COFF_LONG (data_sect->s_size); data_vaddr = COFF_LONG (data_sect->s_vaddr); } else { data_scnptr = 0; data_size = 0; data_vaddr = 0; } /* * Generate the proper values for the bss fields */ if (bss_sect != NULL) { bss_size = COFF_LONG (bss_sect->s_size); bss_vaddr = COFF_LONG (bss_sect->s_vaddr); } else { bss_size = 0; bss_vaddr = 0; } /* * Flush the executable from memory. At this point the executable is * committed to being defined or a segmentation violation will occur. */ if (lib_ok) { #ifdef COFF_DEBUG printk ("flushing executable\n"); #endif flush_old_exec (bprm); /* * Define the initial locations for the various items in the new process */ current->mm->mmap = NULL; current->mm->rss = 0; /* * Construct the parameter and environment string table entries. */ bprm->p += change_ldt (0, bprm->page); bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; bprm->p = (unsigned long) create_tables ((char *) bprm->p, bprm->argc, bprm->envc, 1); /* * Do the end processing once the stack has been constructed */ current->mm->start_code = text_vaddr & PAGE_MASK; current->mm->end_code = text_vaddr + text_size; current->mm->end_data = data_vaddr + data_size; current->mm->start_brk = current->mm->brk = bss_vaddr + bss_size; current->suid = current->euid = bprm->e_uid; current->sgid = current->egid = bprm->e_gid; current->executable = bprm->inode; /* Store inode for file */ ++bprm->inode->i_count; /* Count the open inode */ regs->eip = start_addr; /* Current EIP register */ regs->esp = current->mm->start_stack = bprm->p; } /* * Map the text pages */ #ifdef COFF_DEBUG printk (".text: vaddr = %d, size = %d, scnptr = %d\n", text_vaddr, text_size, text_scnptr); #endif status = do_mmap (fp, text_vaddr & PAGE_MASK, text_size + (text_vaddr & ~PAGE_MASK), PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED, text_scnptr & PAGE_MASK); status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC; /* * Map the data pages */ if (status >= 0 && data_size != 0) { #ifdef COFF_DEBUG printk (".data: vaddr = %d, size = %d, scnptr = %d\n", data_vaddr, data_size, data_scnptr); #endif status = do_mmap (fp, data_vaddr & PAGE_MASK, data_size + (data_vaddr & ~PAGE_MASK), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, data_scnptr & PAGE_MASK); status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC; } /* * Construct the bss data for the process. The bss ranges from the * end of the data (which may not be on a page boundary) to the end * of the bss section. Allocate any necessary pages for the data. */ if (status >= 0 && bss_size != 0) { #ifdef COFF_DEBUG printk (".bss: vaddr = %d, size = %d\n", bss_vaddr, bss_size); #endif zeromap_page_range (PAGE_ALIGN (bss_vaddr), PAGE_ALIGN (bss_size), PAGE_COPY); status = clear_memory (bss_vaddr, bss_size); } /* * Load any shared library for the executable. */ if (status >= 0 && lib_ok && lib_count != 0) { int nIndex; COFF_SCNHDR *sect_ptr = sect_bufr; /* * Find the library sections. (There should be at least one. It was counted * earlier.) This will eventually recurse to our code and load the shared * library with our own procedures. */ for (nIndex = 0; nIndex < sections; ++nIndex) { long int sect_flags = COFF_LONG (sect_ptr->s_flags); if (sect_flags == COFF_STYP_LIB) { status = preload_library (bprm, sect_ptr, fp); if (status != 0) break; } sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ]; } } /* * Generate any needed trap for this process. If an error occurred then * generate a segmentation violation. If the process is being debugged * then generate the load trap. (Note: If this is a library load then * do not generate the trap here. Pass the error to the caller who * will do it for the process in the outer lay of this procedure call.) */ if (lib_ok) { if (status < 0) send_sig (SIGSEGV, current, 0); /* Generate the error trap */ else { if (current->flags & PF_PTRACED) send_sig (SIGTRAP, current, 0); } status = 0; /* We are committed. It can't fail */ } } /* * Do any cleanup processing */ if (fd >= 0) sys_close (fd); /* Close unused code file */ if (sect_bufr != NULL) kfree (sect_bufr); /* Release section list buffer */ /* * Return the completion status. */ #ifdef COFF_DEBUG printk ("binfmt_coff: result = %d\n", status); #endif return (status); }