<div dir="ltr"><p><font size="2">This patch is for $ER_TOP/erts/emulator/sys/win32 and fixes a bug affecting os:cmd and open_port + spawn on winnt systems that prevents execution of child processes containing spaces in the filename or path string.<br>
<br>It appears that the original code allowed for the file name and / or path to be enclosed in double quotes. For instance parse_command searches for the first occurrence of a space outside an opening closing pair of double quotes. The location of that space is used to split the application and its path from any command line arguments. The actual bug occurs when the applications' file name and path are passed to the windows API GetFileAttributes with the quotes still intact in the function ApplicationType. <br>
<br>Since ApplicationType does some file searching by appending .com, .exe, .bat to the filename, I figured it would be best to strip the quotes from the command string before calling ApplicationType, however the code could just as easily be placed in ApplicationType. On a side note, it appears that GetFileAttributes is called in places and it's possible that the same kind of quote scrubbing may be required in other source files.<br>
<br>While I'm sure there is a easier way to strip characters from a string, I removed the characters using strtok within a loop using double quotes character as the token delimited and then appended the results using strncat into a new string.<br>
<br>As for a test case, I have Visual Studio 2005 installed at C:\Program Files\Microsoft Visual Studio 8\ (its default location, however the actual installed location can be found in the registry.) In order to fetch the build number for Visual Stuudio 2005, execute the following command line<br>
C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\<a href="http://devenv.com">devenv.com</a> /?<br>and grab the version number from the first line.<br><br>To execute <a href="http://devenv.com">devenv.com</a> (assuming that it is NOT in your path) via <a href="http://command.com">command.com</a> the application and file path need to be wrapped in double quotes.<br>
cmd /c "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\<a href="http://devenv.com">devenv.com</a>" /?<br>It's important that the command line options (in this case /?) are located outside the double quotes. <br>
<br>Without this patch, the following erlang expression fails however should work after patching and building<br>os:cmd("\"C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\<a href="http://devenv.com">devenv.com</a>\" /?").<br>
<br>The following two erlang expressions should always fail (with or without patch)<br><br>No double quotes -- C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\<a href="http://devenv.com">devenv.com</a> /?<br>os:cmd("C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\<a href="http://devenv.com">devenv.com</a> /?").<br>
<br>Command line parameters inside the quotes used for the filename - "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\<a href="http://devenv.com">devenv.com</a> /?" <br>os:cmd("\"C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\<a href="http://devenv.com">devenv.com</a> /?\"").<br>
<br><br>--- sys-orig.c 2008-06-10 05:47:26.000000000 -0700<br>+++ sys.c 2008-08-11 15:17:56.052245700 -0700<br>@@ -1186,6 +1186,8 @@<br> char execPath[MAX_PATH];<br> int cmdlength;<br> char* thecommand;<br>
+ char* fixedcommand;<br>+ char * pch;<br> HANDLE hProcess = GetCurrentProcess();<br> <br> siStartInfo.cb = sizeof(STARTUPINFO);<br>@@ -1200,13 +1202,29 @@<br> */<br> cmdlength = parse_command(origcmd);<br>
thecommand = (char *) erts_alloc(ERTS_ALC_T_TMP, cmdlength+1);<br>+<br> strncpy(thecommand, origcmd, cmdlength);<br> thecommand[cmdlength] = '\0';<br>- DEBUGF(("spawn command: %s\n", thecommand));<br>
+<br>+ fixedcommand = (char *) erts_alloc(ERTS_ALC_T_TMP, cmdlength+1);<br>+ fixedcommand[0] = '\0';<br>+ pch = strtok(thecommand,"\"");<br>+ if (pch == NULL) {<br>+ strncpy(fixedcommand, origcmd, cmdlength);<br>
+ fixedcommand[cmdlength] = '\0';<br>+ }<br>+ else {<br>+ while (pch != NULL) {<br>+ strncat(fixedcommand, pch, strlen(pch));<br>+ pch = strtok(NULL, "\"");<br>
+ }<br>+ }<br> <br>- applType = ApplicationType(thecommand, execPath);<br>- DEBUGF(("ApplicationType returned for (%s) is %d\n", thecommand, applType));<br>+ DEBUGF(("spawn command: %s\n", thecommand));<br>
+ applType = ApplicationType(fixedcommand, execPath);<br>+ DEBUGF(( "ApplicationType returned for (%s) is %d\n", fixedcommand, applType));<br> erts_free(ERTS_ALC_T_TMP, (void *) thecommand);<br>+ erts_free(ERTS_ALC_T_TMP, (void *) fixedcommand);<br>
if (applType == APPL_NONE) {<br> return FALSE;<br> }<br><br><br><br></font></p></div>