Fixed failing hunks and added preallocate.diff.
[rsync-patches.git] / slp.diff
1 This adds Service Location Protocol support.
2
3 To use this patch, run these commands for a successful build:
4
5     patch -p1 <patches/slp.diff
6     ./prepare-source
7     ./configure --enable-slp
8     make
9
10 TODO: the configure changes should abort if the user requests --enable-slp
11 and we can't honor that request.
12
13 --- old/Makefile.in
14 +++ new/Makefile.in
15 @@ -13,6 +13,8 @@ CFLAGS=@CFLAGS@
16  CPPFLAGS=@CPPFLAGS@
17  EXEEXT=@EXEEXT@
18  LDFLAGS=@LDFLAGS@
19 +LIBSLP=@LIBSLP@
20 +SLPOBJ=@SLPOBJ@
21  
22  INSTALLCMD=@INSTALL@
23  INSTALLMAN=@INSTALL@
24 @@ -36,7 +38,7 @@ OBJS1=rsync.o generator.o receiver.o cle
25  OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
26         fileio.o batch.o clientname.o chmod.o
27  OBJS3=progress.o pipe.o
28 -DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
29 +DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o $(SLPOBJ)
30  popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
31         popt/popthelp.o popt/poptparse.o
32  OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
33 @@ -70,7 +72,7 @@ install-strip:
34         $(MAKE) INSTALL_STRIP='-s' install
35  
36  rsync$(EXEEXT): $(OBJS)
37 -       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
38 +       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(LIBSLP)
39  
40  $(OBJS): $(HEADERS)
41  
42 --- old/clientserver.c
43 +++ new/clientserver.c
44 @@ -849,6 +849,13 @@ int daemon_main(void)
45          * address too.  In fact, why not just do inet_ntop on the
46          * local address??? */
47  
48 +#ifdef HAVE_LIBSLP
49 +       if (register_services()) {
50 +               rprintf(FINFO,
51 +                   "Couldn't register with service discovery protocol, continuing anyway\n");
52 +       }
53 +#endif
54 +
55         if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
56                 char pidbuf[16];
57                 int fd;
58 --- old/configure.in
59 +++ new/configure.in
60 @@ -614,6 +614,29 @@ if test $rsync_cv_can_hardlink_special =
61      AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
62  fi
63  
64 +AC_ARG_ENABLE(slp, [  --disable-slp           turn off SLP support, defaults to on])
65 +AC_ARG_WITH(openslp-libs, [  --with-openslp-libs     set directory for OpenSLP library],
66 +    LDFLAGS="-L$withval $LDFLAGS"
67 +    DSOFLAGS="-L$withval $DSOFLAGS",)
68 +AC_ARG_WITH(openslp-includes, [  --with-openslp-includes set directory for OpenSLP includes],
69 +    CFLAGS="-I$withval $CFLAGS"
70 +    CXXFLAGS="-I$withval $CXXFLAGS"
71 +    CPPFLAGS="-I$withval $CPPFLAGS",)
72 +
73 +LIBSLP=""
74 +SLPOBJ=""
75 +
76 +if test x$enable_slp != xno; then
77 +    AC_CHECK_HEADER(slp.h,
78 +        AC_CHECK_LIB(slp, SLPOpen,
79 +           AC_DEFINE(HAVE_LIBSLP, 1, [Define to 1 for SLP support])
80 +           SLPOBJ="srvreg.o srvloc.o"
81 +            LIBSLP="-lslp"))
82 +fi
83 +
84 +AC_SUBST(LIBSLP)
85 +AC_SUBST(SLPOBJ)
86 +
87  AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
88  AC_TRY_RUN([
89  #include <sys/types.h>
90 --- old/loadparm.c
91 +++ new/loadparm.c
92 @@ -108,6 +108,9 @@ typedef struct
93         char *socket_options;
94  
95         int rsync_port;
96 +#ifdef HAVE_LIBSLP
97 +       int slp_refresh;
98 +#endif
99  } global;
100  
101  static global Globals;
102 @@ -291,6 +294,9 @@ static struct parm_struct parm_table[] =
103   {"motd file",         P_STRING, P_GLOBAL,&Globals.motd_file,          NULL,0},
104   {"pid file",          P_STRING, P_GLOBAL,&Globals.pid_file,           NULL,0},
105   {"port",              P_INTEGER,P_GLOBAL,&Globals.rsync_port,         NULL,0},
106 +#ifdef HAVE_LIBSLP
107 + {"slp refresh",       P_INTEGER,P_GLOBAL,&Globals.slp_refresh,        NULL,0},
108 +#endif
109   {"socket options",    P_STRING, P_GLOBAL,&Globals.socket_options,     NULL,0},
110  
111   {"auth users",        P_STRING, P_LOCAL, &sDefault.auth_users,        NULL,0},
112 @@ -381,6 +387,9 @@ FN_GLOBAL_STRING(lp_pid_file, &Globals.p
113  FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
114  
115  FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
116 +#ifdef HAVE_LIBSLP
117 +FN_GLOBAL_INTEGER(lp_slp_refresh, &Globals.slp_refresh)
118 +#endif
119  
120  FN_LOCAL_STRING(lp_auth_users, auth_users)
121  FN_LOCAL_STRING(lp_comment, comment)
122 --- old/main.c
123 +++ new/main.c
124 @@ -1059,6 +1059,18 @@ static int start_client(int argc, char *
125  
126         if (!read_batch) { /* for read_batch, NO source is specified */
127                 shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
128 +
129 +               if (shell_machine && !shell_machine[0]) {
130 +#ifdef HAVE_LIBSLP
131 +                       /* User entered just rsync:// URI */
132 +                       print_service_list();
133 +                       exit_cleanup(0);
134 +#else /* No SLP, die here */
135 +                       rprintf(FINFO, "No SLP support, cannot browse\n");
136 +                       exit_cleanup(RERR_SYNTAX);
137 +#endif
138 +               }
139 +
140                 if (shell_path) { /* source is remote */
141                         char *dummy1;
142                         int dummy2;
143 --- old/options.c
144 +++ new/options.c
145 @@ -201,6 +201,7 @@ static void print_rsync_version(enum log
146         char const *hardlinks = "no ";
147         char const *links = "no ";
148         char const *ipv6 = "no ";
149 +       char const *slp = "no ";
150         STRUCT_STAT *dumstat;
151  
152  #ifdef HAVE_SOCKETPAIR
153 @@ -223,6 +224,10 @@ static void print_rsync_version(enum log
154         ipv6 = "";
155  #endif
156  
157 +#if HAVE_LIBSLP
158 +       slp = "";
159 +#endif
160 +
161         rprintf(f, "%s  version %s  protocol version %d\n",
162                 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
163         rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
164 @@ -233,8 +238,8 @@ static void print_rsync_version(enum log
165                 (int)(sizeof (int64) * 8));
166         rprintf(f, "    %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
167                 got_socketpair, hardlinks, links, ipv6, have_inplace);
168 -       rprintf(f, "    %sappend\n",
169 -               have_inplace);
170 +       rprintf(f, "    %sappend, %sSLP\n",
171 +               have_inplace, slp);
172  
173  #ifdef MAINTAINER_MODE
174         rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
175 --- old/rsync.h
176 +++ new/rsync.h
177 @@ -158,6 +158,9 @@
178  #define SIGNIFICANT_ITEM_FLAGS (~(\
179         ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
180  
181 +/* this is the minimum we'll use, irrespective of config setting */
182 +/* definately don't set to less than about 30 seconds */
183 +#define SLP_MIN_TIMEOUT 120
184  
185  /* Log-message categories.  Only FERROR and FINFO get sent over the socket,
186   * but FLOG and FSOCKERR can be sent over the receiver -> generator pipe.
187 --- old/rsync.yo
188 +++ new/rsync.yo
189 @@ -139,7 +139,12 @@ particular rsync daemon by leaving off t
190  
191  quote(tt(rsync somehost.mydomain.com::))
192  
193 -See the following section for more details.
194 +And, if Service Location Protocol is available, the following will list the
195 +available rsync servers:
196 +
197 +quote(tt(rsync rsync://))
198 +
199 +See the following section for even more usage details.
200  
201  manpagesection(ADVANCED USAGE)
202  
203 --- old/rsyncd.conf
204 +++ new/rsyncd.conf
205 @@ -0,0 +1,3 @@
206 +
207 +slp refresh = 300
208 +
209 --- old/rsyncd.conf.yo
210 +++ new/rsyncd.conf.yo
211 @@ -103,6 +103,15 @@ details on some of the options you may b
212  special socket options are set.  These settings are superseded by the
213  bf(--sockopts) command-line option.
214  
215 +dit(bf(slp refresh)) This option is used to determine how long service
216 +advertisements are valid (measured in seconds), and is only applicable if
217 +you have Service Location Protocol support compiled in. If this option is
218 +not set or is set to zero, then service advertisements never time out. If
219 +this is set to less than 120 seconds, then 120 seconds is used. If it is
220 +set to more than 65535, then 65535 is used (which is a limitation of SLP).
221 +Using 3600 (one hour) is a good number if you tend to change your
222 +configuration.
223 +
224  enddit()
225  
226  
227 @@ -556,6 +565,7 @@ use chroot = no
228  max connections = 4
229  syslog facility = local5
230  pid file = /var/run/rsyncd.pid
231 +slp refresh = 3600
232  
233  [ftp]
234          path = /var/ftp/pub
235 --- old/socket.c
236 +++ new/socket.c
237 @@ -466,6 +466,16 @@ void start_accept_loop(int port, int (*f
238  {
239         fd_set deffds;
240         int *sp, maxfd, i;
241 +#ifdef HAVE_LIBSLP
242 +       time_t next_slp_refresh;
243 +       short slp_timeout = lp_slp_refresh();
244 +       if (slp_timeout) {
245 +               if (slp_timeout < SLP_MIN_TIMEOUT)
246 +                       slp_timeout = SLP_MIN_TIMEOUT;
247 +               /* re-register before slp times out */
248 +               slp_timeout -= 15;
249 +       }
250 +#endif
251  
252  #ifdef HAVE_SIGACTION
253         sigact.sa_flags = SA_NOCLDSTOP;
254 @@ -494,14 +504,25 @@ void start_accept_loop(int port, int (*f
255                         maxfd = sp[i];
256         }
257  
258 +#ifdef HAVE_LIBSLP
259 +       next_slp_refresh = time(NULL) + slp_timeout;
260 +#endif
261 +
262         /* now accept incoming connections - forking a new process
263          * for each incoming connection */
264         while (1) {
265                 fd_set fds;
266                 pid_t pid;
267                 int fd;
268 +               int sel_ret;
269                 struct sockaddr_storage addr;
270                 socklen_t addrlen = sizeof addr;
271 +#ifdef HAVE_LIBSLP
272 +               struct timeval slp_tv;
273 +
274 +               slp_tv.tv_sec = 10;
275 +               slp_tv.tv_usec = 0;
276 +#endif
277  
278                 /* close log file before the potentially very long select so
279                  * file can be trimmed by another process instead of growing
280 @@ -513,8 +534,18 @@ void start_accept_loop(int port, int (*f
281  #else
282                 fds = deffds;
283  #endif
284 -
285 -               if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
286 +#ifdef HAVE_LIBSLP
287 +               sel_ret = select(maxfd + 1, &fds, NULL, NULL,
288 +                                slp_timeout ? &slp_tv : NULL);
289 +               if (sel_ret == 0 && slp_timeout && time(NULL) > next_slp_refresh) {
290 +                   rprintf(FINFO, "Service registration expired, refreshing it\n");
291 +                   register_services();
292 +                   next_slp_refresh = time(NULL) + slp_timeout;
293 +               }
294 +#else
295 +               sel_ret = select(maxfd + 1, &fds, NULL, NULL, NULL);
296 +#endif
297 +               if (sel_ret != 1)
298                         continue;
299  
300                 for (i = 0, fd = -1; sp[i] >= 0; i++) {
301 --- old/srvloc.c
302 +++ new/srvloc.c
303 @@ -0,0 +1,103 @@
304 +/* -*- c-file-style: "linux"; -*-
305 +
306 +   Copyright (C) 2002 by Brad Hards <bradh@frogmouth.net>
307 +
308 +   This program is free software; you can redistribute it and/or modify
309 +   it under the terms of the GNU General Public License as published by
310 +   the Free Software Foundation; either version 2 of the License, or
311 +   (at your option) any later version.
312 +
313 +   This program is distributed in the hope that it will be useful,
314 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
315 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
316 +   GNU General Public License for more details.
317 +
318 +   You should have received a copy of the GNU General Public License
319 +   along with this program; if not, write to the Free Software
320 +   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
321 +*/
322 +
323 +/* This file implements the service location functionality */
324 +/* Basically, it uses normal Service Location Protocol API */
325 +
326 +/* It is really a cheap hack - just to show how it might work
327 +   in a real application.
328 +*/
329 +
330 +#include "rsync.h"
331 +
332 +#include <slp.h>
333 +#include <stdio.h>
334 +#include <string.h>
335 +
336 +/* This one just prints out the attributes */
337 +static SLPBoolean getAttrCallback(UNUSED(SLPHandle hslp), const char *attrlist,
338 +                                 SLPError errcode, UNUSED(void *cookie))
339 +{
340 +       char *cleanstr;
341 +
342 +       if (errcode == SLP_OK) {
343 +               if (!strcmp(attrlist, "(comment=)"))
344 +                       rprintf(FINFO, "\t(No description)\n");
345 +               else {
346 +                       cleanstr = strrchr(attrlist, ')') ;
347 +                       *cleanstr = ' '; /* remove last ')' */
348 +                       rprintf(FINFO, "\t%s\n", strchr(attrlist, '=') + 1);
349 +               }
350 +       }
351 +       return SLP_FALSE;
352 +}
353 +
354 +static SLPBoolean getSLPSrvURLCallback(UNUSED(SLPHandle hslp),
355 +                       const char *srvurl, UNUSED(unsigned short lifetime),
356 +                       SLPError errcode, void *cookie)
357 +{
358 +       SLPError    result;
359 +       SLPHandle   attrhslp;
360 +
361 +       if (errcode == SLP_OK) {
362 +               /* chop service: off the front */
363 +               rprintf(FINFO, "  %s  ", (strchr(srvurl, ':') + 1));
364 +               /* check for any attributes */
365 +               if (SLPOpen("en", SLP_FALSE,&attrhslp) == SLP_OK) {
366 +                       result = SLPFindAttrs(attrhslp, srvurl,
367 +                                             "", /* return all attributes */
368 +                                             "", /* use configured scopes */
369 +                                             getAttrCallback, NULL);
370 +                       if (result != SLP_OK) {
371 +                               rprintf(FERROR, "errorcode: %i\n",result);
372 +                       }
373 +                       SLPClose(attrhslp);
374 +               }
375 +               *(SLPError*)cookie = SLP_OK;
376 +       } else
377 +               *(SLPError*)cookie = errcode;
378 +
379 +       /* Return SLP_TRUE because we want to be called again
380 +        * if more services were found. */
381 +
382 +       return SLP_TRUE;
383 +}
384 +
385 +int print_service_list(void)
386 +{
387 +       SLPError err;
388 +       SLPError callbackerr;
389 +       SLPHandle hslp;
390 +
391 +       err = SLPOpen("en",SLP_FALSE,&hslp);
392 +       if (err != SLP_OK) {
393 +               rprintf(FERROR, "Error opening slp handle %i\n", err);
394 +               return err;
395 +       }
396 +
397 +       SLPFindSrvs(hslp, "rsync",
398 +                   0, /* use configured scopes */
399 +                   0, /* no attr filter        */
400 +                   getSLPSrvURLCallback, &callbackerr);
401 +
402 +       /* Now that we're done using slp, close the slp handle */
403 +       SLPClose(hslp);
404 +
405 +       return 0;
406 +}
407 --- old/srvreg.c
408 +++ new/srvreg.c
409 @@ -0,0 +1,128 @@
410 +/* -*- c-file-style: "linux"; -*-
411 +
412 +   Copyright (C) 2002 by Brad Hards <bradh@frogmouth.net>
413 +
414 +   This program is free software; you can redistribute it and/or modify
415 +   it under the terms of the GNU General Public License as published by
416 +   the Free Software Foundation; either version 2 of the License, or
417 +   (at your option) any later version.
418 +
419 +   This program is distributed in the hope that it will be useful,
420 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
421 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
422 +   GNU General Public License for more details.
423 +
424 +   You should have received a copy of the GNU General Public License
425 +   along with this program; if not, write to the Free Software
426 +   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
427 +*/
428 +
429 +/* This file implements the service registration functionality */
430 +
431 +/* Basically, it uses normal Service Location Protocol API */
432 +
433 +#include "rsync.h"
434 +#include "slp.h"
435 +#include "netdb.h"
436 +
437 +extern int rsync_port;
438 +
439 +static void slp_callback(UNUSED(SLPHandle hslp), SLPError errcode, void *cookie)
440 +{
441 +       /* return the error code in the cookie */
442 +       *(SLPError*)cookie = errcode;
443 +
444 +       /* You could do something else here like print out
445 +        * the errcode, etc.  Remember, as a general rule,
446 +        * do not try to do too much in a callback because
447 +        * it is being executed by the same thread that is
448 +        * reading slp packets from the wire. */
449 +}
450 +
451 +int register_services(void)
452 +{
453 +       SLPError err, callbackerr;
454 +       SLPHandle hslp;
455 +       int n;
456 +       int i;
457 +       char srv[120];
458 +       char attr[120];
459 +       char localhost[256];
460 +       extern char *config_file;
461 +       short timeout;
462 +       struct addrinfo aih, *ai = 0;
463 +
464 +       if (!lp_load(config_file, 0)) {
465 +               exit_cleanup(RERR_SYNTAX);
466 +       }
467 +
468 +       n = lp_numservices();
469 +
470 +       if (0 == lp_slp_refresh())
471 +               timeout = SLP_LIFETIME_MAXIMUM; /* don't expire, ever */
472 +       else if (SLP_MIN_TIMEOUT > lp_slp_refresh())
473 +               timeout = SLP_MIN_TIMEOUT; /* use a reasonable minimum */
474 +       else if (SLP_LIFETIME_MAXIMUM <= lp_slp_refresh())
475 +               timeout = (SLP_LIFETIME_MAXIMUM - 1); /* as long as possible */
476 +       else
477 +               timeout = lp_slp_refresh();
478 +
479 +       rprintf(FINFO, "rsyncd registering %d service%s with slpd for %d seconds:\n", n, ((n==1)? "":"s"), timeout);
480 +       err = SLPOpen("en",SLP_FALSE,&hslp);
481 +       if (err != SLP_OK) {
482 +               rprintf(FINFO, "Error opening slp handle %i\n",err);
483 +               return err;
484 +       }
485 +       if (gethostname(localhost, sizeof localhost)) {
486 +              rprintf(FINFO, "Could not get hostname: %s\n", strerror(errno));
487 +              return err;
488 +       }
489 +       memset(&aih, 0, sizeof aih);
490 +       aih.ai_family = PF_UNSPEC;
491 +       aih.ai_flags = AI_CANONNAME;
492 +       if (0 != (err = getaddrinfo(localhost, 0, &aih, &ai)) || !ai) {
493 +              rprintf(FINFO, "Could not resolve hostname: %s\n", gai_strerror(err));
494 +              return err;
495 +       }
496 +       /* Register each service with SLP */
497 +       for (i = 0; i < n; i++) {
498 +               if (!lp_list(i))
499 +                       continue;
500 +
501 +               snprintf(srv, sizeof srv, "service:rsync://%s:%d/%s",
502 +                        ai->ai_canonname,
503 +                        rsync_port,
504 +                        lp_name(i));
505 +               rprintf(FINFO, "    %s\n", srv);
506 +               if (lp_comment(i)) {
507 +                       snprintf(attr, sizeof attr, "(comment=%s)",
508 +                                lp_comment(i));
509 +               }
510 +               err = SLPReg(hslp,
511 +                            srv, /* service to register */
512 +                            timeout,
513 +                            0,  /* this is ignored */
514 +                            attr, /* attributes */
515 +                            SLP_TRUE, /* new registration - don't change this */
516 +                            slp_callback, /* callback */
517 +                            &callbackerr);
518 +
519 +               /* err may contain an error code that occurred as the slp library
520 +                * _prepared_ to make the call. */
521 +               if (err != SLP_OK || callbackerr != SLP_OK)
522 +                       rprintf(FINFO, "Error registering service with slp %i\n", err);
523 +
524 +               /* callbackerr may contain an error code (that was assigned through
525 +                * the callback cookie) that occurred as slp packets were sent on
526 +                * the wire. */
527 +               if (callbackerr != SLP_OK)
528 +                       rprintf(FINFO, "Error registering service with slp %i\n",callbackerr);
529 +       }
530 +
531 +       /* Now that we're done using slp, close the slp handle */
532 +       freeaddrinfo(ai);
533 +       SLPClose(hslp);
534 +
535 +       /* refresh is done in main select loop */
536 +       return 0;
537 +}