Date: Tue, 12 Feb 2013 22:35:14 +0000 (UTC) From: Dag-Erling Smørgrav <des@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r246722 - user/des/ndr Message-ID: <201302122235.r1CMZEXq010878@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: des Date: Tue Feb 12 22:35:14 2013 New Revision: 246722 URL: http://svnweb.freebsd.org/changeset/base/246722 Log: Old code from projcvs I'd completely forgotten about. Added: user/des/ndr/Makefile (contents, props changed) user/des/ndr/ndr.1 (contents, props changed) user/des/ndr/ndr.h (contents, props changed) user/des/ndr/ndr_client.c (contents, props changed) user/des/ndr/ndr_main.c (contents, props changed) user/des/ndr/ndr_protocol.c (contents, props changed) user/des/ndr/ndr_server.c (contents, props changed) Directory Properties: user/des/ndr/ (props changed) Added: user/des/ndr/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/Makefile Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,12 @@ +# $FreeBSD$ + +PROG = ndr +SRCS = ndr_main.c ndr_protocol.c ndr_client.c ndr_server.c +CSTD = c99 +WARNS ?= 6 +WFORMAT ?= 1 + +DPADD = ${LIBMD} +LDADD = -lmd + +.include <bsd.prog.mk> Added: user/des/ndr/ndr.1 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr.1 Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,134 @@ +.\"- +.\" Copyright (c) 2007 Dag-Erling Smørgrav +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 20, 2007 +.Dt NDR 1 +.Os +.Sh NAME +.Nm ndr +.Nd network-assisted disk recovery +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Fl a Ar addr +.Op Fl d Ar dir +.Op Fl p Ar port +.Fl s +.Nm +.Op Fl v +.Op Fl a Ar addr +.Op Fl p Ar port +.Fl c +.Ar device +.Ar host +.Op Ar port +.Sh DESCRIPTION +The +.Nm +utility attempts to recover the contents of a damaged disk over the +network. +One instance of +.Nm +runs in client mode on the machine to which the damaged disk is +attached. +Another instance runs in server mode on a separate machine. +.Pp +When the client contacts the server and announces the device which is +to be recovered, the server creates a file of the appropriate size and +starts requesting blocks of data from the client. +As recovery progresses, the server keeps track of recovered and failed +blocks in a separate file. +Thus, both the server and the client can be interrupted and restarted +without losing progress. +This is particularly useful when a disk is so badly damaged that the +client machine crashes during recovery. +.Pp +The following options are available: +.Bl -tag -width Fl +.It Fl a Ar addr +Bind to the specified address. +.It Fl c +Work in client mode. +The name of the device to recover, the name or address of the server, +and (optionally) the server's port number must be specified on the +command line after all other options. +.It Fl d Ar dir +In server mode, work from the specified directory. +For each client that connects to the server, a subdirectory named +after the IP address of the client is created within the working +directory. +The data and map files for each device are stored in directories named +after the device within each client directory. +.It Fl p Ar port +Bind to the specified port. +.It Fl s +Work in server mode. +.It Fl v +Increase the verbosity level. +Specifying this option more than once may result in overwhelming +amounts of debugging output. +.El +.Sh EXAMPLES +Start a server which will listen on port 6543 at the address +corresponding to +.Pa ndr.example.com , +store the data it receives in +.Pa /var/ndr , +and show a moderate amount of debugging information: +.Bd -literal -offset indent +ndr -s -a ndr.example.com -p 6543 -d /var/ndr -v +.Ed +.Pp +Start a client which will transfer the contents of +.Pa /dev/ad4 +to the server running on port 6543 on +.Pa ndr.example.com : +.Bd -literal -offset indent +ndr -c /dev/ad4 ndr.example.com 6543 +.Ed +.Pp +The following +.Xr hexdump 1 +command line displays the contents of a map file: +.Bd -literal -offset indent +hexdump -v -e '"%07.7_ax " 64/1 "%_c" "\\n"' map +.Ed +.Pp +Each output line starts with a hexadecimal offset followed by 64 ASCII +characters, each representing one block of the device. +Successfully recovered blocks are marked with a hash sign. +Blocks which have failed but will be retried are marked with a digit +reflecting the number of attempts that have been made. +Blocks which +.Nm +has given up on are marked with an asterisk. +.Sh AUTHORS +.An -nosplit +The +.Nm +utility and this manual page were written by +.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . Added: user/des/ndr/ndr.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr.h Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2007 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef NDR_H_INCLUDED +#define NDR_H_INCLUDED + +void verbose(int level, const char *fmt, ...); +void status(const char *fmt, ...); + +void client(const char *device, const char *saddr, const char *sport, + const char *daddr, const char *dport); +void server(const char *laddr, const char *lport); + +int client_socket(const char *saddr, const char *sport, + const char *daddr, const char *dport); +int server_socket(const char *laddr, const char *lport); +int accept_socket(int sd, char **saddr, char **sport); + +void sendstr(int sd, const char *str, size_t len); +void sendstrf(int sd, const char *fmt, ...); +void senddata(int sd, const void *buf, size_t len); +void read_full(int sd, void *buf, size_t len); +char *recvstr(int sd, char **str, size_t *len); +void *recvdata(int sd, void **buf, size_t *len, size_t *datalen); + +#endif Added: user/des/ndr/ndr_client.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr_client.c Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2007 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/disk.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <err.h> +#include <fcntl.h> +#include <md5.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ndr.h" + +void +client(const char *device, const char *saddr, const char *sport, + const char *daddr, const char *dport) +{ + uintmax_t size, bsize; + struct stat st; + int dd, sd; + + /* open device */ + if ((dd = open(device, O_RDONLY)) < 0) + err(1, "%s", device); + if (fstat(dd, &st) == -1) + err(1, "fstat()"); + if (S_ISCHR(st.st_mode)) { + off_t ot; + unsigned int ui; + + if (ioctl(dd, DIOCGMEDIASIZE, &ot) == -1) + err(1, "ioctl(DIOCGMEDIASIZE)"); + size = ot; + if (ioctl(dd, DIOCGSECTORSIZE, &ui) == -1) + err(1, "ioctl(DIOCGSECTORSIZE)"); + bsize = ui; + } else if (S_ISREG(st.st_mode)) { + size = st.st_size; + bsize = st.st_blksize; + } else { + errx(1, "invalid device type"); + } + + /* connect to server */ + sd = client_socket(saddr, sport, daddr, dport); + + /* send device information */ + sendstrf(sd, "device %s", device); + sendstrf(sd, "size %016jx %08jx", size, bsize); + sendstrf(sd, "ready"); + + /* process server requests */ + void *buf = NULL; + size_t buflen = 0; + char *str = NULL; + size_t len = 0; + for (;;) { + uintmax_t rstart, rstop; + int verify; + + recvstr(sd, &str, &len); + if (strcmp(str, "done") == 0) { + break; + } else if (sscanf(str, "verify %jx %jx", &rstart, &rstop) == 2) { + verify = 1; + } else if (sscanf(str, "read %jx %jx", &rstart, &rstop) == 2) { + verify = 0; + } else { + errx(1, "protocol error"); + } + + if (rstop < rstart) + errx(1, "protocol error"); + + off_t off = rstart * bsize; + size_t rlen = (rstop - rstart + 1) * bsize; + if ((uintmax_t)(off + rlen) > size || + lseek(dd, off, SEEK_SET) != off) { + sendstrf(sd, "failed"); + continue; + } + if (buflen < rlen) + if ((buf = reallocf(buf, rlen)) == NULL) + err(1, "realloc()"); + status("%s blocks %ju - %ju from %s", + verify ? "verifying" : "reading", + rstart, rstop, device); + ssize_t ret = read(dd, buf, rlen); + if (ret < 0) { + warn("read()"); + sendstrf(sd, "failed"); + continue; + } + uintmax_t dlen = ret; + uintmax_t dstart = rstart; + uintmax_t dstop = rstop; + if (dlen < rlen) { + warnx("read(): short read"); + dstop = dstart + dlen / bsize - 1; + } + if (verify) { + char md5[33]; + MD5Data(buf, dlen, md5); + sendstrf(sd, "md5 %016jx %016jx", dstart, dstop); + sendstrf(sd, "%s", md5); + } else { + sendstrf(sd, "data %016jx %016jx", dstart, dstop); + senddata(sd, buf, (dstop - dstart + 1) * bsize); + } + } + status("done"); + status(""); + exit(0); +} Added: user/des/ndr/ndr_main.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr_main.c Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2007 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/disk.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/uio.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ndr.h" + +static const char *a_arg; +static int c_flag; +static const char *d_arg; +static const char *p_arg; +static int s_flag; +static int v_count; + +static void +usage(void) +{ + + fprintf(stderr, + "usage: ndr [-v] [-d dir] [-a addr] [-p port] -s\n" + " ndr [-v] -c <device> <server> [<port>]\n"); + exit(1); +} + +void +verbose(int level, const char *fmt, ...) +{ + va_list ap; + + if (v_count >= level) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +void +status(const char *fmt, ...) +{ + static struct timeval prev; + struct timeval now; + static int olen = 0; + va_list ap; + int len; + + if (!isatty(STDERR_FILENO) || v_count > 1) + return; + + if (fmt[0] == '\0') { + /* cleanup requested */ + fputc('\n', stderr); + return; + } + + gettimeofday(&now, NULL); + if (now.tv_sec == prev.tv_sec) + return; + + prev = now; + fputc('\r', stderr); + va_start(ap, fmt); + len = vfprintf(stderr, fmt, ap); + va_end(ap); + + for (int i = len; i < olen; ++i) + fputc(' ', stderr); + olen = len; +} + +int +main(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "a:cd:p:sv")) != -1) + switch (opt) { + case 'a': + a_arg = optarg; + break; + case 'c': + c_flag = 1; + break; + case 'd': + d_arg = optarg; + break; + case 'p': + p_arg = optarg; + break; + case 's': + s_flag = 1; + break; + case 'v': + v_count++; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (!(c_flag ^ s_flag)) + usage(); + + if (c_flag) { + if (d_arg || argc < 2 || argc > 3) + usage(); + client(argv[0], a_arg, p_arg, argv[1], argv[2]); + } else if (s_flag) { + if (argc > 0) + usage(); + if (d_arg && chdir(d_arg) != 0) + err(1, "chdir(%s)", d_arg); + server(a_arg, p_arg); + } else { + usage(); + } + errx(1, "not reached"); +} Added: user/des/ndr/ndr_protocol.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr_protocol.c Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,336 @@ +/*- + * Copyright (c) 2007 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/uio.h> + +#include <sys/socket.h> +#include <netinet/in.h> + +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ndr.h" + +static const char *ndr_default_port = "9110"; +static const char *ndr_client_sig = "ndr client\n"; +static const char *ndr_server_sig = "ndr server\n"; + +static int +handshake(int sd, const char *mine, const char *theirs) +{ + ssize_t mlen = strlen(mine); + ssize_t tlen = strlen(theirs); + char buf[tlen]; + + if (write(sd, mine, mlen) != mlen || + read(sd, buf, tlen) != tlen || + strncmp(buf, theirs, tlen) != 0) + return (-1); + return (0); +} + +int +client_socket(const char *saddr, const char *sport, + const char *daddr, const char *dport) +{ + struct addrinfo hints, *sres, *dres; + int one, ret, sd; + + /* resolve server address */ + memset(&hints, 0, sizeof hints); + hints.ai_flags = 0; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + dres = NULL; + if (dport == NULL) + dport = ndr_default_port; + if ((ret = getaddrinfo(daddr, dport, &hints, &dres)) != 0) + errx(1, "getaddrinfo(): %s", gai_strerror(ret)); + + /* open socket */ + if ((sd = socket(dres->ai_family, dres->ai_socktype, dres->ai_protocol)) < 0) + err(1, "socket()"); + + /* resolve source address if given */ + if (saddr != NULL || sport != NULL) { + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = dres->ai_family; + hints.ai_socktype = dres->ai_socktype; + hints.ai_protocol = dres->ai_protocol; + sres = NULL; + if ((ret = getaddrinfo(saddr, sport, &hints, &sres)) != 0) + errx(1, "getaddrinfo(): %s", gai_strerror(ret)); + one = 1; + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) != 0) + err(1, "setsockopt(SO_REUSEADDR)"); + if (bind(sd, sres->ai_addr, sres->ai_addrlen) != 0) + err(1, "connect()"); + freeaddrinfo(sres); + } + + /* connect to server */ + if (connect(sd, dres->ai_addr, dres->ai_addrlen) != 0) + err(1, "connect()"); + freeaddrinfo(dres); + + verbose(1, "connected to server %s:%s\n", daddr, dport); + + /* handshake */ + if (handshake(sd, ndr_client_sig, ndr_server_sig) != 0) + errx(1, "handshake failed"); + + return (sd); +} + +int +server_socket(const char *laddr, const char *lport) +{ + struct addrinfo hints, *lres; + int one, ret, sd; + + /* resolve listening address */ + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + lres = NULL; + if (lport == NULL) + lport = ndr_default_port; + if ((ret = getaddrinfo(laddr, lport, &hints, &lres)) != 0) + errx(1, "getaddrinfo(): %s", gai_strerror(ret)); + + /* open listening socket */ + if ((sd = socket(lres->ai_family, lres->ai_socktype, lres->ai_protocol)) < 0) + err(1, "socket()"); + one = 1; + if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof one) != 0) + err(1, "setsockopt(SO_REUSEPORT)"); + if (bind(sd, lres->ai_addr, lres->ai_addrlen) != 0) + err(1, "bind()"); + if (listen(sd, 16) != 0) + err(1, "listen()"); + freeaddrinfo(lres); + + verbose(1, "server listening on %s:%s\n", laddr ? laddr : "*", lport); + + return (sd); +} + +int +accept_socket(int sd, char **saddr, char **sport) +{ + struct sockaddr_storage addr; + socklen_t addrlen; + int ad, ret; + + memset(&addr, 0, addrlen = sizeof addr); + if ((ad = accept(sd, (struct sockaddr *)&addr, &addrlen)) < 0) + return (-1); + + if ((*saddr = malloc(NI_MAXHOST)) == NULL || + (*sport = malloc(NI_MAXSERV)) == NULL) + err(1, "malloc()"); + + /* resolve client address */ + if ((ret = getnameinfo((struct sockaddr *)&addr, addrlen, + *saddr, NI_MAXHOST, *sport, NI_MAXSERV, + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) + /* shouldn't happen */ + err(1, "getnameinfo(): %s", gai_strerror(ret)); + + verbose(1, "accepted connection from %s:%s\n", *saddr, *sport); + + if (handshake(ad, ndr_server_sig, ndr_client_sig) != 0) { + verbose(1, "handshake failed"); + close(ad); + return (-1); + } + + return (ad); +} + +void +sendstr(int sd, const char *str, size_t len) +{ + struct iovec iov[3]; + uint32_t count; + char s = 's'; + ssize_t res, ret; + + if (len == 0) + len = strlen(str); + count = len; + verbose(2, ">>> s %08x %s\n", count, str); + count = htonl(count); + res = 0; + iov[0].iov_base = &s; + res += (iov[0].iov_len = 1); + iov[1].iov_base = &count; + res += (iov[1].iov_len = sizeof count); + iov[2].iov_base = (void *)(uintptr_t)str; + res += (iov[2].iov_len = len); + if ((ret = writev(sd, iov, 3)) != res) { + if (ret == -1) + err(1, "writev()"); + errx(1, "writev(): short write (%zd / %zd)", ret, res); + } +} + +void +sendstrf(int sd, const char *fmt, ...) +{ + va_list ap; + char *str; + int len; + + str = NULL; + va_start(ap, fmt); + if ((len = vasprintf(&str, fmt, ap)) == -1) + err(1, "malloc()"); + va_end(ap); + + sendstr(sd, str, len); + free(str); +} + +void +senddata(int sd, const void *buf, size_t len) +{ + struct iovec iov[3]; + uint32_t count; + char d = 'd'; + ssize_t res, ret; + + if (len == 0) + len = strlen(buf); + count = len; + verbose(3, ">>> d %08x <binary data>\n", count); + count = htonl(count); + res = 0; + iov[0].iov_base = &d; + res += (iov[0].iov_len = 1); + iov[1].iov_base = &count; + res += (iov[1].iov_len = sizeof count); + iov[2].iov_base = (void *)(uintptr_t)buf; + res += (iov[2].iov_len = len); + if ((ret = writev(sd, iov, 3)) != res) { + if (ret == -1) + err(1, "writev()"); + errx(1, "writev(): short write (%zd / %zd)", ret, res); + } +} + +void +read_full(int sd, void *buf, size_t len) +{ + ssize_t res, ret; + int retry; + + for (retry = 0, res = len; res > 0; res -= ret) { + while ((ret = read(sd, buf, res)) < 0) + if (errno != EAGAIN && errno != EINTR) + err(1, "read()"); + if (ret == 0) { + if (++retry < 5) + continue; + errx(1, "read(): short read (%zd / %zu)", + len - res, len); + } + retry = 0; + buf = (char *)buf + ret; + } +} + +char * +recvstr(int sd, char **str, size_t *len) +{ + uint32_t count; + char s; + + /* read marker */ + read_full(sd, &s, sizeof s); + if (s != 's') + errx(1, "protocol error"); + + /* read count */ + read_full(sd, &count, sizeof count); + count = ntohl(count); + + /* make sure the buffer is sufficiently large */ + if (*len < count + 1) + if ((*str = reallocf(*str, count + 1)) == NULL) + err(1, "realloc()"); + + /* read string */ + read_full(sd, *str, count); + (*str)[count] = '\0'; + + /* check for early termination */ + for (unsigned int i = 0; i < count; ++i) + if ((*str)[i] == '\0') + err(1, "protocol error"); + + verbose(2, "<<< s %08x %s\n", count, *str); + return (*str); +} + +void * +recvdata(int sd, void **buf, size_t *len, size_t *datalen) +{ + uint32_t count; + char d; + + /* read marker */ + read_full(sd, &d, sizeof d); + if (d != 'd') + errx(1, "protocol error"); + + /* read count */ + read_full(sd, &count, sizeof count); + count = ntohl(count); + + /* make sure the buffer is sufficiently large */ + if (*len < count) + if ((*buf = reallocf(*buf, count)) == NULL) + err(1, "realloc()"); + + /* read data */ + read_full(sd, *buf, count); + + verbose(3, "<<< d %08x <binary data>\n", count); + *datalen = count; + return (*buf); +} Added: user/des/ndr/ndr_server.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/des/ndr/ndr_server.c Tue Feb 12 22:35:14 2013 (r246722) @@ -0,0 +1,436 @@ +/*- + * Copyright (c) 2007 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <errno.h> +#include <md5.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ndr.h" + +struct client { + pid_t pid; /* handler's PID */ + + int sd; /* socket descriptor */ + char *host; /* host name */ + char *port; /* port number */ + char *device; /* device name */ + + char *wpath; /* working directory */ + char *dpath; /* data file */ + int dd; /* data file descriptor */ + char *mpath; /* map file */ + int md; /* map file descriptor */ + char *map; /* map file pointer */ + + uintmax_t size; /* device size */ + uintmax_t bsize; /* device block size */ + uintmax_t blocks; /* # blocks total (size / bsize) */ + uintmax_t failed; /* # blocks failed */ + uintmax_t received; /* # blocks successfully recovered */ + uintmax_t retry; /* # blocks needing retry */ + + void *buf; /* buffer for receiving data */ + size_t bufsz; /* current size of buffer */ + size_t buflen; /* current length of buffer contents */ + + char *str; /* buffer for receiving strings */ + size_t strsz; /* current size of string buffer */ +}; + +static volatile sig_atomic_t interrupted; + +static void +interrupt(int sig) +{ + + (void)sig; + interrupted = 1; +} + +static void +reaper(int sig) +{ + int ret; + + (void)sig; + if (waitpid(0, &ret, WNOHANG) > 0 && WIFSIGNALED(ret)) + raise(WTERMSIG(ret)); +} + +static void +init_paths(struct client *cp) +{ + char path[PATH_MAX], rpath[PATH_MAX]; + char *p, *q, t; + + /* XXX overflow */ + snprintf(path, sizeof path, "%s/%s", cp->host, cp->device); + + /* create directory if necessary */ + for (p = q = path; *p != '\0'; p = q) { + if ((q = strchr(p, '/')) == NULL) + q = strchr(p, '\0'); + if ((t = *q) != '\0') + *q = '\0'; + if (mkdir(path, 0755) != 0 && errno != EEXIST) + err(1, "mkdir(%s)", path); + if (t == '\0') + break; + *q++ = t; + } + + /* resolve paths */ + realpath(path, rpath); + if ((cp->wpath = strdup(rpath)) == NULL) + err(1, "strdup()"); + if ((asprintf(&cp->dpath, "%s/data", cp->wpath)) < 0 || + (asprintf(&cp->mpath, "%s/map", cp->wpath)) < 0) + err(1, "asprintf()"); +} + +static void +init_files(struct client *cp) +{ + struct stat st; + int new = 0; + + /* initialize data and map */ + if ((cp->dd = open(cp->dpath, O_RDWR|O_CREAT, 0600)) < 0) + err(1, "%s", cp->dpath); + if (fstat(cp->dd, &st) != 0) + err(1, "fstat(%s)", cp->dpath); + if (st.st_size != (off_t)cp->size) + new = 1; + if ((cp->md = open(cp->mpath, O_RDWR|O_CREAT, 0600)) < 0) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302122235.r1CMZEXq010878>