URI: 
       tRearrange function declaration - synk - synchronize files between hosts
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit bc9d67414e3bc01b83f7a6b054397fa3e2ee986e
   DIR parent a5fa976251072410375f2466833bef081e496846
  HTML Author: Willy <willyatmailoodotorg>
       Date:   Sun,  4 Sep 2016 10:32:23 +0200
       
       Rearrange function declaration
       
       Diffstat:
         M synk.c                              |     367 ++++++++++++++++---------------
       
       1 file changed, 187 insertions(+), 180 deletions(-)
       ---
   DIR diff --git a/synk.c b/synk.c
       t@@ -65,23 +65,23 @@ enum {
        };
        
        void usage(char *name);
       -int sendmetadata(struct client_t *);
       -int serverloop(in_addr_t, in_port_t);
       -
        char *echo(char * []);
        char **concat(int, ...);
       -struct in_addr *resolve(char *);
        
       -struct peer_t *addpeer(struct peers_t *, char *, in_port_t);
        long gettimestamp(const char *path);
       -int getpeermeta(struct peer_t *, struct metadata_t *);
       +struct in_addr *getinetaddr(char *);
       +struct metadata_t *getmetadata(const char *);
       +struct peer_t *addpeer(struct peers_t *, char *, in_port_t);
        struct peer_t *freshestpeer(struct peers_t *);
       -int syncfile(struct peers_t *, const char *);
       -int uptodate(struct peers_t *);
       +int getpeermeta(struct peer_t *, struct metadata_t *);
        int flushpeers(struct peers_t *);
       -int syncwithmaster(struct peer_t *master, struct peers_t *plist);
       -int dosync(struct peer_t *master, struct peer_t *slave);
        int spawnremote(struct peers_t *);
       +int uptodate(struct peers_t *);
       +int dosync(struct peer_t *master, struct peer_t *slave);
       +int syncwithmaster(struct peer_t *master, struct peers_t *plist);
       +int syncfile(struct peers_t *, const char *);
       +int sendmetadata(struct client_t *);
       +int waitclient(in_addr_t, in_port_t);
        
        const char *rsync_cmd[] = { "rsync", "-azEq", "--delete", NULL };
        const char *ssh_cmd[] = { "ssh", NULL };
       t@@ -158,40 +158,6 @@ concat(int n, ...)
        }
        
        /*
       - * Put an hostname, get an in_addr!
       - * This is intended to be consumed directly, as gethostbyname() might
       - * return a pointer to a static buffer
       - */
       -struct in_addr *
       -resolve(char *hostname)
       -{
       -        struct hostent *he;
       -        
       -        if (!(he = gethostbyname(hostname))) {
       -                herror(hostname);
       -                return NULL;
       -        }
       -        
       -        return ((struct in_addr **)he->h_addr_list)[0];
       -}
       -
       -/*
       - * Returns the UNIX timestamp for the given file, or -1 in case stat(2)
       - * is in error.
       - */
       -long
       -gettimestamp(const char *path)
       -{
       -        struct stat sb;
       -        if (stat(path, &sb) < 0) {
       -                log(LOG_ERROR, "%s: %s\n", path, strerror(errno));;
       -                return -1;
       -        }
       -
       -        return sb.st_mtim.tv_sec;
       -}
       -
       -/*
         * Retrieve metadata about a filename and store it in the given pointer.
         * The pointer must be already allocated
         */
       t@@ -219,85 +185,38 @@ getmetadata(const char *fn)
                return meta;
        }
        
       -
        /*
       - * Read a path from a connected client, get the timestamp for this path and
       - * send it back to the client. Close connection afterward.
       + * Returns the UNIX timestamp for the given file, or -1 in case stat(2)
       + * is in error.
         */
       -int
       -sendmetadata(struct client_t *c)
       +long
       +gettimestamp(const char *path)
        {
       -        ssize_t len = 0;
       -        struct metadata_t *local, remote;
       -
       -        memset(&remote, 0, sizeof(remote));
       -
       -        if ((len = read(c->fd, &remote, sizeof(remote))) < 0) {
       -                log(LOG_ERROR, "%s: %s\n", inet_ntoa(c->inet), strerror(errno));;
       +        struct stat sb;
       +        if (stat(path, &sb) < 0) {
       +                log(LOG_ERROR, "%s: %s\n", path, strerror(errno));;
                        return -1;
                }
        
       -        local = getmetadata(remote.path);
       -
       -        /* .. and send it to the client */
       -        write(c->fd, local, sizeof(struct metadata_t));
       -        close(c->fd);
       -
       -        free(c);
       -
       -        return -1;
       +        return sb.st_mtim.tv_sec;
        }
        
        /*
       - * Server part: bind on given address/port and wait for a client connection.
       - * Only one client is handled per server instance, and the server gets close
       - * at the end.
       + * Put an hostname, get an in_addr!
       + * This is intended to be consumed directly, as gethostbyname() might
       + * return a pointer to a static buffer
         */
       -int
       -serverloop(in_addr_t host, in_port_t port)
       +struct in_addr *
       +getinetaddr(char *hostname)
        {
       -        int sfd;
       -        int cfd;
       -        socklen_t len;
       -        struct sockaddr_in clt;
       -        struct sockaddr_in srv;
       -        struct client_t *c = NULL;
       -
       -        if ((sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
       -                log(LOG_ERROR, "socket: %s\n", strerror(errno));;
       -                return -1;
       -        }
       -
       -        memset(&srv, 0, sizeof(srv));
       -        srv.sin_family        = AF_INET;
       -        srv.sin_addr.s_addr   = host;
       -        srv.sin_port          = htons(port);
       -
       -        if (bind(sfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) {
       -                log(LOG_ERROR, "bind: %s\n", strerror(errno));;
       -                return -1;
       -        }
       -
       -        if (listen(sfd, CONNECTION_MAX) < 0) {
       -                log(LOG_ERROR, "listen: %s\n", strerror(errno));;
       -                return -1;
       -        }
       +        struct hostent *he;
        
       -        len = sizeof(clt);
       -        if ((cfd = accept(sfd, (struct sockaddr *)&clt, &len)) < 0) {
       -                log(LOG_ERROR, "accept: %s\n", strerror(errno));;
       -                return -1;
       +        if (!(he = gethostbyname(hostname))) {
       +                herror(hostname);
       +                return NULL;
                }
        
       -        alarm(0); /* cancel previously set SIGALRM */
       -
       -        c = malloc(sizeof(struct client_t));
       -        c->fd = cfd;
       -        c->inet = clt.sin_addr;
       -
       -        sendmetadata(c);
       -
       -        return close(sfd);
       +        return ((struct in_addr **)he->h_addr_list)[0];
        }
        
        /*
       t@@ -321,7 +240,7 @@ addpeer(struct peers_t *plist, char *hostname, in_port_t port)
                }
        
                strncpy(entry->host, hostname, HOST_NAME_MAX);
       -        host = resolve(hostname);
       +        host = getinetaddr(hostname);
        
                entry->peer.sin_family        = AF_INET;
                entry->peer.sin_addr.s_addr   = host->s_addr;
       t@@ -333,37 +252,24 @@ addpeer(struct peers_t *plist, char *hostname, in_port_t port)
        }
        
        /*
       - * Empty the linked-list containing all peers
       + * return a pointer to the peer having the highest timestamp.
       + * NULL is returned in case the local file is the most recent
         */
       -int
       -flushpeers(struct peers_t *plist)
       +struct peer_t *
       +freshestpeer(struct peers_t *plist)
        {
       +        long ts = -1;
                struct peer_t *tmp = NULL;
       -        while (!SLIST_EMPTY(plist)) {
       -                tmp = SLIST_FIRST(plist);
       -                SLIST_REMOVE_HEAD(plist, entries);
       -                free(tmp);
       -        }
       -
       -        return 0;
       -}
       -
       -/*
       - * Check the synchronisation status between all peers. If at least 2 hashes
       - * differ, it returns with a non-zero status.
       - */
       -int
       -uptodate(struct peers_t *plist)
       -{
       -        struct peer_t *tmp, *ref;
       +        struct peer_t *freshest = NULL;
        
       -        ref = SLIST_FIRST(plist);
                SLIST_FOREACH(tmp, plist, entries) {
       -                if (!sha512_compare(ref->meta.hash, tmp->meta.hash))
       -                        return 0;
       +                if (tmp->meta.mtime > ts) {
       +                        freshest = tmp;
       +                        ts = tmp->meta.mtime;
       +                }
                }
        
       -        return 1;
       +        return freshest;
        }
        
        /*
       t@@ -412,45 +318,149 @@ getpeermeta(struct peer_t *clt, struct metadata_t *local)
        }
        
        /*
       - * return a pointer to the peer having the highest timestamp.
       - * NULL is returned in case the local file is the most recent
       + * Empty the linked-list containing all peers
         */
       -struct peer_t *
       -freshestpeer(struct peers_t *plist)
       +int
       +flushpeers(struct peers_t *plist)
        {
       -        long ts = -1;
                struct peer_t *tmp = NULL;
       -        struct peer_t *freshest = NULL;
       +        while (!SLIST_EMPTY(plist)) {
       +                tmp = SLIST_FIRST(plist);
       +                SLIST_REMOVE_HEAD(plist, entries);
       +                free(tmp);
       +        }
       +
       +        return 0;
       +}
       +
       +/*
       + * Read a path from a connected client, get the timestamp for this path and
       + * send it back to the client. Close connection afterward.
       + */
       +int
       +sendmetadata(struct client_t *c)
       +{
       +        ssize_t len = 0;
       +        struct metadata_t *local, remote;
       +
       +        memset(&remote, 0, sizeof(remote));
       +
       +        if ((len = read(c->fd, &remote, sizeof(remote))) < 0) {
       +                log(LOG_ERROR, "%s: %s\n", inet_ntoa(c->inet), strerror(errno));;
       +                return -1;
       +        }
       +
       +        local = getmetadata(remote.path);
       +
       +        /* .. and send it to the client */
       +        write(c->fd, local, sizeof(struct metadata_t));
       +        close(c->fd);
       +
       +        free(c);
       +
       +        return -1;
       +}
       +
       +/*
       + * Server part: bind on given address/port and wait for a client connection.
       + * Only one client is handled per server instance, and the server gets close
       + * at the end.
       + */
       +int
       +waitclient(in_addr_t host, in_port_t port)
       +{
       +        int sfd;
       +        int cfd;
       +        socklen_t len;
       +        struct sockaddr_in clt;
       +        struct sockaddr_in srv;
       +        struct client_t *c = NULL;
       +
       +        if ((sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
       +                log(LOG_ERROR, "socket: %s\n", strerror(errno));;
       +                return -1;
       +        }
       +
       +        memset(&srv, 0, sizeof(srv));
       +        srv.sin_family        = AF_INET;
       +        srv.sin_addr.s_addr   = host;
       +        srv.sin_port          = htons(port);
       +
       +        if (bind(sfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) {
       +                log(LOG_ERROR, "bind: %s\n", strerror(errno));;
       +                return -1;
       +        }
       +
       +        if (listen(sfd, CONNECTION_MAX) < 0) {
       +                log(LOG_ERROR, "listen: %s\n", strerror(errno));;
       +                return -1;
       +        }
       +
       +        len = sizeof(clt);
       +        if ((cfd = accept(sfd, (struct sockaddr *)&clt, &len)) < 0) {
       +                log(LOG_ERROR, "accept: %s\n", strerror(errno));;
       +                return -1;
       +        }
       +
       +        alarm(0); /* cancel previously set SIGALRM */
       +
       +        c = malloc(sizeof(struct client_t));
       +        c->fd = cfd;
       +        c->inet = clt.sin_addr;
       +
       +        sendmetadata(c);
       +
       +        return close(sfd);
       +}
       +
       +/*
       + * Connect via ssh to a remote and spawn an instance running in server-mode
       + */
       +int
       +spawnremote(struct peers_t *plist)
       +{
       +        char **cmd = NULL;
       +        char synk_cmd[_POSIX_ARG_MAX];
       +
       +        struct peer_t *tmp;
        
                SLIST_FOREACH(tmp, plist, entries) {
       -                if (tmp->meta.mtime > ts) {
       -                        freshest = tmp;
       -                        ts = tmp->meta.mtime;
       +                snprintf(synk_cmd, _POSIX_ARG_MAX, "synk -s -h %s",
       +                        inet_ntoa(tmp->peer.sin_addr));
       +                cmd = concat(2, ssh_cmd, (char *[]){ tmp->host, synk_cmd, NULL });
       +                if (!fork()) {
       +                        log(LOG_VERBOSE, "%s\n", echo(cmd));
       +                        execvp(cmd[0], cmd);
       +                        log(LOG_ERROR, "%s: %s\n", cmd[0], strerror(errno));;
       +                        return -1;
                        }
                }
       -
       -        return freshest;
       +        return 0;
        }
        
        /*
       - * Logic to synchronize a remote peer with all the slaves if they differ
       + * Check the synchronisation status between all peers. If at least 2 hashes
       + * differ, it returns with a non-zero status.
         */
        int
       -syncwithmaster(struct peer_t *master, struct peers_t *plist)
       +uptodate(struct peers_t *plist)
        {
       -        int ret = 0;
       -        struct peer_t *slave = NULL;
       -        SLIST_FOREACH(slave, plist, entries) {
       -                if (slave == master)
       -                        continue;
       -                if (!sha512_compare(master->meta.hash, slave->meta.hash))
       -                        continue;
       +        struct peer_t *tmp, *ref;
        
       -                ret += dosync(master, slave);
       +        ref = SLIST_FIRST(plist);
       +        SLIST_FOREACH(tmp, plist, entries) {
       +                if (!sha512_compare(ref->meta.hash, tmp->meta.hash))
       +                        return 0;
                }
       -        return ret;
       +
       +        return 1;
        }
        
       +/*
       + * Given a master and a slave, create the appropriate rsync(1) command to
       + * get the slave in sync with the master, from localhost (this might involve
       + * using ssh to spawn the rsync process on a remote master)
       + */
        int
        dosync(struct peer_t *master, struct peer_t *slave)
        {
       t@@ -489,6 +499,25 @@ dosync(struct peer_t *master, struct peer_t *slave)
        }
        
        /*
       + * Logic to synchronize a remote peer with all the slaves if they differ
       + */
       +int
       +syncwithmaster(struct peer_t *master, struct peers_t *plist)
       +{
       +        int ret = 0;
       +        struct peer_t *slave = NULL;
       +        SLIST_FOREACH(slave, plist, entries) {
       +                if (slave == master)
       +                        continue;
       +                if (!sha512_compare(master->meta.hash, slave->meta.hash))
       +                        continue;
       +
       +                ret += dosync(master, slave);
       +        }
       +        return ret;
       +}
       +
       +/*
         * Check the synchronisation state of a file between mutliple peers, and
         * synchronise them if they differ
         */
       t@@ -528,28 +557,6 @@ syncfile(struct peers_t *plist, const char *fn)
        }
        
        int
       -spawnremote(struct peers_t *plist)
       -{
       -        char **cmd = NULL;
       -        char synk_cmd[_POSIX_ARG_MAX];
       -
       -        struct peer_t *tmp;
       -
       -        SLIST_FOREACH(tmp, plist, entries) {
       -                snprintf(synk_cmd, _POSIX_ARG_MAX, "synk -s -h %s",
       -                        inet_ntoa(tmp->peer.sin_addr));
       -                cmd = concat(2, ssh_cmd, (char *[]){ tmp->host, synk_cmd, NULL });
       -                if (!fork()) {
       -                        log(LOG_VERBOSE, "%s\n", echo(cmd));
       -                        execvp(cmd[0], cmd);
       -                        log(LOG_ERROR, "%s: %s\n", cmd[0], strerror(errno));;
       -                        return -1;
       -                }
       -        }
       -        return 0;
       -}
       -
       -int
        main(int argc, char *argv[])
        {
                char *argv0, *fn;
       t@@ -567,9 +574,9 @@ main(int argc, char *argv[])
                                addpeer(&plist, hostname, port);
                        break;
                case 'p': port = atoi(EARGF(usage(argv0))); break;
       +        case 'q': verbose = LOG_NONE; break;
                case 's': mode = SYNK_SERVER; break;
                case 'v': verbose++; break;
       -        case 'q': verbose = LOG_NONE; break;
                }ARGEND;
        
                if (hostname == NULL)
       t@@ -584,7 +591,7 @@ main(int argc, char *argv[])
                        break;
                case SYNK_SERVER:
                        alarm(TIMEOUT);
       -                serverloop(resolve(hostname)->s_addr, port);
       +                waitclient(getinetaddr(hostname)->s_addr, port);
                        break;
                }
                return 0;