[ksh93-integration-discuss] Shouldksh93/libshelluse|posix_spawn()| instead of |vfork()| ?

Glenn Fowler gsf at research.att.com
Mon Oct 30 07:40:33 PST 2006


On Mon, 30 Oct 2006 06:01:42 +0100 Roland Mainz wrote:
> On Solaris 11/B48/i386 with ast-ksh.2006-10-26 the "iffe" test says:
> -- snip --
> iffe: test: posix_spawn exists and it works and its worth using ... no
> -- snip --
> IMO should should be "yes" on Solaris for "correctness" reasons...

I double checked the iffe posix_spawn tests uses by spawnveg()

one of the pitfalls of iffe/autconfig is that *any* failure can be a
valid test outcome, so if you don't keep on top of some tests as target
systems evolve, some test outcomes may be due to failures not related to the test

it turns out there were some syntax errors on solaris
I fixed those, but posix_spawn() was still found unworthy
the reason is that at least on solaris 10, posix_spawn() returns 0 (success)
when the executable file is empty
truss shows the underlying execve() getting ENOEXEC (which it should),
but that errno fails to make its way back as the posix_spawn() return value

note that linux posix_spawn() is not worthy for the same reason

the ast spanwveg() implementation recognizes 2 vfork() implementations
one where the parent and child share data (_real_vfork), and the other;
for the latter it sets up a pipe for the child to communicate the execv()
errno back to the parent -- I don't know if similar care needs to be taken on
linux and solaris

here is an annotated version of the iffe-generated test
call it t.c, cc -o t.exe t.c, and it will generate t.exe.sh for the ENOEXEC test

---
#define fork	______fork

#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
#define _STD_		1
#define _ARG_(x)	x
#define _VOID_		void
#else
#define _STD_		0
#define _ARG_(x)	()
#define _VOID_		char
#endif
#if defined(__cplusplus)
#define _BEGIN_EXTERNS_	extern "C" {
#define _END_EXTERNS_	}
#else
#define _BEGIN_EXTERNS_
#define _END_EXTERNS_
#endif
#define _NIL_(x)	((x)0)
#include <stdio.h>

#define _hdr_unistd 1
#define _hdr_stdlib 1
#define _hdr_spawn 1

#include <unistd.h>
#include <stdlib.h>
#include <spawn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <spawn.h>
#include <signal.h>
#include <wait.h>
#include <fcntl.h>
#include <string.h>

#undef	fork

/* if it uses fork() why bother? */
pid_t fork _ARG_((void)) { return -1; }
pid_t _fork _ARG_((void)) { return -1; }
pid_t __fork _ARG_((void)) { return -1; }
int
main(argc, argv)
int	argc;
char**	argv;
{
	char*			s;

	pid_t			pid;
	posix_spawnattr_t	attr;
	int			n;
	int			status;
	char*			cmd[3];
	char			tmp[1024];
	fprintf(stderr, "%d: %p\n", __LINE__, argv[1]);
	if (argv[1])
		_exit(signal(SIGHUP, SIG_DFL) != SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	fprintf(stderr, "%d:\n", __LINE__);
	if (posix_spawnattr_init(&attr))
		_exit(1);
	fprintf(stderr, "%d:\n", __LINE__);
	if (posix_spawnattr_setpgroup(&attr, 0))
		_exit(1);
	/* first try an a.out and verify that SIGHUP is ignored */
	cmd[0] = argv[0];
	cmd[1] = "test";
	cmd[2] = 0;
	fprintf(stderr, "%d:\n", __LINE__);
	if (posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0))
		_exit(1);
	status = 1;
	fprintf(stderr, "%d:\n", __LINE__);
	if (wait(&status) < 0 || status != 0)
		_exit(1);
	/* passing ENOEXEC to the shell is bogus */
	n = strlen(cmd[0]);
	if (n >= (sizeof(tmp) - 3))
		_exit(1);
	strcpy(tmp, cmd[0]);
	tmp[n] = '.';
	tmp[n+1] = 's';
	tmp[n+2] = 'h';
	tmp[n+3] = 0;
	fprintf(stderr, "%d:\n", __LINE__);
	if (close(open(tmp, O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO)) < 0 || chmod(tmp, S_IRWXU|S_IRWXG|S_IRWXO) < 0)
		_exit(1);
	cmd[0] = tmp;
	fprintf(stderr, "%d: %s\n", __LINE__, cmd[0]);
	if (!posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0))
	{
		wait(&status);
		_exit(1);
	}
	fprintf(stderr, "%d:\n", __LINE__);
	_exit(0);
}
---

-- Glenn Fowler -- AT&T Research, Florham Park NJ --




More information about the ksh93-integration-discuss mailing list