diff options
42 files changed, 755 insertions, 64 deletions
diff --git a/enums/debug_type.in b/enums/debug_type.in index 4e3126e..f4de3ab 100644 --- a/enums/debug_type.in +++ b/enums/debug_type.in @@ -25,3 +25,4 @@ ipc, 'i', "client/server interactions" invoke, 'k', "invocation and launching" benchmark, 'b', "performance statistics" verbose, 'V', "extra detail" +xattr, 'x', "extended attributes" diff --git a/enums/op.in b/enums/op.in index 3b8e23e..61ee666 100644 --- a/enums/op.in +++ b/enums/op.in @@ -21,3 +21,9 @@ exec, 0 may-unlink, 1 did-unlink, 0 cancel-unlink, 0 +get-xattr, 1 +list-xattr, 1 +remove-xattr, 1 +set-xattr, 0 +create-xattr, 1 +replace-xattr, 1 diff --git a/ports/linux/guts/fgetxattr.c b/ports/linux/noxattr/guts/fgetxattr.c index 9d33643..9d33643 100644 --- a/ports/linux/guts/fgetxattr.c +++ b/ports/linux/noxattr/guts/fgetxattr.c diff --git a/ports/linux/guts/flistxattr.c b/ports/linux/noxattr/guts/flistxattr.c index 77db021..77db021 100644 --- a/ports/linux/guts/flistxattr.c +++ b/ports/linux/noxattr/guts/flistxattr.c diff --git a/ports/linux/guts/fremovexattr.c b/ports/linux/noxattr/guts/fremovexattr.c index 529a9de..529a9de 100644 --- a/ports/linux/guts/fremovexattr.c +++ b/ports/linux/noxattr/guts/fremovexattr.c diff --git a/ports/linux/guts/fsetxattr.c b/ports/linux/noxattr/guts/fsetxattr.c index 3c56ddd..3c56ddd 100644 --- a/ports/linux/guts/fsetxattr.c +++ b/ports/linux/noxattr/guts/fsetxattr.c diff --git a/ports/linux/guts/getxattr.c b/ports/linux/noxattr/guts/getxattr.c index fe8912d..fe8912d 100644 --- a/ports/linux/guts/getxattr.c +++ b/ports/linux/noxattr/guts/getxattr.c diff --git a/ports/linux/guts/lgetxattr.c b/ports/linux/noxattr/guts/lgetxattr.c index 404211f..404211f 100644 --- a/ports/linux/guts/lgetxattr.c +++ b/ports/linux/noxattr/guts/lgetxattr.c diff --git a/ports/linux/guts/listxattr.c b/ports/linux/noxattr/guts/listxattr.c index 1b0b5e7..1b0b5e7 100644 --- a/ports/linux/guts/listxattr.c +++ b/ports/linux/noxattr/guts/listxattr.c diff --git a/ports/linux/guts/llistxattr.c b/ports/linux/noxattr/guts/llistxattr.c index a33f970..a33f970 100644 --- a/ports/linux/guts/llistxattr.c +++ b/ports/linux/noxattr/guts/llistxattr.c diff --git a/ports/linux/guts/lremovexattr.c b/ports/linux/noxattr/guts/lremovexattr.c index 38429da..38429da 100644 --- a/ports/linux/guts/lremovexattr.c +++ b/ports/linux/noxattr/guts/lremovexattr.c diff --git a/ports/linux/guts/lsetxattr.c b/ports/linux/noxattr/guts/lsetxattr.c index 140ae8d..140ae8d 100644 --- a/ports/linux/guts/lsetxattr.c +++ b/ports/linux/noxattr/guts/lsetxattr.c diff --git a/ports/linux/guts/removexattr.c b/ports/linux/noxattr/guts/removexattr.c index cd7f486..cd7f486 100644 --- a/ports/linux/guts/removexattr.c +++ b/ports/linux/noxattr/guts/removexattr.c diff --git a/ports/linux/guts/setxattr.c b/ports/linux/noxattr/guts/setxattr.c index de2de98..de2de98 100644 --- a/ports/linux/guts/setxattr.c +++ b/ports/linux/noxattr/guts/setxattr.c diff --git a/ports/linux/noxattr/wrapfuncs.in b/ports/linux/noxattr/wrapfuncs.in new file mode 100644 index 0000000..de22ae1 --- /dev/null +++ b/ports/linux/noxattr/wrapfuncs.in @@ -0,0 +1,14 @@ +# we use "pathname" to avoid canonicalizing paths, because these functions are +# unimplemented +ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size); +ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size); +ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); +ssize_t listxattr(const char *pathname, char *list, size_t size); +ssize_t llistxattr(const char *pathname, char *list, size_t size); +ssize_t flistxattr(int filedes, char *list, size_t size); +int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); +int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); +int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); +int removexattr(const char *pathname, const char *name); +int lremovexattr(const char *pathname, const char *name); +int fremovexattr(int filedes, const char *name); diff --git a/ports/linux/subports b/ports/linux/subports index 02a4688..b68c25b 100755 --- a/ports/linux/subports +++ b/ports/linux/subports @@ -25,3 +25,8 @@ rm -f dummy.c dummy.o if ! $found; then echo >&2 "Can't tell, omitting clone(2) support." fi +if getfattr --help >/dev/null 2>&1; then + echo "linux/xattr" +else + echo "linux/noxattr" +fi diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in index 1ffdb3a..e2b661b 100644 --- a/ports/linux/wrapfuncs.in +++ b/ports/linux/wrapfuncs.in @@ -13,20 +13,6 @@ int fcntl(int fd, int cmd, ...{struct flock *lock}); # just so we know the inums of symlinks char *canonicalize_file_name(const char *filename); int eaccess(const char *path, int mode); -# we use "pathname" to avoid canonicalizing paths, because these functions are -# unimplemented -ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size); -ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size); -ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); -ssize_t listxattr(const char *pathname, char *list, size_t size); -ssize_t llistxattr(const char *pathname, char *list, size_t size); -ssize_t flistxattr(int filedes, char *list, size_t size); -int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); -int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags); -int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); -int removexattr(const char *pathname, const char *name); -int lremovexattr(const char *pathname, const char *name); -int fremovexattr(int filedes, const char *name); int open64(const char *path, int flags, ...{mode_t mode}); /* flags=0 */ int openat64(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=0 */ int __openat64_2(int dirfd, const char *path, int flags); /* flags=0 */ diff --git a/ports/linux/xattr/guts/fgetxattr.c b/ports/linux/xattr/guts/fgetxattr.c new file mode 100644 index 0000000..ae8c3a3 --- /dev/null +++ b/ports/linux/xattr/guts/fgetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(NULL, filedes, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/flistxattr.c b/ports/linux/xattr/guts/flistxattr.c new file mode 100644 index 0000000..cdd9454 --- /dev/null +++ b/ports/linux/xattr/guts/flistxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t flistxattr(int filedes, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(NULL, filedes, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/fremovexattr.c b/ports/linux/xattr/guts/fremovexattr.c new file mode 100644 index 0000000..a029d2c --- /dev/null +++ b/ports/linux/xattr/guts/fremovexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fremovexattr(int filedes, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(NULL, filedes, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/fsetxattr.c b/ports/linux/xattr/guts/fsetxattr.c new file mode 100644 index 0000000..cbed2ea --- /dev/null +++ b/ports/linux/xattr/guts/fsetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + rc = shared_setxattr(NULL, filedes, name, value, size, flags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/getxattr.c b/ports/linux/xattr/guts/getxattr.c new file mode 100644 index 0000000..7bd2bf5 --- /dev/null +++ b/ports/linux/xattr/guts/getxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t getxattr(const char *path, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(path, -1, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lgetxattr.c b/ports/linux/xattr/guts/lgetxattr.c new file mode 100644 index 0000000..675d3da --- /dev/null +++ b/ports/linux/xattr/guts/lgetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) + * ssize_t rc = -1; + */ + rc = shared_getxattr(path, -1, name, value, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/listxattr.c b/ports/linux/xattr/guts/listxattr.c new file mode 100644 index 0000000..0decf71 --- /dev/null +++ b/ports/linux/xattr/guts/listxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t listxattr(const char *path, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(path, -1, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/llistxattr.c b/ports/linux/xattr/guts/llistxattr.c new file mode 100644 index 0000000..9934256 --- /dev/null +++ b/ports/linux/xattr/guts/llistxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * ssize_t llistxattr(const char *path, char *list, size_t size) + * ssize_t rc = -1; + */ + rc = shared_listxattr(path, -1, list, size); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lremovexattr.c b/ports/linux/xattr/guts/lremovexattr.c new file mode 100644 index 0000000..1f39788 --- /dev/null +++ b/ports/linux/xattr/guts/lremovexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lremovexattr(const char *path, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(path, -1, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/lsetxattr.c b/ports/linux/xattr/guts/lsetxattr.c new file mode 100644 index 0000000..b167b15 --- /dev/null +++ b/ports/linux/xattr/guts/lsetxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + rc = shared_setxattr(path, -1, name, value, size, flags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/removexattr.c b/ports/linux/xattr/guts/removexattr.c new file mode 100644 index 0000000..0d4d8e3 --- /dev/null +++ b/ports/linux/xattr/guts/removexattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int removexattr(const char *path, const char *name) + * int rc = -1; + */ + rc = shared_removexattr(path, -1, name); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/guts/setxattr.c b/ports/linux/xattr/guts/setxattr.c new file mode 100644 index 0000000..dd85252 --- /dev/null +++ b/ports/linux/xattr/guts/setxattr.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * int setxattr(const char *path, const char *name, const void *value, size_t size, int flags) + * int rc = -1; + */ + rc = shared_setxattr(path, -1, name, value, size, flags); + +/* return rc; + * } + */ diff --git a/ports/linux/xattr/portdefs.h b/ports/linux/xattr/portdefs.h new file mode 100644 index 0000000..ec030b7 --- /dev/null +++ b/ports/linux/xattr/portdefs.h @@ -0,0 +1 @@ +#include <attr/xattr.h> diff --git a/ports/linux/xattr/pseudo_wrappers.c b/ports/linux/xattr/pseudo_wrappers.c new file mode 100644 index 0000000..7fe44a6 --- /dev/null +++ b/ports/linux/xattr/pseudo_wrappers.c @@ -0,0 +1,117 @@ +/* shared functionality for the xattr code */ +/* Each of these functions is expecting to get an optional name, and + * a populated statbuf to use for sending messages to the server. + */ + +#define RC_AND_BUF \ + int rc; \ + PSEUDO_STATBUF buf; \ + if (path) { \ + rc = base_lstat(path, &buf); \ + } else { \ + rc = base_fstat(fd, &buf); \ + } \ + if (rc == -1) { \ + return rc; \ + } + +static ssize_t shared_getxattr(const char *path, int fd, const char *name, void *value, size_t size) { + RC_AND_BUF + + pseudo_debug(PDBGF_XATTR, "getxattr(%s/%d, %s)\n", + path ? path : "<no path>", fd, name); + pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name); + if (result->result != RESULT_SUCCEED) { + errno = ENOATTR; + return -1; + } + + if (value) { + pseudo_debug(PDBGF_XATTR, "returned attributes: '%s' (%d bytes)\n", + result->path, result->pathlen); + if (size >= result->pathlen) { + memcpy(value, result->path, result->pathlen); + } else { + memcpy(value, result->path, size); + errno = ERANGE; + } + } + return result->pathlen; +} + +static int shared_setxattr(const char *path, int fd, const char *name, const void *value, size_t size, int flags) { + RC_AND_BUF + + char *combined; + size_t nlen = strlen(name); + size_t combined_len = nlen + size + 1; + combined = malloc(combined_len + 1); + memcpy(combined, name, nlen); + combined[nlen] = '\0'; + memcpy(combined + nlen + 1, value, size); + combined[combined_len] = '\0'; + + pseudo_debug(PDBGF_XATTR, "setxattr(%s/%d, %s, %s => %s [%d])\n", + path ? path : "<no path>", fd, name, (char *) value, combined + nlen + 1, (int) size); + + pseudo_op_t op; + switch (flags) { + case XATTR_CREATE: + op = OP_CREATE_XATTR; + break; + case XATTR_REPLACE: + op = OP_REPLACE_XATTR; + break; + default: + op = OP_SET_XATTR; + break; + } + + pseudo_msg_t *result = pseudo_client_op(op, 0, fd, -1, path, &buf, combined, combined_len); + + /* we automatically assume success */ + if (op == OP_SET_XATTR) { + return 0; + } + + /* CREATE/REPLACE operations can report failure */ + if (!result || result->result == RESULT_FAIL) { + return -1; + } + + return 0; +} + +static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size) { + RC_AND_BUF + pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf); + if (result->result != RESULT_SUCCEED) { + pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n"); + errno = ENOATTR; + return -1; + } + if (list) { + pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of names, starting '%.*s'\n", + (int) result->pathlen, (int) result->pathlen, result->path); + if (size >= result->pathlen) { + memcpy(list, result->path, result->pathlen); + } else { + memcpy(list, result->path, size); + errno = ERANGE; + } + } + return result->pathlen; +} + +static int shared_removexattr(const char *path, int fd, const char *name) { + RC_AND_BUF + pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name); + + if (result->result != RESULT_SUCCEED) { + /* docs say ENOATTR, but I don't have one */ + errno = ENOENT; + return -1; + } + return 0; +} + diff --git a/ports/linux/xattr/wrapfuncs.in b/ports/linux/xattr/wrapfuncs.in new file mode 100644 index 0000000..edfc788 --- /dev/null +++ b/ports/linux/xattr/wrapfuncs.in @@ -0,0 +1,12 @@ +ssize_t getxattr(const char *path, const char *name, void *value, size_t size) /* flags=0 */; +ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) /* flags=AT_SYMLINK_NOFOLLOW */; +ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); +int setxattr(const char *path, const char *name, const void *value, size_t size, int flags) /* flags=0 */; +int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) /* flags=AT_SYMLINK_NOFOLLOW */; +int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); +ssize_t listxattr(const char *path, char *list, size_t size) /* flags=0 */; +ssize_t llistxattr(const char *path, char *list, size_t size) /* flags=AT_SYMLINK_NOFOLLOW */; +ssize_t flistxattr(int filedes, char *list, size_t size); +int removexattr(const char *path, const char *name) /* flags=0 */; +int lremovexattr(const char *path, const char *name) /* flags=AT_SYMLINK_NOFOLLOW */; +int fremovexattr(int filedes, const char *name); @@ -51,7 +51,7 @@ long opt_p = 0; char *opt_r = NULL; int opt_S = 0; -static int pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag); +static int pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len); static int pseudo_db_check(int fix); void @@ -318,7 +318,7 @@ main(int argc, char *argv[]) { pseudo_diag("Couldn't allocate data structure for path.\n"); exit(EXIT_FAILURE); } - if (pdb_find_file_path(msg)) { + if (pdb_find_file_path(msg, NULL)) { pseudo_diag("Couldn't find a database entry for '%s'.\n", opt_i); exit(EXIT_FAILURE); } @@ -485,14 +485,17 @@ main(int argc, char *argv[]) { * sanity checks, then implements the fairly small DB changes required. */ int -pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { +pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len) { pseudo_msg_t msg_header; pseudo_msg_t by_path = { .op = 0 }, by_ino = { .op = 0 }; + long long row = -1; pseudo_msg_t db_header; char *path_by_ino = 0; char *oldpath = 0; + size_t oldpathlen = 0; int found_path = 0, found_ino = 0; int prefer_ino = 0; + int xattr_flags = 0; if (!msg) return 1; @@ -520,11 +523,23 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { * stuff into a rename, break them apart (null seperated) */ - if (msg->pathlen && msg->op == OP_RENAME) { - /* In a rename there are two paths, null seperate in msg->path */ - oldpath = msg->path + strlen(msg->path) + 1; - pseudo_debug(PDBGF_OP | PDBGF_FILE, "rename: path %s, oldpath %s\n", - msg->path, oldpath); + if (msg->pathlen) { + switch (msg->op) { + case OP_RENAME: + case OP_CREATE_XATTR: + case OP_GET_XATTR: + case OP_LIST_XATTR: + case OP_REPLACE_XATTR: + case OP_SET_XATTR: + /* In a rename there are two paths, null separated in msg->path */ + oldpath = msg->path + strlen(msg->path) + 1; + oldpathlen = msg->pathlen - (oldpath - msg->path); + pseudo_debug(PDBGF_OP | PDBGF_FILE | PDBGF_XATTR, "%s: path '%s', oldpath '%s' [%d]\n", + pseudo_op_name(msg->op), msg->path, oldpath, (int) oldpathlen); + break; + default: + break; + } } /* stash original header, in case we need it later */ @@ -537,7 +552,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { /* Lookup the full path, with inode and dev if available */ if (msg->pathlen && msg->dev && msg->ino) { - if (!pdb_find_file_exact(msg)) { + if (!pdb_find_file_exact(msg, &row)) { /* restore header contents */ by_path = *msg; by_ino = *msg; @@ -553,7 +568,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { if (msg->pathlen) { /* for now, don't canonicalize paths anymore */ /* used to do it here, but now doing it in client */ - if (!pdb_find_file_path(msg)) { + if (!pdb_find_file_path(msg, &row)) { by_path = *msg; found_path = 1; } else { @@ -564,7 +579,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { } /* search on original inode -- in case of mismatch */ if (msg->dev && msg->ino) { - if (!pdb_find_file_dev(&by_ino)) { + if (!pdb_find_file_dev(&by_ino, &row)) { found_ino = 1; path_by_ino = pdb_get_file_path(&by_ino); } @@ -760,7 +775,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { pdb_unlink_file_dev(&by_ino); } if (!found_path) { - pdb_link_file(msg); + pdb_link_file(msg, NULL); } else { /* again, an error, but leaving it alone for now. */ pseudo_diag("creat ignored for existing file '%s'.\n", @@ -790,7 +805,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { /* if the path is not known, link it */ if (!found_path) { pseudo_debug(PDBGF_FILE, "(new) "); - pdb_link_file(msg); + pdb_link_file(msg, NULL); } break; case OP_CHOWN: /* FALLTHROUGH */ @@ -816,7 +831,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { } /* if the path is not known, link it */ if (!found_path) { - pdb_link_file(msg); + pdb_link_file(msg, NULL); } break; case OP_STAT: /* FALLTHROUGH */ @@ -871,7 +886,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { } else { *msg = msg_header; } - pdb_link_file(msg); + pdb_link_file(msg, NULL); break; case OP_RENAME: /* a rename implies renaming an existing entry... and every @@ -933,7 +948,46 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { pdb_unlink_file_dev(&by_ino); } *msg = msg_header; - pdb_link_file(msg); + pdb_link_file(msg, NULL); + break; + case OP_GET_XATTR: + if (pdb_get_xattr(row, &oldpath, &oldpathlen)) { + msg->result = RESULT_FAIL; + } else { + *response_path = oldpath; + *response_len = oldpathlen; + pseudo_debug(PDBGF_XATTR, "get results: '%s' (%d bytes)\n", + *response_path, (int) *response_len); + } + break; + case OP_LIST_XATTR: + if (pdb_list_xattr(row, &oldpath, &oldpathlen)) { + msg->result = RESULT_FAIL; + } else { + pseudo_debug(PDBGF_XATTR, "got %d bytes of xattrs to list: %.*s\n", (int) oldpathlen, (int) oldpathlen, oldpath); + *response_path = oldpath; + *response_len = oldpathlen; + } + break; + case OP_CREATE_XATTR: + case OP_REPLACE_XATTR: /* fallthrough */ + if (msg->op == OP_CREATE_XATTR) { + xattr_flags = XATTR_CREATE; + } + if (msg->op == OP_REPLACE_XATTR) { + xattr_flags = XATTR_REPLACE; + } + case OP_SET_XATTR: + /* we need a row entry to store xattr info */ + if (row == -1) { + pdb_link_file(msg, &row); + } + if (pdb_set_xattr(row, oldpath, oldpathlen, xattr_flags)) { + msg->result = RESULT_FAIL; + } + break; + case OP_REMOVE_XATTR: + pdb_remove_xattr(row, oldpath, oldpathlen); break; default: pseudo_diag("unknown op from client %d, op %d [%s]\n", @@ -956,7 +1010,7 @@ pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) { /* SHUTDOWN does not get this far, it's handled in pseudo_server.c */ int -pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag) { +pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len) { switch (msg->type) { case PSEUDO_MSG_PING: msg->result = RESULT_SUCCEED; @@ -966,7 +1020,7 @@ pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag) break; case PSEUDO_MSG_OP: case PSEUDO_MSG_FASTOP: - return pseudo_op(msg, program, tag); + return pseudo_op(msg, program, tag, response_path, response_len); break; case PSEUDO_MSG_ACK: /* FALLTHROUGH */ case PSEUDO_MSG_NAK: /* FALLTHROUGH */ @@ -134,4 +134,12 @@ extern char *pseudo_version; */ #define PSEUDO_LINK_SYMLINK_BEHAVIOR 0 +/* given n, pick a multiple of block enough bigger than n + * to give us some breathing room. + */ +static inline size_t +round_up(size_t n, size_t block) { + return block * (((n + block / 4) / block) + 1); +} + #include "pseudo_ports.h" diff --git a/pseudo_client.c b/pseudo_client.c index 2134c8e..40985e6 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -1056,6 +1056,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path size_t pathlen = -1; int do_request = 0; char *oldpath = 0; + size_t oldpathlen = 0; char *alloced_path = 0; /* disable wrappers */ @@ -1073,6 +1074,11 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path pseudo_magic(); return 0; } + /* we have to calculate this here, because SET_XATTR + * and friends will be using oldpath to hold a hunk of + * data of arbitrary length + */ + oldpathlen = strlen(oldpath); if (!path) { pseudo_diag("rename (%s) without new path.\n", path ? path : "<nil>"); @@ -1081,6 +1087,28 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path } } + /* we treat the "create" and "replace" flags as logically + * distinct operations, because they can fail when set can't. + */ + if (op == OP_SET_XATTR || op == OP_CREATE_XATTR || op == OP_REPLACE_XATTR) { + va_list ap; + va_start(ap, buf); + oldpath = va_arg(ap, char *); + oldpathlen = va_arg(ap, size_t); + pseudo_debug(PDBGF_XATTR, "setxattr, oldpath (%d bytes): '%s'\n", + (int) oldpathlen, oldpath); + va_end(ap); + } + if (op == OP_GET_XATTR){ + va_list ap; + va_start(ap, buf); + oldpath = va_arg(ap, char *); + oldpathlen = strlen(oldpath); + pseudo_debug(PDBGF_XATTR, "getxattr, oldpath (%d bytes): '%s'\n", + (int) oldpathlen, oldpath); + va_end(ap); + } + if (path) { /* path fixup has to happen in the specific functions, * because they may have to make calls which have to be @@ -1093,16 +1121,18 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path pathlen = strlen(path) + 1; int strip_slash = (pathlen > 2 && (path[pathlen - 2]) == '/'); if (oldpath) { - size_t full_len = strlen(oldpath) + 1 + pathlen; + size_t full_len = oldpathlen + 1 + pathlen; + size_t partial_len = pathlen - 1 - strip_slash; char *both_paths = malloc(full_len); if (!both_paths) { pseudo_diag("Can't allocate space for paths for a rename operation. Sorry.\n"); pseudo_magic(); return 0; } - snprintf(both_paths, full_len, "%.*s%c%s", - (int) (pathlen - 1 - strip_slash), - path, 0, oldpath); + memcpy(both_paths, path, partial_len); + both_paths[partial_len] = '\0'; + memcpy(both_paths + partial_len + 1, oldpath, oldpathlen); + both_paths[full_len - 1] = '\0'; pseudo_debug(PDBGF_PATH | PDBGF_FILE, "rename: %s -> %s [%d]\n", both_paths + pathlen, both_paths, (int) full_len); alloced_path = both_paths; @@ -1239,6 +1269,10 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path case OP_DID_UNLINK: case OP_CANCEL_UNLINK: case OP_MAY_UNLINK: + case OP_GET_XATTR: + case OP_LIST_XATTR: + case OP_SET_XATTR: + case OP_REMOVE_XATTR: do_request = 1; break; default: diff --git a/pseudo_db.c b/pseudo_db.c index 0d6f5ca..2faeb10 100644 --- a/pseudo_db.c +++ b/pseudo_db.c @@ -85,6 +85,13 @@ static struct sql_table { "rdev INTEGER", NULL, NULL }, + { "xattrs", + "id INTEGER PRIMARY KEY, " + "file_id INTEGER REFERENCES files(id) ON DELETE CASCADE, " + "name VARCHAR, " + "value VARCHAR", + NULL, + NULL }, { NULL, NULL, NULL, NULL }, }, log_tables[] = { { "logs", @@ -114,6 +121,7 @@ static struct sql_index { /* { "files__path", "files", "path" }, */ { "files__path_dev_ino", "files", "path, dev, ino" }, { "files__dev_ino", "files", "dev, ino" }, + { "xattrs__file", "xattrs", "file_id" }, { NULL, NULL, NULL }, }, log_indexes[] = { { NULL, NULL, NULL }, @@ -136,6 +144,7 @@ static char *file_pragmas[] = { * need. */ "PRAGMA synchronous = OFF;", + "PRAGMA foreign_keys = ON;", NULL }; @@ -365,6 +374,7 @@ make_tables(sqlite3 *db, for (i = 0; sql_tables[i].name; ++i) { found = 0; + printf("considering table %s\n", sql_tables[i].name); for (j = 1; j <= rows; ++j) { if (!strcmp(existing[j], sql_tables[i].name)) { found = 1; @@ -587,6 +597,8 @@ get_db(struct database_info *dbinfo) { if (dbinfo->pragmas) { for (i = 0; dbinfo->pragmas[i]; ++i) { rc = sqlite3_exec(db, dbinfo->pragmas[i], NULL, NULL, &errmsg); + pseudo_debug(PDBGF_SQL | PDBGF_VERBOSE, "executed pragma: '%s', rc %d.\n", + dbinfo->pragmas[i], rc); if (rc) { dberr(db, dbinfo->pragmas[i]); } @@ -1356,7 +1368,7 @@ log_entry_free(log_entry *e) { * or 'NAMELESS FILE'. */ int -pdb_link_file(pseudo_msg_t *msg) { +pdb_link_file(pseudo_msg_t *msg, long long *row) { static sqlite3_stmt *insert; int rc; char *sql = "INSERT INTO files " @@ -1397,6 +1409,10 @@ pdb_link_file(pseudo_msg_t *msg) { if (rc != SQLITE_DONE) { dberr(file_db, "insert may have failed (rc %d)", rc); } + /* some users care what the row ID is */ + if (row) { + *row = sqlite3_last_insert_rowid(file_db); + } sqlite3_reset(insert); sqlite3_clear_bindings(insert); return rc != SQLITE_DONE; @@ -1933,7 +1949,7 @@ pdb_update_file(pseudo_msg_t *msg) { /* find file using both path AND dev/inode as key */ int -pdb_find_file_exact(pseudo_msg_t *msg) { +pdb_find_file_exact(pseudo_msg_t *msg, long long *row) { static sqlite3_stmt *select; int rc; char *sql = "SELECT * FROM files WHERE path = ? AND dev = ? AND ino = ?;"; @@ -1961,6 +1977,9 @@ pdb_find_file_exact(pseudo_msg_t *msg) { rc = sqlite3_step(select); switch (rc) { case SQLITE_ROW: + if (row) { + *row = sqlite3_column_int64(select, 0); + } msg->uid = (unsigned long) sqlite3_column_int64(select, 4); msg->gid = (unsigned long) sqlite3_column_int64(select, 5); msg->mode = (unsigned long) sqlite3_column_int64(select, 6); @@ -1984,7 +2003,7 @@ pdb_find_file_exact(pseudo_msg_t *msg) { /* find file using path as a key */ int -pdb_find_file_path(pseudo_msg_t *msg) { +pdb_find_file_path(pseudo_msg_t *msg, long long *row) { static sqlite3_stmt *select; int rc; char *sql = "SELECT * FROM files WHERE path = ?;"; @@ -2015,6 +2034,9 @@ pdb_find_file_path(pseudo_msg_t *msg) { rc = sqlite3_step(select); switch (rc) { case SQLITE_ROW: + if (row) { + *row = sqlite3_column_int64(select, 0); + } msg->dev = sqlite3_column_int64(select, 2); msg->ino = sqlite3_column_int64(select, 3); msg->uid = sqlite3_column_int64(select, 4); @@ -2090,7 +2112,7 @@ pdb_get_file_path(pseudo_msg_t *msg) { /* find file using dev/inode as key */ int -pdb_find_file_dev(pseudo_msg_t *msg) { +pdb_find_file_dev(pseudo_msg_t *msg, long long *row) { static sqlite3_stmt *select; int rc; char *sql = "SELECT * FROM files WHERE dev = ? AND ino = ?;"; @@ -2114,6 +2136,9 @@ pdb_find_file_dev(pseudo_msg_t *msg) { rc = sqlite3_step(select); switch (rc) { case SQLITE_ROW: + if (row) { + *row = sqlite3_column_int64(select, 0); + } msg->uid = (unsigned long) sqlite3_column_int64(select, 4); msg->gid = (unsigned long) sqlite3_column_int64(select, 5); msg->mode = (unsigned long) sqlite3_column_int64(select, 6); @@ -2135,11 +2160,286 @@ pdb_find_file_dev(pseudo_msg_t *msg) { return rc; } +int +pdb_get_xattr(long long file_id, char **value, size_t *len) { + static sqlite3_stmt *select; + int rc; + char *response; + size_t length; + char *sql = "SELECT value FROM xattrs WHERE file_id = ? AND name = ?;"; + + if (!file_db && get_dbs()) { + pseudo_diag("%s: database error.\n", __func__); + return 0; + } + if (!select) { + rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &select, NULL); + if (rc) { + dberr(file_db, "couldn't prepare SELECT statement"); + return 1; + } + } + pseudo_debug(PDBGF_XATTR, "requested xattr named '%s' for file %lld\n", *value, file_id); + sqlite3_bind_int(select, 1, file_id); + rc = sqlite3_bind_text(select, 2, *value, -1, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr name to SELECT."); + return 1; + } + rc = sqlite3_step(select); + switch (rc) { + case SQLITE_ROW: + response = (char *) sqlite3_column_text(select, 0); + length = sqlite3_column_bytes(select, 0); + pseudo_debug(PDBGF_XATTR, "got %d-byte results: '%s'\n", + (int) length, response); + if (response && length >= 1) { + /* not a strdup because the values can contain + * arbitrary bytes. + */ + *value = malloc(length); + memcpy(*value, response, length); + *len = length; + rc = 0; + } else { + *value = NULL; + *len = 0; + rc = 1; + } + break; + case SQLITE_DONE: + pseudo_debug(PDBGF_DB, "find_exact: sqlite_done on first row\n"); + rc = 1; + break; + default: + dberr(file_db, "find_exact: select returned neither a row nor done"); + rc = 1; + break; + } + sqlite3_reset(select); + sqlite3_clear_bindings(select); + return rc; +} + +int +pdb_list_xattr(long long file_id, char **value, size_t *len) { + static sqlite3_stmt *select; + size_t allocated = 0; + size_t used = 0; + char *buffer = 0; + int rc; + char *sql = "SELECT name FROM xattrs WHERE file_id = ?;"; + + /* if we don't have a record of the file, it must not have + * any extended attributes... + */ + if (file_id == -1) { + *value = NULL; + *len = 0; + return 0; + } + + if (!file_db && get_dbs()) { + pseudo_diag("%s: database error.\n", __func__); + return 0; + } + if (!select) { + rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &select, NULL); + if (rc) { + dberr(file_db, "couldn't prepare SELECT statement"); + return 1; + } + } + sqlite3_bind_int(select, 1, file_id); + do { + rc = sqlite3_step(select); + if (rc == SQLITE_ROW) { + char *value = (char *) sqlite3_column_text(select, 0); + size_t len = sqlite3_column_bytes(select, 0); + if (!buffer) { + allocated = round_up(len, 256); + buffer = malloc(allocated); + } + if (used + len + 2 > allocated) { + size_t new_allocated = round_up(used + len + 2, 256); + char *new_buffer = malloc(new_allocated); + memcpy(new_buffer, buffer, used); + free(buffer); + allocated = new_allocated; + buffer = new_buffer; + } + memcpy(buffer + used, value, len); + buffer[used + len] = '\0'; + used = used + len + 1; + } else if (rc == SQLITE_DONE) { + *value = buffer; + *len = used; + } else { + dberr(file_db, "non-row response from select?"); + free(buffer); + *value = NULL; + *len = 0; + } + } while (rc == SQLITE_ROW); + sqlite3_reset(select); + sqlite3_clear_bindings(select); + return rc != SQLITE_DONE; +} + +int +pdb_remove_xattr(long long file_id, char *value, size_t len) { + static sqlite3_stmt *delete; + int rc; + char *sql = "DELETE FROM xattrs WHERE file_id = ? AND name = ?;"; + + if (!file_db && get_dbs()) { + pseudo_diag("%s: database error.\n", __func__); + return 0; + } + if (!delete) { + rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &delete, NULL); + if (rc) { + dberr(file_db, "couldn't prepare DELETE statement"); + return 1; + } + } + sqlite3_bind_int(delete, 1, file_id); + rc = sqlite3_bind_text(delete, 2, value, len, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr name to DELETE."); + return 1; + } + file_db_dirty = 1; + rc = sqlite3_step(delete); + if (rc != SQLITE_DONE) { + dberr(file_db, "delete xattr may have failed"); + } + sqlite3_reset(delete); + sqlite3_clear_bindings(delete); + return rc != SQLITE_DONE; +} + +int +pdb_set_xattr(long long file_id, char *value, size_t len, int flags) { + static sqlite3_stmt *select, *update, *insert; + int rc; + long long existing_row = -1; + char *select_sql = "SELECT id FROM xattrs WHERE file_id = ? AND name = ?;"; + char *insert_sql = "INSERT INTO xattrs " + " ( file_id, name, value ) " + " VALUES (?, ?, ?);"; + char *update_sql = "UPDATE xattrs SET value = ? WHERE id = ?;"; + char *vname = value; + size_t vlen; + + if (!file_db && get_dbs()) { + pseudo_diag("%s: database error.\n", __func__); + return 0; + } + if (!select) { + rc = sqlite3_prepare_v2(file_db, select_sql, strlen(select_sql), &select, NULL); + if (rc) { + dberr(file_db, "couldn't prepare SELECT statement"); + return 1; + } + } + sqlite3_bind_int(select, 1, file_id); + rc = sqlite3_bind_text(select, 2, value, -1, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr name to SELECT."); + return 1; + } + rc = sqlite3_step(select); + switch (rc) { + case SQLITE_ROW: + existing_row = sqlite3_column_int64(select, 0); + break; + case SQLITE_DONE: + pseudo_debug(PDBGF_DB | PDBGF_VERBOSE, "find_exact: sqlite_done on first row\n"); + existing_row = -1; + break; + default: + dberr(file_db, "set_xattr: select returned neither a row nor done"); + rc = 1; + break; + } + sqlite3_reset(select); + sqlite3_clear_bindings(select); + if (flags == XATTR_CREATE && existing_row != -1) { + pseudo_debug(PDBGF_DB, "XATTR_CREATE with an existing row, failing."); + return 1; + } + if (flags == XATTR_REPLACE && existing_row == -1) { + pseudo_debug(PDBGF_DB, "XATTR_REPLACE with no existing row, failing."); + return 1; + } + /* the material after the name is the value */ + vlen = strlen(value); + len = len - (vlen + 1); + value = value + len; + pseudo_debug(PDBGF_XATTR, "trying to set a value for %lld: name is '%s', value is '%s'. Existing row %lld.\n", + file_id, vname, value, existing_row); + if (existing_row != -1) { + /* update */ + if (!update) { + rc = sqlite3_prepare_v2(file_db, update_sql, strlen(update_sql), &update, NULL); + if (rc) { + dberr(file_db, "couldn't prepare UPDATE statement"); + return 1; + } + } + rc = sqlite3_bind_text(update, 1, value, -1, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr value to UPDATE."); + return 1; + } + sqlite3_bind_int(update, 2, existing_row); + file_db_dirty = 1; + rc = sqlite3_step(update); + if (rc != SQLITE_DONE) { + dberr(file_db, "update xattr may have failed"); + } + sqlite3_reset(update); + sqlite3_clear_bindings(update); + return rc != SQLITE_DONE; + } else { + /* insert */ + if (!insert) { + rc = sqlite3_prepare_v2(file_db, insert_sql, strlen(insert_sql), &insert, NULL); + if (rc) { + dberr(file_db, "couldn't prepare INSERT statement"); + return 1; + } + } + pseudo_debug(PDBGF_XATTR, "insert should be getting ID %lld\n", file_id); + sqlite3_bind_int64(insert, 1, file_id); + rc = sqlite3_bind_text(insert, 2, vname, -1, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr name to INSERT statement"); + return 1; + } + rc = sqlite3_bind_text(insert, 3, value, vlen, SQLITE_STATIC); + if (rc) { + dberr(file_db, "couldn't bind xattr value to INSERT statement"); + return 1; + } + file_db_dirty = 1; + rc = sqlite3_step(insert); + if (rc != SQLITE_DONE) { + dberr(file_db, "insert xattr may have failed"); + } + sqlite3_reset(insert); + sqlite3_clear_bindings(insert); + return rc != SQLITE_DONE; + } + return rc; +} + /* find file using only inode as key. Unused for now, planned to come * in for NFS usage. */ int -pdb_find_file_ino(pseudo_msg_t *msg) { +pdb_find_file_ino(pseudo_msg_t *msg, long long *row) { static sqlite3_stmt *select; int rc; char *sql = "SELECT * FROM files WHERE ino = ?;"; @@ -2162,6 +2462,9 @@ pdb_find_file_ino(pseudo_msg_t *msg) { rc = sqlite3_step(select); switch (rc) { case SQLITE_ROW: + if (row) { + *row = sqlite3_column_int64(select, 0); + } msg->dev = (unsigned long) sqlite3_column_int64(select, 2); msg->uid = (unsigned long) sqlite3_column_int64(select, 4); msg->gid = (unsigned long) sqlite3_column_int64(select, 5); diff --git a/pseudo_db.h b/pseudo_db.h index 9e0382a..a8d9676 100644 --- a/pseudo_db.h +++ b/pseudo_db.h @@ -41,7 +41,7 @@ extern int pdb_maybe_backup(void); extern int pdb_cancel_unlink_file(pseudo_msg_t *msg); extern int pdb_did_unlink_file(char *path, int deleting); extern int pdb_did_unlink_files(int deleting); -extern int pdb_link_file(pseudo_msg_t *msg); +extern int pdb_link_file(pseudo_msg_t *msg, long long *row); extern int pdb_may_unlink_file(pseudo_msg_t *msg, int deleting); extern int pdb_unlink_file(pseudo_msg_t *msg); extern int pdb_unlink_file_dev(pseudo_msg_t *msg); @@ -51,11 +51,15 @@ extern int pdb_update_inode(pseudo_msg_t *msg); extern int pdb_unlink_contents(pseudo_msg_t *msg); extern int pdb_rename_file(const char *oldpath, pseudo_msg_t *msg); extern int pdb_renumber_all(dev_t from, dev_t to); -extern int pdb_find_file_exact(pseudo_msg_t *msg); -extern int pdb_find_file_path(pseudo_msg_t *msg); -extern int pdb_find_file_dev(pseudo_msg_t *msg); -extern int pdb_find_file_ino(pseudo_msg_t *msg); +extern int pdb_find_file_exact(pseudo_msg_t *msg, long long *row); +extern int pdb_find_file_path(pseudo_msg_t *msg, long long *row); +extern int pdb_find_file_dev(pseudo_msg_t *msg, long long *row); +extern int pdb_find_file_ino(pseudo_msg_t *msg, long long *row); extern char *pdb_get_file_path(pseudo_msg_t *msg); +extern int pdb_get_xattr(long long file_id, char **value, size_t *len); +extern int pdb_list_xattr(long long file_id, char **value, size_t *len); +extern int pdb_remove_xattr(long long file_id, char *value, size_t len); +extern int pdb_set_xattr(long long file_id, char *value, size_t len, int flags); struct log_history; typedef struct log_history *log_history; diff --git a/pseudo_server.c b/pseudo_server.c index 822df2b..a7600af 100644 --- a/pseudo_server.c +++ b/pseudo_server.c @@ -1,5 +1,6 @@ /* * pseudo_server.c, pseudo's server-side logic and message handling + * * Copyright (c) 2008-2010, 2013 Wind River Systems, Inc. * @@ -268,6 +269,7 @@ serve_client(int i) { in = pseudo_msg_receive(clients[i].fd); if (in) { char *response_path = 0; + size_t response_pathlen; int send_response = 1; pseudo_debug(PDBGF_SERVER | PDBGF_VERBOSE, "got a message (%d): %s\n", in->type, (in->pathlen ? in->path : "<no path>")); /* handle incoming ping */ @@ -306,16 +308,22 @@ serve_client(int i) { if (in->type != PSEUDO_MSG_SHUTDOWN) { if (in->type == PSEUDO_MSG_FASTOP) send_response = 0; - if (pseudo_server_response(in, clients[i].program, clients[i].tag)) { + /* most messages don't need these, but xattr may */ + response_path = 0; + response_pathlen = -1; + if (pseudo_server_response(in, clients[i].program, clients[i].tag, &response_path, &response_pathlen)) { in->type = PSEUDO_MSG_NAK; } else { in->type = PSEUDO_MSG_ACK; pseudo_debug(PDBGF_SERVER | PDBGF_VERBOSE, "response: %d (%s)\n", in->result, pseudo_res_name(in->result)); } - /* no path in response */ - in->pathlen = 0; in->client = i; + if (response_path) { + in->pathlen = response_pathlen; + } else { + in->pathlen = 0; + } } else { /* the server's listen fd is "a client", and * so is the program connecting to request a shutdown. @@ -347,7 +355,7 @@ serve_client(int i) { } } if (send_response) { - if ((rc = pseudo_msg_send(clients[i].fd, in, -1, response_path)) != 0) { + if ((rc = pseudo_msg_send(clients[i].fd, in, in->pathlen, response_path)) != 0) { pseudo_debug(PDBGF_SERVER, "failed to send response to client %d [%d]: %d (%s)\n", i, (int) clients[i].pid, rc, strerror(errno)); } diff --git a/pseudo_server.h b/pseudo_server.h index 5c595ea..06598e7 100644 --- a/pseudo_server.h +++ b/pseudo_server.h @@ -18,6 +18,6 @@ * */ extern int pseudo_server_start(int); -extern int pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag); +extern int pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len); extern int pseudo_server_timeout; extern int opt_l; diff --git a/pseudo_util.c b/pseudo_util.c index 277b058..a4a14b4 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -421,14 +421,6 @@ pseudo_diag(char *fmt, ...) { return wrote; } -/* given n, pick a multiple of block enough bigger than n - * to give us some breathing room. - */ -static inline size_t -round_up(size_t n, size_t block) { - return block * (((n + block / 4) / block) + 1); -} - /* store pid in text form for prepending to messages */ void pseudo_new_pid() { diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c index a594d2e..4a40fed 100644 --- a/pseudo_wrappers.c +++ b/pseudo_wrappers.c @@ -48,6 +48,9 @@ #include "pseudo_ipc.h" #include "pseudo_client.h" +/* Types and declarations we need in advance. */ +#include "pseudo_wrapper_table.c" + static void pseudo_enosys(const char *); static int pseudo_check_wrappers(void); static volatile int antimagic = 0; @@ -62,10 +65,6 @@ static void pseudo_sigblock(sigset_t *); extern char *program_invocation_short_name; static sigset_t pseudo_saved_sigmask; -/* the generated code goes here */ -#include "pseudo_wrapper_table.c" -#include "pseudo_wrapfuncs.c" - /* Constructor only exists in libpseudo */ static void _libpseudo_init(void) __attribute__ ((constructor)); @@ -252,4 +251,7 @@ pseudo_check_wrappers(void) { return _libpseudo_initted; } +/* the generated code goes here */ #include "port_wrappers.c" +#include "pseudo_wrapfuncs.c" + @@ -38,7 +38,7 @@ main(int argc, char **argv) { exit(1); } msg = pseudo_msg_new(0, argv[1]); - rc = pdb_find_file_path(msg); + rc = pdb_find_file_path(msg, NULL); if (rc) { printf("error.\n"); return 1; |