mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	command -x: fix efficiency; always run external cmd (re: acf84e96)
				
					
				
			This commit fixes 'command -x' to adapt to OS limitations with
regards to data alignment in the arguments list. A feature test is
added that detects if the OS aligns the argument on 32-bit or
64-bit boundaries or not at all, allowing 'command -x' to avoid
E2BIG errors while maximising efficiency.
Also, as of now, 'command -x' is a way to bypass built-ins and
run/query an external command. Built-ins do not limit the length of
their argument list, so '-x' never made sense to use for them. And
because '-x' hangs on Linux and macOS on every ksh93 release
version to date (see acf84e96), few use it, so there is little
reason not to make this change.
Finally, this fixes a longstanding bug that caused the minimum exit
status of 'command -x' to be 1 if a command with many arguments was
divided into several command invocations. This is done by replacing
broken flaggery with a new SH_XARG state flag bit.
src/cmd/ksh93/features/externs:
- Add new C feature test detecting byte alignment in args list.
  The test writes a #define ARG_ALIGN_BYTES with the amount of
  bytes the OS aligns arguments to, or zero for no alignment.
src/cmd/ksh93/include/defs.h:
- Add new SH_XARG state bit indicating 'command -x' is active.
src/cmd/ksh93/sh/path.c: path_xargs():
- Leave extra 2k in the args buffer instead of 1k, just to be sure;
  some commands add large environment variables these days.
- Fix a bug in subtracting the length of existing arguments and
  environment variables. 'size -= strlen(cp)-1;' subtracts one less
  than the size of cp, which makes no sense; what is necessary is
  to substract the length plus one to account for the terminating
  zero byte, i.e.: 'size -= strlen(cp)+1'.
- Use the ARG_ALIGN_BYTES feature test result to match the OS's
  data alignment requirements.
- path_spawn(): E2BIG: Change to checking SH_XARG state bit.
src/cmd/ksh93/bltins/whence.c: b_command():
- Allow combining -x with -p, -v and -V with the expected results
  by setting P_FLAG to act like 'whence -p'. E.g., as of now,
	command -xv printf
  is equivalent to
	whence -p printf
  but note that 'whence' has no equivalent of 'command -pvx printf'
  which searches $(getconf PATH) for a command.
- When -x will run a command, now set the new SH_XARG state flag.
src/cmd/ksh93/sh/xec.c: sh_exec():
- Change to using the new SH_XARG state bit.
- Skip the check for built-ins if SH_XARG is active, so that
  'command -x' now always runs an external command.
src/lib/libcmd/date.c, src/lib/libcmd/uname.c:
- These path-bound builtins sometimes need to run the external
  system command by the same name, but they did that by hardcoding
  an unportable direct path. Now that 'command -x' runs an external
  command, change this to using 'command -px' to guarantee using
  the known-good external system utility in the default PATH.
- In date.c, fix the format string passed to 'command -px date'
  when setting the date; it was only compatible with BSD systems.
  Use the POSIX variant on non-BSD systems.
			
			
This commit is contained in:
		
							parent
							
								
									005d38f410
								
							
						
					
					
						commit
						66e1d44642
					
				
					 12 changed files with 239 additions and 75 deletions
				
			
		|  | @ -11,3 +11,125 @@ reference	unistd.h | |||
| extern	nice		int	(int) | ||||
| extern	setreuid	int	(uid_t,uid_t) | ||||
| extern	setregid	int	(gid_t,gid_t) | ||||
| 
 | ||||
| tst	note{ determining data alignment factor for arguments list }end output{ | ||||
| 	/* | ||||
| 	 * Feature test to figure out if this OS does data alignment on | ||||
| 	 * the arguments list of a process, and if so, at how many bits. | ||||
| 	 * Outputs an appropriate #define ARG_ALIGN_BITS. | ||||
| 	 * Without this, 'command -x' failed with E2BIG on macOS and Linux even | ||||
| 	 * if all the arguments should fit in ARG_MAX based on their length. | ||||
| 	 * | ||||
| 	 * Strategy: first try to fill as many single-character arguments as | ||||
| 	 * should fit in ARG_MAX without alignment. If that fails with E2BIG, | ||||
| 	 * then start with a 2-byte alignment factor and keep doubling it | ||||
| 	 * until we either succeed or exceed an absurdly large value. | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* AST includes */ | ||||
| 	#include <ast.h> | ||||
| 	#include <error.h> | ||||
| 	#include <sfio.h> | ||||
| 	#include <stak.h> | ||||
| 	#include <wait.h> | ||||
| 
 | ||||
| 	/* Standard includes */ | ||||
| 	#include <errno.h> | ||||
| 
 | ||||
| 	#ifndef _lib_fork | ||||
| 	#error requires fork(2) | ||||
| 	#endif | ||||
| 	#ifndef _lib_execve | ||||
| 	#error requires execve(2) | ||||
| 	#endif | ||||
| 	#ifndef _lib_waitpid | ||||
| 	#error requires waitpid(2) | ||||
| 	#endif | ||||
| 
 | ||||
| 	int main(int argc,char *argv[]) | ||||
| 	{ | ||||
| 		int align_bytes = 0, envlen = 0, argmax, i; | ||||
| 		pid_t childpid; | ||||
| 
 | ||||
| 		error_info.id="args list aligment test (parent)"; | ||||
| 		for(i=0; environ[i]; i++) | ||||
| 			envlen += strlen(environ[i]) + 1; | ||||
| 		argmax = strtoimax(astconf("ARG_MAX",NiL,NiL),NiL,0) - envlen - 1024; | ||||
| 		if (argmax < 2048) | ||||
| 		{ | ||||
| 			error(ERROR_ERROR|2, "argmax too small"); | ||||
| 			return 1; | ||||
| 		} | ||||
| 		while(1) | ||||
| 		{ | ||||
| 			if(!(childpid = fork())) | ||||
| 			{ | ||||
| 				/* child */ | ||||
| 				int bytec; | ||||
| 
 | ||||
| 				error_info.id="args list aligment test (child)"; | ||||
| 				argv = (char **)stakalloc((argmax / 2 + 1) * sizeof(char*)); | ||||
| 				argc = bytec = 0; | ||||
| 				while(bytec < argmax) | ||||
| 				{ | ||||
| 					if(argc==0) | ||||
| 						argv[argc] = "/usr/bin/env"; | ||||
| 					else if(argc==1) | ||||
| 						argv[argc] = "true"; | ||||
| 					else | ||||
| 						argv[argc] = "x"; | ||||
| 					bytec += strlen(argv[argc]) + 1 + align_bytes; | ||||
| 					if(align_bytes) | ||||
| 						bytec += bytec % align_bytes; | ||||
| 					argc++; | ||||
| 				} | ||||
| 				argv[argc] = (char*)0; | ||||
| 				if(execve(argv[0], argv, environ) < 0) | ||||
| 				{ | ||||
| 					if(errno == E2BIG) | ||||
| 						return 1; | ||||
| 					else | ||||
| 					{ | ||||
| 						error(ERROR_SYSTEM|2, "execve failed"); | ||||
| 						return 2; | ||||
| 					} | ||||
| 				} | ||||
| 				error(ERROR_SYSTEM|2, "[BUG] we should never get here!"); | ||||
| 				return 2; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* parent */ | ||||
| 				int exitstatus; | ||||
| 
 | ||||
| 				if (waitpid(childpid,&i,0) < 0) | ||||
| 				{ | ||||
| 					error(ERROR_SYSTEM|2, "waitpid failed"); | ||||
| 					return 1; | ||||
| 				} | ||||
| 				if (!WIFEXITED(i) || (exitstatus = WEXITSTATUS(i)) > 1) | ||||
| 				{ | ||||
| 					error(ERROR_ERROR|2, "child process exited abnormally"); | ||||
| 					return 1; | ||||
| 				} | ||||
| 				if (exitstatus == 0) | ||||
| 					break;	/* yay :) */ | ||||
| 				if (!align_bytes) | ||||
| 					align_bytes = 2; | ||||
| 				else | ||||
| 					align_bytes *= 2; | ||||
| 				if (align_bytes > 256) | ||||
| 				{ | ||||
| 					error(ERROR_ERROR|2, "giving up"); | ||||
| 					return 1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		sfprintf(sfstdout, | ||||
| 			"#define ARG_ALIGN_BYTES\t%d\t/* data alignment factor for arguments list */\n", | ||||
| 			align_bytes); | ||||
| 		return 0; | ||||
| 	} | ||||
| }end fail{ | ||||
| 	echo "#define ARG_ALIGN_BYTES	16	/* BUG: arg list alignment factor test failed; assuming 16 */" | ||||
| }end | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue