[OE-core] [PATCH 10/20] pseudo: Wrap renameat and opendir

Saul Wold sgw at linux.intel.com
Tue Feb 7 16:21:54 UTC 2012


On 02/05/2012 10:40 PM, Khem Raj wrote:
> Signed-off-by: Khem Raj<raj.khem at gmail.com>
> ---
>   meta/recipes-devtools/pseudo/pseudo/opendir.patch  |   92 ++++++++
>   meta/recipes-devtools/pseudo/pseudo/renameat.patch |  227 ++++++++++++++++++++
>   meta/recipes-devtools/pseudo/pseudo_1.2.bb         |    6 +-
>   3 files changed, 323 insertions(+), 2 deletions(-)
>   create mode 100644 meta/recipes-devtools/pseudo/pseudo/opendir.patch
>   create mode 100644 meta/recipes-devtools/pseudo/pseudo/renameat.patch
>
> diff --git a/meta/recipes-devtools/pseudo/pseudo/opendir.patch b/meta/recipes-devtools/pseudo/pseudo/opendir.patch
> new file mode 100644
> index 0000000..d20f717
> --- /dev/null
> +++ b/meta/recipes-devtools/pseudo/pseudo/opendir.patch
> @@ -0,0 +1,92 @@
> +commit 162f2692c399b93311652201a940fdaf9c9e6924
> +Author: Peter Seebach<peter.seebach at windriver.com>
> +Date:   Thu Feb 2 11:45:42 2012 -0600
> +
> +    Make opendir/closedir stash and forget directory names.
> +
> +    The dirfd(DIR *) interface allows you to get the fd for a DIR *,
> +    meaning you can use it with openat(), meaning you can need its
> +    path.  This causes a segfault.  Also gonna fix the base_path
> +    code not to segfault in that case, but first fix the underlying
> +    problem.
> +

Missing Upstream-Status: and Signed-off-by (yes I know we have an email 
header).

Thanks
	Sau!

> +diff --git a/ChangeLog.txt b/ChangeLog.txt
> +index 4de488c..9625b38 100644
> +--- a/ChangeLog.txt
> ++++ b/ChangeLog.txt
> +@@ -1,3 +1,7 @@
> ++2012-02-02:
> ++	* (seebs) stash dir name for DIR * from opendir using dirfd.
> ++	* (seebs) add closedir.
> ++
> + 2011-11-02:
> + 	* (seebs) Call this 1.2 because the UNLOAD change is moderately
> + 	  significant, and so's the clone change.
> +diff --git a/ports/unix/guts/closedir.c b/ports/unix/guts/closedir.c
> +new file mode 100644
> +index 0000000..1085361
> +--- /dev/null
> ++++ b/ports/unix/guts/closedir.c
> +@@ -0,0 +1,20 @@
> ++/*
> ++ * Copyright (c) 2012 Wind River Systems; see
> ++ * guts/COPYRIGHT for information.
> ++ *
> ++ * static int
> ++ * wrap_closedir(DIR *dirp) {
> ++ *	int rc = -1;
> ++ */
> ++	if (!dirp) {
> ++		errno = EFAULT;
> ++		return -1;
> ++	}
> ++
> ++	int fd = dirfd(dirp);
> ++	pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0);
> ++	rc = real_closedir(dirp);
> ++
> ++/*	return rc;
> ++ * }
> ++ */
> +diff --git a/ports/unix/guts/opendir.c b/ports/unix/guts/opendir.c
> +index 8eaa71f..e69717e 100644
> +--- a/ports/unix/guts/opendir.c
> ++++ b/ports/unix/guts/opendir.c
> +@@ -6,8 +6,25 @@
> +  * wrap_opendir(const char *path) {
> +  *	DIR * rc = NULL;
> +  */
> ++ 	struct stat buf;
> ++	int save_errno;
> +
> + 	rc = real_opendir(path);
> ++	if (rc) {
> ++		int fd;
> ++		save_errno = errno;
> ++		fd = dirfd(rc);
> ++		if (real_fstat(fd,&buf) == -1) {
> ++			pseudo_debug(1, "diropen (fd %d) succeeded, but fstat failed (%s).\n",
> ++				fd, strerror(errno));
> ++			pseudo_client_op_plain(OP_OPEN, PSA_READ, fd, -1, path, 0);
> ++		} else {
> ++			pseudo_client_op_plain(OP_OPEN, PSA_READ, fd, -1, path,&buf);
> ++		}
> ++
> ++
> ++		errno = save_errno;
> ++	}
> +
> + /*	return rc;
> +  * }
> +diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in
> +index e06e404..32250c4 100644
> +--- a/ports/unix/wrapfuncs.in
> ++++ b/ports/unix/wrapfuncs.in
> +@@ -21,6 +21,7 @@ long pathconf(const char *path, int name);
> + char *realpath(const char *name, char *resolved_name); /* version="GLIBC_2.3" */
> + int remove(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
> + DIR *opendir(const char *path);
> ++int closedir(DIR *dirp);
> + char *tempnam(const char *template, const char *pfx);
> + char *tmpnam(char *s);
> + int truncate(const char *path, off_t length);
> diff --git a/meta/recipes-devtools/pseudo/pseudo/renameat.patch b/meta/recipes-devtools/pseudo/pseudo/renameat.patch
> new file mode 100644
> index 0000000..74c8585
> --- /dev/null
> +++ b/meta/recipes-devtools/pseudo/pseudo/renameat.patch
> @@ -0,0 +1,227 @@
> +commit 795f2b44b7f692151556782f142a4a6e7d45d892
> +Author: Peter Seebach<peter.seebach at windriver.com>
> +Date:   Thu Feb 2 15:49:21 2012 -0600
> +
> +    Implement renameat()
> +
> +    After three long years, someone tried to use this.  This was impossibly
> +    hard back when pseudo was written, because there was only one dirfd
> +    provided for.  Thing is, now, the canonicalization happens in wrapfuncs,
> +    so a small tweak to makewrappers to recognize that oldpath should use
> +    olddirfd if it exists is enough to get us fully canonicalized paths
> +    when needed.
> +
> +    Also fix the crash if base_path gets called with an fd for which we have
> +    no path.
> +
> +diff --git a/ChangeLog.txt b/ChangeLog.txt
> +index 9625b38..25bd463 100644
> +--- a/ChangeLog.txt
> ++++ b/ChangeLog.txt
> +@@ -1,6 +1,9 @@
> + 2012-02-02:
> + 	* (seebs) stash dir name for DIR * from opendir using dirfd.
> + 	* (seebs) add closedir.
> ++	* (seebs) add initial pass at renameat()
> ++	* (seebs) in base_path, don't try to strlen the result if
> ++	  fd_path() returns NULL.
> +
> + 2011-11-02:
> + 	* (seebs) Call this 1.2 because the UNLOAD change is moderately
> +diff --git a/makewrappers b/makewrappers
> +index 20bbf2b..bf344d6 100755
> +--- a/makewrappers
> ++++ b/makewrappers
> +@@ -211,12 +211,13 @@ class Function:
> +         self.flags = '0'
> +         self.port = port
> +         self.directory = ''
> +-	self.version = 'NULL'
> ++        self.version = 'NULL'
> +         # On Darwin, some functions are SECRETLY converted to foo$INODE64
> +         # when called.  So we have to look those up for real_*
> +         self.inode64 = None
> +         self.real_func = None
> +         self.paths_to_munge = []
> ++        self.dirfds = {}
> +         self.hand_wrapped = None
> +         # used for the copyright date when creating stub functions
> +         self.date = datetime.date.today().year
> +@@ -239,6 +240,7 @@ class Function:
> +         # * If the arg has a name ending in 'path', we will canonicalize it.
> +         # * If the arg is named 'dirfd' or 'flags', it becomes the default
> +         #   values for the dirfd and flags arguments when canonicalizing.
> ++        # * If the name ends in dirfd, we do the same fancy stuff.
> +         # * Note that the "comments" field (/* ... */ after the decl) can
> +         #   override the dirfd/flags values.
> +         self.args = ArgumentList(bits.group(2))
> +@@ -246,7 +248,9 @@ class Function:
> +             # ignore varargs, they never get these special treatments
> +             if arg.vararg:
> +                 pass
> +-            elif arg.name == 'dirfd':
> ++            elif arg.name[-5:] == 'dirfd':
> ++                if len(arg.name)>  5:
> ++                    self.dirfds[arg.name[:-5]] = True
> +                 self.dirfd = 'dirfd'
> +             elif arg.name == 'flags':
> +                 self.flags = 'flags'
> +@@ -325,9 +329,13 @@ class Function:
> +         """create/allocate canonical paths"""
> +         alloc_paths = []
> +         for path in self.paths_to_munge:
> ++            prefix = path[:-4]
> ++	    if not prefix in self.dirfds:
> ++                prefix = ''
> ++            print "for path %s: prefix<%s>" % ( path, prefix )
> +             alloc_paths.append(
> +-                "%s = pseudo_root_path(__func__, __LINE__, %s, %s, %s);" %
> +-                (path, self.dirfd, path, self.flags))
> ++                "%s = pseudo_root_path(__func__, __LINE__, %s%s, %s, %s);" %
> ++                (path, prefix, self.dirfd, path, self.flags))
> +         return "\n\t\t\t".join(alloc_paths)
> +
> +     def free_paths(self):
> +diff --git a/ports/unix/guts/renameat.c b/ports/unix/guts/renameat.c
> +index c8203b7..f13cd1e 100644
> +--- a/ports/unix/guts/renameat.c
> ++++ b/ports/unix/guts/renameat.c
> +@@ -1,15 +1,111 @@
> + /*
> +- * Copyright (c) 2008-2010 Wind River Systems; see
> ++ * Copyright (c) 2008-2012 Wind River Systems; see
> +  * guts/COPYRIGHT for information.
> +  *
> +  * static int
> +  * wrap_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
> +  *	int rc = -1;
> +  */
> ++ 	pseudo_msg_t *msg;
> ++ 	struct stat oldbuf, newbuf;
> ++	int oldrc, newrc;
> ++	int save_errno;
> ++	int old_db_entry = 0;
> +
> +-	pseudo_diag("help! unimplemented renameat [%s ->  %s].\n", oldpath, newpath);
> ++	pseudo_debug(2, "renameat: %d,%s->%d,%s\n",
> ++		olddirfd, oldpath ? oldpath : "<nil>",
> ++		newdirfd, newpath ? newpath : "<nil>");
> ++
> ++#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
> ++	if (olddirfd != AT_FDCWD || newdirfd != AT_FDCWD) {
> ++		errno = ENOSYS;
> ++		return -1;
> ++	}
> ++#endif
> ++
> ++	if (!oldpath || !newpath) {
> ++		errno = EFAULT;
> ++		return -1;
> ++	}
> ++
> ++	save_errno = errno;
> ++
> ++#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
> ++	newrc = real_lstat(newpath,&newbuf);
> ++	oldrc = real_lstat(oldpath,&oldbuf);
> ++#else
> ++	oldrc = real___fxstatat(_STAT_VER, olddirfd, oldpath,&oldbuf, AT_SYMLINK_NOFOLLOW);
> ++	newrc = real___fxstatat(_STAT_VER, newdirfd, newpath,&newbuf, AT_SYMLINK_NOFOLLOW);
> ++#endif
> ++
> ++	errno = save_errno;
> ++
> ++	/* newpath must be removed. */
> ++	/* as with unlink, we have to mark that the file may get deleted */
> ++	msg = pseudo_client_op_plain(OP_MAY_UNLINK, 0, -1, newdirfd, newpath, newrc ? NULL :&newbuf);
> ++	if (msg&&  msg->result == RESULT_SUCCEED)
> ++		old_db_entry = 1;
> + 	rc = real_renameat(olddirfd, oldpath, newdirfd, newpath);
> ++	save_errno = errno;
> ++	if (old_db_entry) {
> ++		if (rc == -1) {
> ++			/* since we failed, that wasn't really unlinked -- put
> ++			 * it back.
> ++			 */
> ++			pseudo_client_op_plain(OP_CANCEL_UNLINK, 0, -1, newdirfd, newpath,&newbuf);
> ++		} else {
> ++			/* confirm that the file was removed */
> ++			pseudo_client_op_plain(OP_DID_UNLINK, 0, -1, newdirfd, newpath,&newbuf);
> ++		}
> ++	}
> ++	if (rc == -1) {
> ++		/* and we're done. */
> ++		errno = save_errno;
> ++		return rc;
> ++	}
> ++	save_errno = errno;
> ++	/* nothing to do for a "rename" of a link to itself */
> ++	if (newrc != -1&&  oldrc != -1&&
> ++	    newbuf.st_dev == oldbuf.st_dev&&
> ++	    newbuf.st_ino == oldbuf.st_ino) {
> ++		return rc;
> ++        }
> ++
> ++	/* rename(3) is not mv(1).  rename(file, dir) fails; you must provide
> ++	 * the corrected path yourself.  You can rename over a directory only
> ++	 * if the source is a directory.  Symlinks are simply removed.
> ++	 *
> ++	 * If we got here, the real rename call succeeded.  That means newpath
> ++	 * has been unlinked and oldpath has been linked to it.
> ++	 *
> ++	 * There are a ton of special cases to error check.  I don't check
> ++	 * for any of them, because in every such case, the underlying rename
> ++	 * failed, and there is nothing to do.
> ++	 * The only tricky part is that, because we used to ignore symlinks,
> ++	 * we may have to rename or remove directory trees even though in
> ++	 * theory rename can never destroy a directory tree.
> ++	 */
> ++	if (!old_db_entry) {
> ++		/* create an entry under the old name, which will then be
> ++		 * renamed; this way, children would get renamed too, if there
> ++		 * were any.
> ++		 */
> ++		if (newrc == 0) {
> ++			if (newbuf.st_dev != oldbuf.st_dev) {
> ++				oldbuf.st_dev = newbuf.st_dev;
> ++				oldbuf.st_ino = newbuf.st_ino;
> ++			}
> ++		}
> ++		pseudo_debug(1, "creating new '%s' [%llu] to rename\n",
> ++			oldpath, (unsigned long long) oldbuf.st_ino);
> ++		pseudo_client_op_plain(OP_LINK, 0, -1, olddirfd, oldpath,&oldbuf);
> ++	}
> ++	/* special case: use 'fd' for olddirfd, because
> ++	 * we know it has no other meaning for RENAME
> ++	 */
> ++	pseudo_client_op_plain(OP_RENAME, 0, olddirfd, newdirfd, newpath,&oldbuf, oldpath);
> +
> ++	errno = save_errno;
> + /*	return rc;
> +  * }
> +  */
> +diff --git a/pseudo_client.c b/pseudo_client.c
> +index 48607c2..4a30420 100644
> +--- a/pseudo_client.c
> ++++ b/pseudo_client.c
> +@@ -988,6 +988,8 @@ base_path(int dirfd, const char *path, int leave_last) {
> + 		if (dirfd != -1&&  dirfd != AT_FDCWD) {
> + 			if (dirfd>= 0) {
> + 				basepath = fd_path(dirfd);
> ++			}
> ++			if (basepath) {
> + 				baselen = strlen(basepath);
> + 			} else {
> + 				pseudo_diag("got *at() syscall for unknown directory, fd %d\n", dirfd);
> +@@ -1128,7 +1130,10 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
> + 	if (path) {
> + 		pseudo_debug(2, " %s", path);
> + 	}
> +-	if (fd != -1) {
> ++	/* for OP_RENAME in renameat, "fd" is also used for the
> ++	 * second dirfd.
> ++	 */
> ++	if (fd != -1&&  op != OP_RENAME) {
> + 		pseudo_debug(2, " [fd %d]", fd);
> + 	}
> + 	if (buf) {
> diff --git a/meta/recipes-devtools/pseudo/pseudo_1.2.bb b/meta/recipes-devtools/pseudo/pseudo_1.2.bb
> index f2ebc22..04bcbce 100644
> --- a/meta/recipes-devtools/pseudo/pseudo_1.2.bb
> +++ b/meta/recipes-devtools/pseudo/pseudo_1.2.bb
> @@ -1,10 +1,12 @@
>   require pseudo.inc
>
> -PR = "r4"
> +PR = "r5"
>
>   SRC_URI = "http://www.yoctoproject.org/downloads/${BPN}/${BPN}-${PV}.tar.bz2 \
>              file://oe-config.patch \
> -           file://static_sqlite.patch"
> +           file://static_sqlite.patch \
> +           file://opendir.patch \
> +           file://renameat.patch"
>
>   SRC_URI[md5sum] = "a2819084bab7e991f06626d02cf55048"
>   SRC_URI[sha256sum] = "4749a22df687f44d24c26e97170d4781a1bd52d5ee092364a40877e4d96ff058"




More information about the Openembedded-core mailing list