the existing procfs stuff is not always usable. stop skipping some relevant tests even if procfs is not available.
Signed-off-by: YAMAMOTO Takashi <[email protected]> --- lib/socket-util.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-- python/ovs/socket_util.py | 46 ++++++++++++++++++++++++++++- tests/library.at | 2 -- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/lib/socket-util.c b/lib/socket-util.c index 7f34ea2..2d4c3fd 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -423,6 +423,69 @@ bind_unix_socket(int fd, struct sockaddr *sun, socklen_t sun_len) return error; } +static const char * +make_short_name(const char *long_name) +{ + struct sockaddr_un *un; + enum { MAX_UN_LEN = sizeof un->sun_path - 1 }; + const char *tmpdir; + char *long_absname; + char *long_dirname; + unsigned int i; + + if (LINUX_DATAPATH) { + /* For Linux we have a different workaround (procfs) */ + return long_name; + } + if (strlen(long_name) <= MAX_UN_LEN) { + return long_name; + } + 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-%lu-%u", tmpdir, random(), 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 long_name; +} + +static void +unlink_short_name(const char *short_name, const char *long_name) +{ + char *link_name; + + if (short_name == long_name) { + return; + } + link_name = dir_name(short_name); + fatal_signal_unlink_file_now(link_name); + free(CONST_CAST(void *, short_name)); +} + /* Creates a Unix domain socket in the given 'style' (either SOCK_DGRAM or * SOCK_STREAM) that is bound to '*bind_path' (if 'bind_path' is non-null) and * connected to '*connect_path' (if 'connect_path' is non-null). If 'nonblock' @@ -456,6 +519,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 +527,15 @@ 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); + short_name = make_short_name(bind_path); + error = make_sockaddr_un(short_name, &un, &un_len, &dirfd); if (!error) { error = bind_unix_socket(fd, (struct sockaddr *) &un, un_len); } if (dirfd >= 0) { close(dirfd); } + unlink_short_name(short_name, bind_path); if (error) { goto error; } @@ -479,8 +545,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); + short_name = make_short_name(connect_path); + error = make_sockaddr_un(short_name, &un, &un_len, &dirfd); if (!error && connect(fd, (struct sockaddr*) &un, un_len) && errno != EINPROGRESS) { @@ -489,6 +557,7 @@ make_unix_socket(int style, bool nonblock, if (dirfd >= 0) { close(dirfd); } + unlink_short_name(short_name, connect_path); 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 [email protected] http://openvswitch.org/mailman/listinfo/dev
