dosexec.c
来自「UNIX下SH的实现源码」· C语言 代码 · 共 1,146 行 · 第 1/3 页
C
1,146 行
"COMMAND.COM", "4DOS.COM", "NDOS.COM", 0};/* A list of Unix-like shells and other non-DJGPP programs which treat single quote specially. */static const char *unix_shells[] = { "SH.EXE", "-SH.EXE", /* people create `-sh.exe' and `-bash.exe' to have login shells */ "SH16.EXE", "SH32.EXE", "TCSH.EXE", "-TCSH.EXE", "BASH.EXE", "-BASH.EXE", 0};static intlist_member (const char *program, const char *program_list[]){ const char *p = program, *ptail = program; int i; while (*p) { if (*p == '/' || *p == ':' || *p == '\\') ptail = p + 1; p++; } for (i = 0; program_list[i]; i++) if (!stricmp (ptail, program_list[i])) return 1; return 0;}int_is_unixy_shell (const char *shellpath){ return list_member (shellpath, unix_shells);}int_is_dos_shell (const char *shellpath){ return list_member (shellpath, shell_brokets);}static int direct_exec(const char *program, char **argv, char **envp){ int i, arglen; char *args, *argp; int need_quote = !__dosexec_in_system; int unescape_quote = __dosexec_in_system; /* PROGRAM can be a shell which expects a single argument (beyond the /c or -c switch) that is the entire command line. With some shells, we must NOT quote that command line, because that will confuse the shell. The hard problem is to know when PROGRAM names a shell that doesn't like its command line quoted... */ if (need_quote && argv[1] && !strcmp (argv[1], "/c") && argv[2] && !argv[3] && _is_dos_shell (program)) need_quote = 0; if (unescape_quote && _is_unixy_shell (program)) unescape_quote = 0; arglen = 0; for (i=1; argv[i]; i++) arglen += 2*strlen(argv[i]) + 1 + 2; args = (char *)alloca(arglen+1); argp = args; for (i=1; argv[i]; i++) { int quoted = 0; const char *p = argv[i]; if (argp - args > CMDLEN_LIMIT) break; *argp++ = ' '; /* If invoked by `spawnXX' or `execXX' functions, we need to quote arguments which include whitespace, so they end up as a single argument on the child side. We will invoke PROGRAM directly by DOS Exec function (not through COMMAND.COM), therefore no need to quote characters special only to COMMAND.COM. We also assume that DJGPP programs aren't invoked through here, so a single quote `\'' is also not special. The only programs other than DJGPP that treat a single quote specially are Unix-like shells, but whoever uses them should know to escape the quotes himself. */ if (need_quote && strpbrk(p, " \t") != 0) { *argp++ = '"'; quoted = 1; } while (*p) { if (argp - args > CMDLEN_LIMIT) break; if (*p == '"' && (quoted || need_quote)) *argp++ = '\\'; /* Most non-DJGPP programs don't treat `\'' specially, but our `system' requires we always escape it, so we should undo the quoting here. */ else if (*p == '\\' && p[1] == '\'' && unescape_quote) p++; *argp++ = *p++; } if (quoted && argp - args <= CMDLEN_LIMIT) *argp++ = '"'; } *argp = 0; if (argp - args > CMDLEN_LIMIT) errno = E2BIG; tbuf_beg = tbuf_ptr = __tb; tbuf_len = _go32_info_block.size_of_transfer_buffer; tbuf_end = tbuf_beg + tbuf_len - 1; return direct_exec_tail(program, args, envp, 0, 2);}static int go32_exec(const char *program, char **argv, char **envp){ const _v2_prog_type * type; char *save_argv0; int i; char *go32, *sip=0; char rpath[FILENAME_MAX]; int argc=0; int si_la=0, si_off=0, rm_off, argv_off; char cmdline[CMDLEN_LIMIT+2], *cmdp = cmdline; char *pcmd = cmdline, *pproxy = 0, *proxy_cmdline = 0; int retval; int lfn = 2; /* means don't know yet */ type = _check_v2_prog (program, -1); /* Because this function is called only, when program exists, I can skip the check for type->valid */#define v2_0 (type->version.v.major > 1)#define is_stubbed (type->exec_format == _V2_EXEC_FORMAT_STUBCOFF)#define is_coff (type->object_format == _V2_OBJECT_FORMAT_COFF)#define found_si (type->has_stubinfo) if (type->exec_format == _V2_EXEC_FORMAT_UNIXSCRIPT) { return script_exec(program, argv, envp); } /* Non-DJGPP programs cannot be run by !proxy. */ if (!is_coff) { const char *ext = strrchr(program, '.'); if (type->exec_format == _V2_EXEC_FORMAT_EXE || (ext && stricmp(ext, ".com") == 0)) return direct_exec(program, argv, envp); else return __dosexec_command_exec (program, argv, envp); } if (found_si) go32 = type->stubinfo->go32; else if (v2_0 && !is_stubbed) go32 = GO32_V2_STRING; else go32 = GO32_STRING; if (v2_0 && is_stubbed) { strcpy(rpath, program); } else { int e = errno; if (!__dosexec_find_on_path(go32, envp, rpath)) { errno = e; return direct_exec(program, argv, envp); /* give up and just run it */ } if (found_si) { sip = (char *)type->stubinfo; } } /* V2.0 programs invoked by `system' must be run via `direct_exec', because otherwise the command-line arguments won't be globbed correctly by the child. Only v2.01 and later knows how to get long command lines from `system' AND glob them correctly. But we don't want to check with which version was the child compiled, so we need to create both the usual DOS command line and the !proxy one (which will be put into the environment). Sigh... */ save_argv0 = argv[0]; argv[0] = unconst(program, char *); /* since that's where we really found it */ /* Construct the DOS command tail */ for (argc=0; argv[argc]; argc++); if (__dosexec_in_system && v2_0) { /* If PROGRAM is an un-stubbed COFF, its name must be passed in the command tail as well, since we call GO32 to run it. */ for (i = (is_stubbed ? 1 : 0); i < argc; i++) { const char *p = argv[i]; if (cmdp - cmdline > CMDLEN_LIMIT) break; *cmdp++ = ' '; while (*p) { if (cmdp - cmdline > CMDLEN_LIMIT) break; *cmdp++ = *p++; } } *cmdp = '\0'; } lfn = _USE_LFN; /* Can't call any functions that use the transfer buffer beyond this point: they will overwrite the data already in __tb. */ tbuf_beg = tbuf_ptr = __tb; tbuf_len = _go32_info_block.size_of_transfer_buffer; tbuf_end = tbuf_ptr + tbuf_len - 1; /* If called from `system' and we have a command line shorter than the DOS limit, we don't need to use !proxy at all. Note that v1.x programs are always run through !proxy, to prevent go32.exe from printing its copyright line. */ if (!__dosexec_in_system || !v2_0 || cmdp - cmdline > CMDLEN_LIMIT) { if (!check_talloc(found_si ? type->stubinfo->struct_length : 0 + (argc+1)*sizeof(short))) { argv[0] = save_argv0; return -1; } if (found_si) { si_la = talloc(type->stubinfo->struct_length); si_off = si_la - tbuf_beg; dosmemput(sip, type->stubinfo->struct_length, si_la); } rm_off = argv_off = talloc((argc+1) * sizeof(short)) - tbuf_beg;#if 0 /* `alloca' could be dangerous with long command lines. We will instead move the offsets one by one with `_farpokew'. */ rm_argv = (short *)alloca((argc+1) * sizeof(short));#endif for (i=0; i<argc; i++) { char *pargv = argv[i]; int sl = strlen(pargv) + 1; unsigned long q;#if 0 /* Workaround for bug in globbing. glob() allocates a fixed buffer of 2000 bytes for its path buffer. If an argument greater than 2000 bytes is passed to a DJGPP program, that program may crash and under Windows take the DOS VM with it. */ if (sl >= 2000) { argv[0] = save_argv0; return -1; }#endif if (check_talloc(sl)) { q = talloc(sl); dosmemput(pargv, sl, q); _farpokew(_dos_ds, tbuf_beg + argv_off, (q - tbuf_beg) & 0xffff); argv_off += sizeof(short); } else /* not enough space to pass args */ { argv[0] = save_argv0; return -1; } } _farpokew (_dos_ds, tbuf_beg + argv_off, 0); argv_off += sizeof(short); argv[0] = save_argv0; /* Environment variables are all malloced. */ proxy_cmdline = (char *)malloc (34); if (!proxy_cmdline) return -1; sprintf(proxy_cmdline, "%s=%04x %04x %04x %04x %04x", __PROXY, argc, (unsigned)(tbuf_beg >> 4), rm_off & 0xffff, (unsigned)(tbuf_beg >> 4), si_off & 0xffff); if (!found_si) proxy_cmdline[22] = 0; /* remove stubinfo information */ if (__dosexec_in_system && v2_0) pproxy = proxy_cmdline; else { /* `proxy_cmdline looks like an environment variable " !proxy=value". This is used as the REAL command line specification by 2.01 and later executables when called by `system'. But if that's not the case, we need a blank instead of the `='. */ proxy_cmdline[__PROXY_LEN] = ' '; pcmd = proxy_cmdline; } } else argv[0] = save_argv0; retval = direct_exec_tail(rpath, pcmd, envp, pproxy, lfn); if (proxy_cmdline) free(proxy_cmdline); return retval;}int__dosexec_command_exec(const char *program, char **argv, char **envp){ const char *comspec=0; char *cmdline; int cmdlen; int i; int was_quoted = 0; /* was the program name quoted? */ /* Add spare space for possible quote characters. */ cmdlen = strlen(program) + 4 + 2; for (i=0; argv[i]; i++) cmdlen += 2*strlen(argv[i]) + 1; cmdline = (char *)alloca(cmdlen); /* FIXME: is this LFN-clean? What special characters can the program name have and how should they be quoted? */ strcpy(cmdline, "/c "); if (strchr(program, ' ') || strchr(program, '\t')) { was_quoted = 1; cmdline[3] = '"'; } for (i = 0; program[i] > ' '; i++) { /* COMMAND.COM cannot grok program names with forward slashes. */ if (program[i] == '/') cmdline[i+3+was_quoted] = '\\'; else cmdline[i+3+was_quoted] = program[i]; } for (; program[i]; i++) cmdline[i+3+was_quoted] = program[i]; if (was_quoted) { cmdline[i+3+was_quoted] = '"'; i++; } cmdline[i+3+was_quoted] = 0; for (i=1; argv[i]; i++) { strcat(cmdline, " "); /* If called by `spawnXX' or `execXX' functions, must quote arguments that have embedded whitespace or characters which are special to COMMAND.COM and its ilk. We don't quote all
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?