Bug 4520 - /sysexec, execute an external program
Status: RESOLVED WONTFIX
Alias: None
Product: ioquake3
Classification: Unclassified
Component: Misc
Version: GIT MASTER
Hardware: All All
: P3 enhancement
Assignee: Zachary J. Slater
QA Contact: ioquake3 bugzilla mailing list
URL:
Depends on:
Blocks:
 
Reported: 2010-01-29 18:34 EST by tinkah
Modified: 2011-02-04 09:50:34 EST
1 user (show)

See Also:



Description tinkah 2010-01-29 18:34:16 EST
The reason I wanted it was to change winamp songs with a bind:P

e.g. this plugin http://membres.multimania.fr/clamp/

and

/bind x sysexec clamp /next <--------goes next winamp song

with clamp in the path or using its full path.



The way this works on Windows is with some acrobatics using CreateProcess() to avoid the new program stealing focus (especially for changing songs with CLamp). For non-Windows it assumes system() will be enough by letting the user using some userland magic to avoid such stealing of focus. It is generally a raw method - especially on non-WIN32 - that may need proper care on what is being fed to it. e.g. Winamp (initial launching) or even ioq3 itself (a new one) will steal focus from it by force even if they are instructed not to. This can be considered 'normal'. On non-windows it may require a shell method that exits right after execution since system() itself halts the program until exit. Theoretically, even windows can be left requiring a userland program doing any focusing/unfocusing business but it allowed some handholding. 



void Com_Sysexec_f (void) {
	int	 num, i;
	char	 cmd[1024];
	#ifdef WIN32 
	char errormsg[1024];
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) ); //up to here carbon copy microsoft's example
	si.dwFlags = STARTF_USESHOWWINDOW; //needed to use the next one
	si.wShowWindow = SW_SHOWNOACTIVATE; //needed to *not activate, i.e. not focus*
	#endif

	num = Cmd_Argc();
	if (num < 2) {
		Com_Printf ("sysexec [command and parameters] : run an external system command/program with its parameters, it can be in the path or be entered in full path\n");
		return;
	}

	cmd[0] = 0; //required to start with a null string
	for (i = 1; i < num; i++) {
		strcat (cmd, Cmd_Argv(i));
		if (i != (num-1))
			strcat (cmd, " ");
	}
	Com_Printf("Issuing external command: %s\n",cmd);
	#ifdef WIN32
	if(!CreateProcess( NULL,cmd,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi )) {
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError(),0,errormsg,1024,NULL);
		Com_Printf("Issuing of %s failed, error: %s.\n",cmd, errormsg);
			if (GetLastError() == 2)
				Com_Printf("a command can be in the path or full path can be used\n");
	}
	#else
	system(cmd);
	#endif
}

//in an 'init':

Cmd_AddCommand( "sysexec", Com_Sysexec_f );
Comment 1 Thilo Schulz 2011-02-04 08:52:18 EST
No. Just no.
Comment 2 Thilo Schulz 2011-02-04 09:50:34 EST
I'm sorry, I realize my initial response is a bit harsh, so I'll explain to you why I said no:

I feel extremely uncomfortable adding any such command, because system() is known to be unsafe. I am a bit afraid because the server has some power to execute certain commands on the client. If there is a security hole in ioquake3 we don't know about yet, this command will open ioquake3 wide open for remote exploitation.