⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1999 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission.  U.M. makes no representations about the * suitability of this software for any purpose.  It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, 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. * * Authors: the Amanda Development Team.  Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $ */#include "amanda.h"#include "util.h"#include <regex.h>#include "arglist.h"#include "clock.h"#include "sockaddr-util.h"#include "conffile.h"#ifdef HAVE_LIBCURL#include <curl/curl.h>#endifstatic int make_socket(sa_family_t family);static int connect_port(struct sockaddr_storage *addrp, in_port_t port, char *proto,			struct sockaddr_storage *svaddr, int nonblock);/* * Keep calling read() until we've read buflen's worth of data, or EOF, * or we get an error. * * Returns the number of bytes read, 0 on EOF, or negative on error. */ssize_tfullread(    int		fd,    void *	vbuf,    size_t	buflen){    ssize_t nread, tot = 0;    char *buf = vbuf;	/* cast to char so we can ++ it */    while (buflen > 0) {	nread = read(fd, buf, buflen);	if (nread < 0) {	    if ((errno == EINTR) || (errno == EAGAIN))		continue;	    return ((tot > 0) ? tot : -1);	}	if (nread == 0)	    break;	tot += nread;	buf += nread;	buflen -= nread;    }    return (tot);}/* * Keep calling write() until we've written buflen's worth of data, * or we get an error. * * Returns the number of bytes written, or negative on error. */ssize_tfullwrite(    int		fd,    const void *vbuf,    size_t	buflen){    ssize_t nwritten, tot = 0;    const char *buf = vbuf;	/* cast to char so we can ++ it */    while (buflen > 0) {	nwritten = write(fd, buf, buflen);	if (nwritten < 0) {	    if ((errno == EINTR) || (errno == EAGAIN))		continue;	    return ((tot > 0) ? tot : -1);	}	tot += nwritten;	buf += nwritten;	buflen -= nwritten;    }    return (tot);}static intmake_socket(    sa_family_t family){    int s;    int save_errno;#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)    int on=1;    int r;#endif    s = socket(family, SOCK_STREAM, 0);    if (s == -1) {        save_errno = errno;        dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));        errno = save_errno;        return -1;    }    if (s < 0 || s >= (int)FD_SETSIZE) {        aclose(s);        errno = EMFILE;                         /* out of range */        return -1;    }#ifdef USE_REUSEADDR    r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));    if (r < 0) {	save_errno = errno;	dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),		  strerror(errno));	errno = save_errno;    }#endif#ifdef SO_KEEPALIVE    r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,		   (void *)&on, SIZEOF(on));    if (r == -1) {	save_errno = errno;	dbprintf(_("make_socket: setsockopt() failed: %s\n"),                  strerror(save_errno));	aclose(s);	errno = save_errno;	return -1;    }#endif    return s;}/* addrp is my address *//* svaddr is the address of the remote machine *//* return socket on success *//* return -1     on failure */intconnect_portrange(    struct sockaddr_storage *addrp,    in_port_t		first_port,    in_port_t		last_port,    char *		proto,    struct sockaddr_storage *svaddr,    int			nonblock){    int			s;    in_port_t		port;    static in_port_t	port_in_use[1024];    static int		nb_port_in_use = 0;    int			i;    int			save_errno = EAGAIN;    assert(first_port <= last_port);    /* Try a port already used */    for(i=0; i < nb_port_in_use; i++) {	port = port_in_use[i];	if(port >= first_port && port <= last_port) {	    s = connect_port(addrp, port, proto, svaddr, nonblock);	    if(s == -2) return -1;	    if(s > 0) {		return s;	    }	    if (errno != EAGAIN && errno != EBUSY)		save_errno = errno;	}    }    /* Try a port in the range */    for (port = first_port; port <= last_port; port++) {	s = connect_port(addrp, port, proto, svaddr, nonblock);	if(s == -2) return -1;	if(s > 0) {	    port_in_use[nb_port_in_use++] = port;	    return s;	}	if (errno != EAGAIN && errno != EBUSY)	    save_errno = errno;    }    dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),	      first_port,	      last_port);    errno = save_errno;    return -1;}/* addrp is my address *//* svaddr is the address of the remote machine *//* return -2: Don't try again *//* return -1: Try with another port *//* return >0: this is the connected socket */intconnect_port(    struct sockaddr_storage *addrp,    in_port_t  		port,    char *		proto,    struct sockaddr_storage *svaddr,    int			nonblock){    int			save_errno;    struct servent *	servPort;    socklen_t		len;    socklen_t		socklen;    int			s;    servPort = getservbyport((int)htons(port), proto);    if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {	dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),		  port, servPort->s_name);	errno = EBUSY;	return -1;    }    if ((s = make_socket(addrp->ss_family)) == -1) return -2;    SS_SET_PORT(addrp, port);    socklen = SS_LEN(addrp);    if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {	save_errno = errno;	aclose(s);	if(servPort == NULL) {	    dbprintf(_("connect_port: Try  port %d: available - %s\n"),		     port, strerror(errno));	} else {	    dbprintf(_("connect_port: Try  port %d: owned by %s - %s\n"),		     port, servPort->s_name, strerror(errno));	}	if (save_errno != EADDRINUSE) {	    errno = save_errno;	    return -2;	}	errno = save_errno;	return -1;    }    if(servPort == NULL) {	dbprintf(_("connect_port: Try  port %d: available - Success\n"), port);    } else {	dbprintf(_("connect_port: Try  port %d: owned by %s - Success\n"),		  port, servPort->s_name);    }    /* find out what port was actually used */    len = sizeof(*addrp);    if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {	save_errno = errno;	dbprintf(_("connect_port: getsockname() failed: %s\n"),		  strerror(save_errno));	aclose(s);	errno = save_errno;	return -1;    }    if (nonblock)	fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);    if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {	save_errno = errno;	dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),		  str_sockaddr(addrp),		  strerror(save_errno));	dbprintf(_("connect_portrange: connect to %s failed: %s\n"),		  str_sockaddr(svaddr),		  strerror(save_errno));	aclose(s);	errno = save_errno;	if (save_errno == ECONNREFUSED ||	    save_errno == EHOSTUNREACH ||	    save_errno == ENETUNREACH ||	    save_errno == ETIMEDOUT)  {	    return -2	;	}	return -1;    }    dbprintf(_("connected to %s\n"),              str_sockaddr(svaddr));    dbprintf(_("our side is %s\n"),              str_sockaddr(addrp));    return s;}/* * Bind to a port in the given range.  Takes a begin,end pair of port numbers. * * Returns negative on error (EGAIN if all ports are in use).  Returns 0 * on success. */intbind_portrange(    int			s,    struct sockaddr_storage *addrp,    in_port_t		first_port,    in_port_t		last_port,    char *		proto){    in_port_t port;    in_port_t cnt;    socklen_t socklen;    struct servent *servPort;    const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);    int save_errno = EAGAIN;    assert(first_port <= last_port);    /*     * We pick a different starting port based on our pid and the current     * time to avoid always picking the same reserved port twice.     */    port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);    /*     * Scan through the range, trying all available ports that are either      * not taken in /etc/services or registered for *amanda*.  Wrap around     * if we don't happen to start at the beginning.     */    for (cnt = 0; cnt < num_ports; cnt++) {	servPort = getservbyport((int)htons(port), proto);	if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {	    SS_SET_PORT(addrp, port);	    socklen = SS_LEN(addrp);	    if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {		if (servPort == NULL) {		    dbprintf(_("bind_portrange2: Try  port %d: Available - Success\n"), port);		} else {		    dbprintf(_("bind_portrange2: Try  port %d: Owned by %s - Success.\n"), port, servPort->s_name);		}		return 0;	    }	    if (errno != EAGAIN && errno != EBUSY)		save_errno = errno;	    if (servPort == NULL) {		dbprintf(_("bind_portrange2: Try  port %d: Available - %s\n"),			port, strerror(errno));	    } else {		dbprintf(_("bind_portrange2: Try  port %d: Owned by %s - %s\n"),			port, servPort->s_name, strerror(errno));	    }	} else {	        dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),		      port, servPort->s_name);	}	if (++port > last_port)	    port = first_port;    }    dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),		  first_port,		  last_port);    errno = save_errno;    return -1;}intneeds_quotes(    const char * str){    return (match("[ \t\f\r\n\"]", str) != 0);}/* * For backward compatibility we are trying for minimal quoting. * We only quote a string if it contains whitespace or is misquoted... */char *quote_string(    const char *str){    char *  s;    char *  ret;    if ((str == NULL) || (*str == '\0')) {	ret = stralloc("\"\"");    } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {	/*	 * String does not need to be quoted since it contains	 * neither whitespace, control or quote characters.	 */	ret = stralloc(str);    } else {	/*	 * Allocate maximum possible string length.	 * (a string of all quotes plus room for leading ", trailing " and NULL)	 */	ret = s = alloc((strlen(str) * 2) + 2 + 1);	*(s++) = '"';	while (*str != '\0') {            if (*str == '\t') {                *(s++) = '\\';                *(s++) = 't';		str++;		continue;	    } else if (*str == '\n') {                *(s++) = '\\';                *(s++) = 'n';		str++;		continue;	    } else if (*str == '\r') {                *(s++) = '\\';                *(s++) = 'r';		str++;		continue;	    } else if (*str == '\f') {                *(s++) = '\\';                *(s++) = 'f';		str++;		continue;	    } else if (*str == '\\') {                *(s++) = '\\';                *(s++) = '\\';		str++;		continue;	    }            if (*str == '"')                *(s++) = '\\';            *(s++) = *(str++);        }        *(s++) = '"';        *s = '\0';    }    return (ret);}char *unquote_string(    const char *str){    char * ret;    if ((str == NULL) || (*str == '\0')) {	ret = stralloc("");    } else {	char * in;	char * out;	ret = in = out = stralloc(str);	while (*in != '\0') {	    if (*in == '"') {	        in++;		continue;	    }	    if (*in == '\\') {		in++;		if (*in == 'n') {		    in++;		    *(out++) = '\n';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -