the existing procfs stuff is not always usable. stop skipping some relevant tests even if procfs is not available.
Signed-off-by: YAMAMOTO Takashi <yamam...@valinux.co.jp> --- lib/socket-util.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-- python/ovs/socket_util.py | 46 +++++++++++++++++++++++++++- tests/library.at | 2 -- 3 files changed, 118 insertions(+), 6 deletions(-) diff --git a/lib/socket-util.c b/lib/socket-util.c index 7f34ea2..0d5fd89 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -337,6 +337,62 @@ drain_fd(int fd, size_t n_packets) } } +/* A helper for make_sockaddr_un. returns malloc'ed string or NULL. */ +static const char * +make_short_name(const char *long_name) +{ + const char *tmpdir; + char *long_absname; + char *long_dirname; + unsigned int i; + + long_absname = abs_file_name(NULL, long_name); + long_dirname = dir_name(long_absname); + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) { + tmpdir = "/tmp"; + } + for (i = 0; i < 1000; i++) { + char link_name[PATH_MAX]; + + snprintf(link_name, sizeof(link_name), + "%s/ovs-un-c-%" PRIu32 "-%u", tmpdir, random_uint32(), i); + if (symlink(long_dirname, link_name) == 0) { + char short_name[PATH_MAX]; + char *long_basename; + + fatal_signal_add_file_to_unlink(link_name); + long_basename = base_name(long_absname); + snprintf(short_name, sizeof(short_name), + "%s/%s", link_name, long_basename); + free(long_absname); + free(long_dirname); + free(long_basename); + return xstrdup(short_name); + } + if (errno != EEXIST) { + break; + } + } + free(long_absname); + free(long_dirname); + return NULL; +} + +/* Clean up the name created by make_short_name */ +static void +unlink_short_name(const char *short_name) +{ + char *link_name; + + if (short_name == NULL) { + return; + } + link_name = dir_name(short_name); + fatal_signal_unlink_file_now(link_name); + free(CONST_CAST(void *, short_name)); +} + /* Stores in '*un' a sockaddr_un that refers to file 'name'. Stores in * '*un_len' the size of the sockaddr_un. */ static void @@ -357,11 +413,12 @@ make_sockaddr_un__(const char *name, struct sockaddr_un *un, socklen_t *un_len) * -1. */ static int make_sockaddr_un(const char *name, struct sockaddr_un *un, socklen_t *un_len, - int *dirfdp) + int *dirfdp, const char **short_namep) { enum { MAX_UN_LEN = sizeof un->sun_path - 1 }; *dirfdp = -1; + *short_namep = NULL; if (strlen(name) > MAX_UN_LEN) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); @@ -400,6 +457,14 @@ make_sockaddr_un(const char *name, struct sockaddr_un *un, socklen_t *un_len, VLOG_WARN_RL(&rl, "Unix socket name %s is longer than maximum " "%d bytes (even shortened)", name, MAX_UN_LEN); } else { + const char *short_name = make_short_name(name); + + if (short_name != NULL && strlen(short_name) <= MAX_UN_LEN) { + make_sockaddr_un__(short_name, un, un_len); + *short_namep = short_name; + return 0; + } + unlink_short_name(short_name); /* 'name' is too long and we have no workaround. */ VLOG_WARN_RL(&rl, "Unix socket name %s is longer than maximum " "%d bytes", name, MAX_UN_LEN); @@ -456,6 +521,7 @@ make_unix_socket(int style, bool nonblock, struct sockaddr_un un; socklen_t un_len; int dirfd; + const char *short_name; if (unlink(bind_path) && errno != ENOENT) { VLOG_WARN("unlinking \"%s\": %s\n", @@ -463,13 +529,14 @@ make_unix_socket(int style, bool nonblock, } fatal_signal_add_file_to_unlink(bind_path); - error = make_sockaddr_un(bind_path, &un, &un_len, &dirfd); + error = make_sockaddr_un(bind_path, &un, &un_len, &dirfd, &short_name); if (!error) { error = bind_unix_socket(fd, (struct sockaddr *) &un, un_len); } if (dirfd >= 0) { close(dirfd); } + unlink_short_name(short_name); if (error) { goto error; } @@ -479,8 +546,10 @@ make_unix_socket(int style, bool nonblock, struct sockaddr_un un; socklen_t un_len; int dirfd; + const char *short_name; - error = make_sockaddr_un(connect_path, &un, &un_len, &dirfd); + error = make_sockaddr_un(connect_path, &un, &un_len, &dirfd, + &short_name); if (!error && connect(fd, (struct sockaddr*) &un, un_len) && errno != EINPROGRESS) { @@ -489,6 +558,7 @@ make_unix_socket(int style, bool nonblock, if (dirfd >= 0) { close(dirfd); } + unlink_short_name(short_name); if (error) { goto error; } diff --git a/python/ovs/socket_util.py b/python/ovs/socket_util.py index 7dac5bb..c657047 100644 --- a/python/ovs/socket_util.py +++ b/python/ovs/socket_util.py @@ -14,6 +14,8 @@ import errno import os +import os.path +import random import select import socket import sys @@ -25,7 +27,33 @@ import ovs.vlog vlog = ovs.vlog.Vlog("socket_util") -def make_unix_socket(style, nonblock, bind_path, connect_path): +def make_short_name(long_name): + if long_name is None: + return None + long_name = os.path.abspath(long_name) + long_dirname = os.path.dirname(long_name) + tmpdir = os.getenv('TMPDIR', '/tmp') + for x in xrange(0, 1000): + link_name = \ + '%s/ovs-un-py-%d-%d' % (tmpdir, random.randint(0, 10000), x) + try: + os.symlink(long_dirname, link_name) + ovs.fatal_signal.add_file_to_unlink(link_name) + return os.path.join(link_name, os.path.basename(long_name)) + except OSError, e: + if e.errno != errno.EEXIST: + break + raise Exception("Failed to create temporary symlink") + + +def free_short_name(short_name): + if short_name is None: + return + link_name = os.path.dirname(short_name) + ovs.fatal_signal.unlink_file_now(link_name) + + +def make_unix_socket(style, nonblock, bind_path, connect_path, short=False): """Creates a Unix domain socket in the given 'style' (either socket.SOCK_DGRAM or socket.SOCK_STREAM) that is bound to 'bind_path' (if 'bind_path' is not None) and connected to 'connect_path' (if 'connect_path' @@ -106,6 +134,22 @@ def make_unix_socket(style, nonblock, bind_path, connect_path): os.close(connect_dirfd) if bind_dirfd is not None: os.close(bind_dirfd) + elif (eno == "AF_UNIX path too long"): + if short: + return get_exception_errno(e), None + short_bind_path = None + try: + short_bind_path = make_short_name(bind_path) + short_connect_path = make_short_name(connect_path) + except: + free_short_name(short_bind_path) + return errno.ENAMETOOLONG, None + try: + return make_unix_socket(style, nonblock, short_bind_path, + short_connect_path, short=True) + finally: + free_short_name(short_bind_path) + free_short_name(short_connect_path) else: return get_exception_errno(e), None diff --git a/tests/library.at b/tests/library.at index a978c13..6d1c6da 100644 --- a/tests/library.at +++ b/tests/library.at @@ -135,7 +135,6 @@ dnl is about 100 bytes. On Linux, we work around this by indirecting through dnl a directory fd using /proc/self/fd/<dirfd>. We do not have a workaround dnl for other platforms, so we skip the test there. AT_SETUP([test unix socket, long pathname - C]) -AT_SKIP_IF([test ! -d /proc/self/fd]) dnl Linux has a 108 byte limit; this is 150 bytes long. longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 mkdir $longname @@ -155,7 +154,6 @@ dnl a directory fd using /proc/self/fd/<dirfd>. We do not have a workaround dnl for other platforms, so we skip the test there. AT_SETUP([test unix socket, long pathname - Python]) AT_SKIP_IF([test $HAVE_PYTHON = no]) -AT_SKIP_IF([test ! -d /proc/self/fd]) dnl Linux has a 108 byte limit; this is 150 bytes long. longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 mkdir $longname -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev