diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2019-02-01 00:00:08 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2019-02-01 12:50:29 -0500 |
commit | 30012351f6cadc25bf800c86f1431eade4ee0af5 (patch) | |
tree | 03529f68d39d3b2eb9971acd3e73b65c89178e01 /tests/mksock.c | |
parent | 6a5c4c1161291a55b35151562a2d86c0a7a06606 (diff) | |
download | bfs-30012351f6cadc25bf800c86f1431eade4ee0af5.tar.xz |
tests: New utility for making and testing socket files
Diffstat (limited to 'tests/mksock.c')
-rw-r--r-- | tests/mksock.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/tests/mksock.c b/tests/mksock.c new file mode 100644 index 0000000..a996d58 --- /dev/null +++ b/tests/mksock.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * bfs * + * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> * + * * + * Permission to use, copy, modify, and/or distribute this software for any * + * purpose with or without fee is hereby granted. * + * * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * + ****************************************************************************/ + +/** + * There's no standard Unix utility that creates a socket file, so this small + * program does the job. + */ + +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/un.h> +#include <unistd.h> + +/** + * Print an error message. + */ +static void errmsg(const char *cmd, const char *path) { + fprintf(stderr, "%s: '%s': %s.\n", cmd, path, strerror(errno)); +} + +/** + * struct sockaddr_un::sun_path is very short, so we chdir() into the target + * directory before creating sockets in case the full path is too long but the + * file name is not. + */ +static int chdir_parent(const char *path) { + char *copy = strdup(path); + if (!copy) { + return -1; + } + const char *dir = dirname(copy); + + int ret = chdir(dir); + + int error = errno; + free(copy); + errno = error; + + return ret; +} + +/** + * Initialize a struct sockaddr_un with the right filename. + */ +static int init_sun(struct sockaddr_un *sock, const char *path) { + size_t len = strlen(path); + if (len == 0 || path[len - 1] == '/') { + errno = ENOENT; + return -1; + } + + char *copy = strdup(path); + if (!copy) { + return -1; + } + const char *base = basename(copy); + + len = strlen(base); + if (len >= sizeof(sock->sun_path)) { + free(copy); + errno = ENAMETOOLONG; + return -1; + } + + sock->sun_family = AF_UNIX; + memcpy(sock->sun_path, base, len + 1); + free(copy); + return 0; +} + +int main(int argc, char *argv[]) { + const char *cmd = argc > 0 ? argv[0] : "mksock"; + + if (argc != 2) { + fprintf(stderr, "Usage: %s NAME\n", cmd); + return EXIT_FAILURE; + } + + const char *path = argv[1]; + + if (chdir_parent(path) != 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + struct sockaddr_un sock; + if (init_sun(&sock, path) != 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + errmsg(cmd, path); + return EXIT_FAILURE; + } + + int ret = EXIT_SUCCESS; + + if (bind(fd, (struct sockaddr *)&sock, sizeof(sock)) != 0) { + errmsg(cmd, path); + ret = EXIT_FAILURE; + } + + if (close(fd) != 0) { + errmsg(cmd, path); + ret = EXIT_FAILURE; + } + + return ret; +} |