From 41936cd5bcfddfbf3374174c1e3cdea951d2d10f Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Fri, 3 Feb 2012 00:03:33 -0800 Subject: pseudo: Wrap renameat and opendir (From OE-Core rev: f6056cf0e7c76f2f3df650b088ce84df41ec14ca) Signed-off-by: Khem Raj Signed-off-by: Richard Purdie --- meta/recipes-devtools/pseudo/pseudo/opendir.patch | 94 +++++++++ meta/recipes-devtools/pseudo/pseudo/renameat.patch | 229 +++++++++++++++++++++ meta/recipes-devtools/pseudo/pseudo_1.2.bb | 6 +- 3 files changed, 327 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 0000000000..bc6cec8e7e --- /dev/null +++ b/meta/recipes-devtools/pseudo/pseudo/opendir.patch @@ -0,0 +1,94 @@ +commit 162f2692c399b93311652201a940fdaf9c9e6924 +Author: Peter Seebach +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. + +Upstream-Status: Backport + +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 0000000000..a2b2cbc78c --- /dev/null +++ b/meta/recipes-devtools/pseudo/pseudo/renameat.patch @@ -0,0 +1,229 @@ +commit 795f2b44b7f692151556782f142a4a6e7d45d892 +Author: Peter Seebach +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. + +Upstream-Status: Backport + +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 : "", ++ newdirfd, newpath ? newpath : ""); ++ ++#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 f2ebc228d9..04bcbce1ea 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" -- cgit v1.2.3-54-g00ecf