[uClibc-cvs] uClibc/libc/unistd exec.c, NONE, 1.1 Makefile, 1.35, 1.36 execl.c, 1.4, NONE execlp.c, 1.5, NONE execv.c, 1.2, NONE execvep.c, 1.2, NONE execvp.c, 1.3, NONE execle.c, 1.2, NONE

Manuel Novoa III mjn3 at uclibc.org
Fri Jan 2 08:45:01 UTC 2004


Update of /var/cvs/uClibc/libc/unistd
In directory nail:/tmp/cvs-serv25086

Modified Files:
	Makefile 
Added Files:
	exec.c 
Removed Files:
	execl.c execlp.c execv.c execvep.c execvp.c execle.c 
Log Message:
Redo the exec functions to comply with SUSv3.


--- NEW FILE: exec.c ---
/*  Copyright (C) 2004     Manuel Novoa III
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Jan 1, 2004
 *   Initial version of a SUSv3 compliant exec*() functions.
 */

/* NOTE: Strictly speaking, there could be problems from accessing
 * __environ in multithreaded programs.  The only way around this
 * that I see is to essentially lock __environ access (modifying
 * the setenv code), make a copy of the environment table (just the
 * pointers since the strings themselves are never freed), and then
 * unlock prior to the execve call.  If that fails, then we'd need
 * to free the storage allocated for the copy.  Better ideas anyone?
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <sys/mman.h>

extern char *__strchrnul(const char *s, int c);

/**********************************************************************/
#ifdef __UCLIBC_HAS_MMU__

/* We have an MMU, so use alloca() to grab space for buffers and
 * arg lists. */

# define EXEC_ALLOC_SIZE(VAR)	/* nothing to do */
# define EXEC_ALLOC(SIZE,VAR)	alloca((SIZE))
# define EXEC_FREE(PTR,VAR)		((void)0)

#else

/* We do not have an MMU, so using alloca() is not an option.
 * Less obviously, using malloc() is not an option either since
 * malloc()ed memory can leak in a vfork() and exec*() situation.
 * Therefore, we must use mmap() and unmap() directly.
 */

# define EXEC_ALLOC_SIZE(VAR)	size_t VAR;	/* Semicolon included! */
# define EXEC_ALLOC(SIZE,VAR)	__exec_alloc((VAR = (SIZE)))
# define EXEC_FREE(PTR,VAR)		__exec_free((PTR),(VAR))

extern void *__exec_alloc(size_t size);
extern void __exec_free(void *ptr, size_t size);

#endif
/**********************************************************************/
#ifdef L___exec_alloc

#ifndef __UCLIBC_HAS_MMU__

void *__exec_alloc(size_t size)
{
	void *p;

	p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

	return (p != MAP_FAILED) ? p : NULL;
}

void __exec_free(void *ptr, size_t size)
{
	if (ptr) {
		munmap(ptr, size);
	}
}

#endif

#endif
/**********************************************************************/
#ifdef L_execl

int execl(const char *path, const char *arg, ...)
{
	EXEC_ALLOC_SIZE(size)		/* Do NOT add a semicolon! */
	int n;
	char **argv;
	char **p;
	va_list args;
	
	n = 0;
	va_start(args, arg);
	do {
		++n;
	} while (va_arg(args, char *));
	va_end(args);

	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);

	p[0] = (char *)arg;

	va_start(args, arg);
	do {
		*++p = va_arg(args, char *);
	} while (--n);
	va_end(args);

	n = execve(path, (char *const *) argv, __environ);

	EXEC_FREE(argv, size);

	return n;
}

#endif
/**********************************************************************/
#ifdef L_execv

int execv(__const char *path, char *__const argv[])
{
	return execve(path, argv, __environ);
}

#endif
/**********************************************************************/
#ifdef L_execle

int execle(const char *path, const char *arg, ...)
{
	EXEC_ALLOC_SIZE(size)		/* Do NOT add a semicolon! */
	int n;
	char **argv;
	char **p;
	char *const *envp;
	va_list args;
	
	n = 0;
	va_start(args, arg);
	do {
		++n;
	} while (va_arg(args, char *));
	envp = va_arg(args, char *const *);	/* Varies from execl and execlp. */
	va_end(args);

	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);

	p[0] = (char *)arg;

	va_start(args, arg);
	do {
		*++p = va_arg(args, char *);
	} while (--n);
	va_end(args);

	n = execve(path, (char *const *) argv, envp);

	EXEC_FREE(argv, size);

	return n;
}

#endif
/**********************************************************************/
#ifdef L_execlp

int execlp(const char *file, const char *arg, ...)
{
	EXEC_ALLOC_SIZE(size)		/* Do NOT add a semicolon! */
	int n;
	char **argv;
	char **p;
	va_list args;
	
	n = 0;
	va_start(args, arg);
	do {
		++n;
	} while (va_arg(args, char *));
	va_end(args);

	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);

	p[0] = (char *)arg;

	va_start(args, arg);
	do {
		*++p = va_arg(args, char *);
	} while (--n);
	va_end(args);

	n = execvp(file, (char *const *) argv);

	EXEC_FREE(argv, size);

	return n;
}

#endif
/**********************************************************************/
#ifdef L_execvp

/* Use a default path that matches glibc behavior, since SUSv3 says
 * this is implementation-defined.  The default is current working dir,
 * /bin, and then /usr/bin. */
static const char default_path[] = ":/bin:/usr/bin";

int execvp(const char *path, char *const argv[])
{
	char *buf = NULL;
	char *p;
	char *e;
	char *s0;
	char *s;
	EXEC_ALLOC_SIZE(size = 0)	/* Do NOT add a semicolon! */
	size_t len;
	size_t plen;

	if (!path || !*path) {		/* Comply with SUSv3. */
	BAD:
		__set_errno(ENOENT);
		return -1;
	}

	if (strchr(path, '/')) {
		execve(path, argv, __environ);
	CHECK_ENOEXEC:
		if (errno == ENOEXEC) {
			char **nargv;
			EXEC_ALLOC_SIZE(size2) /* Do NOT add a semicolon! */
			size_t n;
			/* Need the dimension - 1.  We omit counting the trailing
			 * NULL but we actually omit the first entry. */
			for (n=0 ; argv[n] ; n++) {}
			nargv = (char **) EXEC_ALLOC((n+2) * sizeof(char *), size2);
			nargv[0] = argv[0];
			nargv[1] = (char *)path;
			memcpy(nargv+2, argv+1, n*sizeof(char *));
			execve("/bin/sh", nargv, __environ);
			EXEC_FREE(nargv, size2);
		}
	} else {
		if ((p = getenv("PATH")) != NULL) {
			if (!*p) {
				goto BAD;
			}
		} else {
			p = (char *) default_path;
		}

		plen = strlen(path);
		if (plen > (FILENAME_MAX - 1)) {
		ALL_TOO_LONG:
			__set_errno(ENAMETOOLONG);
			return -1;
		}
		len = (FILENAME_MAX - 1) - plen;

		if ((buf = EXEC_ALLOC(FILENAME_MAX, size)) != NULL) {
			int seen_small = 0;
			s0 = buf + len;
			memcpy(s0, path, plen+1);

			do {
				s = s0;
				e = __strchrnul(p, ':');
				if (e > p) {
					plen = e - p;
					if (e[-1] != '/') {
						++plen;
					}
					if (plen > len) {
						goto NEXT;
					}
					s -= plen;
					memcpy(s, p, plen);
					s[plen-1] = '/';
				}

				execve(s, argv, __environ);

				seen_small = 1;

				if (errno != ENOENT) {
					path = s;
					goto CHECK_ENOEXEC;
				}

			NEXT:
				if (!*e) {
					if (!seen_small) {
						goto ALL_TOO_LONG;
					}
					break;
				}
				p = e + 1;
			} while (1);
		}
	}

	EXEC_FREE(buf, size);

	return -1;
}

#endif
/**********************************************************************/

--- execl.c DELETED ---

Index: Makefile
===================================================================
RCS file: /var/cvs/uClibc/libc/unistd/Makefile,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- Makefile	5 Nov 2003 07:08:20 -0000	1.35
+++ Makefile	2 Jan 2004 08:44:58 -0000	1.36
@@ -20,13 +20,18 @@
 include $(TOPDIR)Rules.mak
 DIRS:=
 
-CSRC=execl.c execlp.c execv.c execvep.c execvp.c execle.c \
-	sleep.c usleep.c getpass.c sysconf.c getlogin.c \
+MSRC1 = exec.c
+MOBJ1 = execl.o execv.o execle.o execlp.o execvp.o
+
+CSRC=	sleep.c usleep.c getpass.c sysconf.c getlogin.c \
 	fpathconf.c confstr.c pathconf.c swab.c usershell.c \
 	getsubopt.c
+
 ifeq ($(strip $(UCLIBC_HAS_MMU)),y)
-    CSRC+=daemon.c
+	CSRC += daemon.c
+	MOBJ1 += __exec_alloc.o
 endif
+
 ifeq ($(strip $(UCLIBC_HAS_GNU_GETOPT)),y)
 	CSRC += getopt.c
 else
@@ -34,7 +39,7 @@
 endif
 
 COBJS=$(patsubst %.c,%.o, $(CSRC))
-OBJS=$(COBJS)
+OBJS=$(COBJS) $(MOBJ1)
 
 all: $(SYSCONF) $(OBJS) $(LIBC)
 
@@ -43,6 +48,10 @@
 ar-target: $(OBJS)
 	$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
 
+$(MOBJ1): $(MSRC1)
+	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+	$(STRIPTOOL) -x -R .note -R .comment $*.o
+
 $(COBJS): %.o : %.c
 	$(CC) $(CFLAGS) -c $< -o $@
 	$(STRIPTOOL) -x -R .note -R .comment $*.o

--- execvp.c DELETED ---

--- execlp.c DELETED ---

--- execvep.c DELETED ---

--- execle.c DELETED ---

--- execv.c DELETED ---




More information about the uClibc-cvs mailing list