Commit | Line | Data |
---|---|---|
c627d613 AT |
1 | /* |
2 | Copyright (C) Andrew Tridgell 1996 | |
3 | Copyright (C) Paul Mackerras 1996 | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | /* | |
21 | Utilities used in rsync | |
22 | ||
23 | tridge, June 1996 | |
24 | */ | |
25 | #include "rsync.h" | |
26 | ||
720b47f2 | 27 | int num_waiting(int fd) |
94481d91 AT |
28 | { |
29 | int len=0; | |
94481d91 | 30 | ioctl(fd,FIONREAD,&len); |
94481d91 AT |
31 | return(len); |
32 | } | |
33 | ||
d9bea2dd | 34 | |
bcacc18b | 35 | struct map_struct *map_file(int fd,OFF_T len) |
c627d613 | 36 | { |
c6e7fcb4 AT |
37 | struct map_struct *ret; |
38 | ret = (struct map_struct *)malloc(sizeof(*ret)); | |
39 | if (!ret) out_of_memory("map_file"); | |
40 | ||
41 | ret->map = NULL; | |
42 | ret->fd = fd; | |
43 | ret->size = len; | |
44 | ret->p = NULL; | |
45 | ret->p_size = 0; | |
46 | ret->p_offset = 0; | |
47 | ret->p_len = 0; | |
48 | ||
d9bea2dd | 49 | #ifdef HAVE_MMAP |
94c9ef1f AT |
50 | if (len < MAX_MAP_SIZE) { |
51 | ret->map = (char *)mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0); | |
52 | if (ret->map == (char *)-1) { | |
53 | ret->map = NULL; | |
54 | } | |
55 | } | |
d9bea2dd | 56 | #endif |
c627d613 AT |
57 | return ret; |
58 | } | |
59 | ||
0b910560 | 60 | |
bcacc18b | 61 | char *map_ptr(struct map_struct *map,OFF_T offset,int len) |
d9bea2dd | 62 | { |
0cfcfa29 AT |
63 | int nread = -2; |
64 | ||
c6e7fcb4 AT |
65 | if (map->map) |
66 | return map->map+offset; | |
d9bea2dd AT |
67 | |
68 | if (len == 0) | |
69 | return NULL; | |
70 | ||
0b910560 AT |
71 | if (len > (map->size-offset)) |
72 | len = map->size-offset; | |
d9bea2dd | 73 | |
c6e7fcb4 AT |
74 | if (offset >= map->p_offset && |
75 | offset+len <= map->p_offset+map->p_len) { | |
76 | return (map->p + (offset - map->p_offset)); | |
d9bea2dd AT |
77 | } |
78 | ||
34ccb63e | 79 | len = MAX(len,CHUNK_SIZE); |
0b910560 AT |
80 | if (len > (map->size-offset)) |
81 | len = map->size-offset; | |
d9bea2dd | 82 | |
c6e7fcb4 AT |
83 | if (len > map->p_size) { |
84 | if (map->p) free(map->p); | |
85 | map->p = (char *)malloc(len); | |
86 | if (!map->p) out_of_memory("map_ptr"); | |
87 | map->p_size = len; | |
d9bea2dd AT |
88 | } |
89 | ||
73233f0f | 90 | if (do_lseek(map->fd,offset,SEEK_SET) != offset || |
0cfcfa29 | 91 | (nread=read(map->fd,map->p,len)) != len) { |
9486289c | 92 | rprintf(FERROR,"EOF in map_ptr! (offset=%d len=%d nread=%d errno=%d)\n", |
feaa89c4 AT |
93 | (int)offset, len, nread, errno); |
94 | exit_cleanup(1); | |
d9bea2dd AT |
95 | } |
96 | ||
c6e7fcb4 AT |
97 | map->p_offset = offset; |
98 | map->p_len = len; | |
d9bea2dd | 99 | |
c6e7fcb4 | 100 | return map->p; |
d9bea2dd AT |
101 | } |
102 | ||
103 | ||
c6e7fcb4 | 104 | void unmap_file(struct map_struct *map) |
c627d613 | 105 | { |
7bec6a5c | 106 | #ifdef HAVE_MMAP |
c6e7fcb4 AT |
107 | if (map->map) |
108 | munmap(map->map,map->size); | |
7bec6a5c | 109 | #endif |
c6e7fcb4 AT |
110 | if (map->p) free(map->p); |
111 | free(map); | |
c627d613 AT |
112 | } |
113 | ||
114 | ||
c627d613 AT |
115 | /* this is taken from CVS */ |
116 | int piped_child(char **command,int *f_in,int *f_out) | |
117 | { | |
118 | int pid; | |
119 | int to_child_pipe[2]; | |
120 | int from_child_pipe[2]; | |
121 | ||
122 | if (pipe(to_child_pipe) < 0 || | |
123 | pipe(from_child_pipe) < 0) { | |
9486289c | 124 | rprintf(FERROR,"pipe: %s\n",strerror(errno)); |
34ccb63e | 125 | exit_cleanup(1); |
c627d613 AT |
126 | } |
127 | ||
128 | ||
3ba62a83 | 129 | pid = do_fork(); |
c627d613 | 130 | if (pid < 0) { |
9486289c | 131 | rprintf(FERROR,"fork: %s\n",strerror(errno)); |
34ccb63e | 132 | exit_cleanup(1); |
c627d613 AT |
133 | } |
134 | ||
135 | if (pid == 0) | |
136 | { | |
6574b4f7 | 137 | extern int orig_umask; |
c627d613 AT |
138 | if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || |
139 | close(to_child_pipe[1]) < 0 || | |
140 | close(from_child_pipe[0]) < 0 || | |
141 | dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { | |
9486289c | 142 | rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); |
34ccb63e | 143 | exit_cleanup(1); |
c627d613 | 144 | } |
773f2bd4 AT |
145 | if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); |
146 | if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); | |
6574b4f7 | 147 | umask(orig_umask); |
c627d613 | 148 | execvp(command[0], command); |
9486289c | 149 | rprintf(FERROR,"Failed to exec %s : %s\n", |
c627d613 | 150 | command[0],strerror(errno)); |
34ccb63e | 151 | exit_cleanup(1); |
c627d613 AT |
152 | } |
153 | ||
154 | if (close(from_child_pipe[1]) < 0 || | |
155 | close(to_child_pipe[0]) < 0) { | |
9486289c | 156 | rprintf(FERROR,"Failed to close : %s\n",strerror(errno)); |
34ccb63e | 157 | exit_cleanup(1); |
c627d613 AT |
158 | } |
159 | ||
160 | *f_in = from_child_pipe[0]; | |
161 | *f_out = to_child_pipe[1]; | |
162 | ||
163 | return pid; | |
164 | } | |
165 | ||
366345fe AT |
166 | int local_child(int argc, char **argv,int *f_in,int *f_out) |
167 | { | |
168 | int pid; | |
169 | int to_child_pipe[2]; | |
170 | int from_child_pipe[2]; | |
171 | ||
172 | if (pipe(to_child_pipe) < 0 || | |
173 | pipe(from_child_pipe) < 0) { | |
9486289c | 174 | rprintf(FERROR,"pipe: %s\n",strerror(errno)); |
366345fe AT |
175 | exit_cleanup(1); |
176 | } | |
177 | ||
178 | ||
179 | pid = do_fork(); | |
180 | if (pid < 0) { | |
9486289c | 181 | rprintf(FERROR,"fork: %s\n",strerror(errno)); |
366345fe AT |
182 | exit_cleanup(1); |
183 | } | |
184 | ||
185 | if (pid == 0) { | |
186 | extern int am_sender; | |
187 | extern int am_server; | |
188 | ||
189 | am_sender = !am_sender; | |
190 | am_server = 1; | |
191 | ||
192 | if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || | |
193 | close(to_child_pipe[1]) < 0 || | |
194 | close(from_child_pipe[0]) < 0 || | |
195 | dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { | |
9486289c | 196 | rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); |
366345fe AT |
197 | exit_cleanup(1); |
198 | } | |
199 | if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); | |
200 | if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); | |
9486289c | 201 | start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); |
366345fe AT |
202 | } |
203 | ||
204 | if (close(from_child_pipe[1]) < 0 || | |
205 | close(to_child_pipe[0]) < 0) { | |
9486289c | 206 | rprintf(FERROR,"Failed to close : %s\n",strerror(errno)); |
366345fe AT |
207 | exit_cleanup(1); |
208 | } | |
209 | ||
210 | *f_in = from_child_pipe[0]; | |
211 | *f_out = to_child_pipe[1]; | |
212 | ||
213 | return pid; | |
214 | } | |
215 | ||
216 | ||
c627d613 AT |
217 | |
218 | void out_of_memory(char *str) | |
219 | { | |
9486289c | 220 | rprintf(FERROR,"ERROR: out of memory in %s\n",str); |
575f2fca AT |
221 | exit_cleanup(1); |
222 | } | |
223 | ||
224 | void overflow(char *str) | |
225 | { | |
9486289c | 226 | rprintf(FERROR,"ERROR: buffer overflow in %s\n",str); |
34ccb63e | 227 | exit_cleanup(1); |
c627d613 AT |
228 | } |
229 | ||
230 | ||
c627d613 AT |
231 | |
232 | int set_modtime(char *fname,time_t modtime) | |
233 | { | |
31e12522 AT |
234 | extern int dry_run; |
235 | if (dry_run) return 0; | |
236 | { | |
1e9f155a | 237 | #ifdef HAVE_UTIMBUF |
31e12522 AT |
238 | struct utimbuf tbuf; |
239 | tbuf.actime = time(NULL); | |
240 | tbuf.modtime = modtime; | |
241 | return utime(fname,&tbuf); | |
c627d613 | 242 | #elif defined(HAVE_UTIME) |
31e12522 AT |
243 | time_t t[2]; |
244 | t[0] = time(NULL); | |
245 | t[1] = modtime; | |
246 | return utime(fname,t); | |
c627d613 | 247 | #else |
31e12522 AT |
248 | struct timeval t[2]; |
249 | t[0].tv_sec = time(NULL); | |
250 | t[0].tv_usec = 0; | |
251 | t[1].tv_sec = modtime; | |
252 | t[1].tv_usec = 0; | |
253 | return utimes(fname,t); | |
c627d613 | 254 | #endif |
31e12522 | 255 | } |
c627d613 | 256 | } |
94481d91 | 257 | |
720b47f2 AT |
258 | |
259 | ||
260 | /**************************************************************************** | |
261 | Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, | |
262 | else | |
263 | if SYSV use O_NDELAY | |
264 | if BSD use FNDELAY | |
265 | ****************************************************************************/ | |
266 | int set_blocking(int fd, int set) | |
267 | { | |
268 | int val; | |
269 | #ifdef O_NONBLOCK | |
270 | #define FLAG_TO_SET O_NONBLOCK | |
271 | #else | |
272 | #ifdef SYSV | |
273 | #define FLAG_TO_SET O_NDELAY | |
274 | #else /* BSD */ | |
275 | #define FLAG_TO_SET FNDELAY | |
276 | #endif | |
277 | #endif | |
278 | ||
279 | if((val = fcntl(fd, F_GETFL, 0)) == -1) | |
280 | return -1; | |
281 | if(set) /* Turn blocking on - ie. clear nonblock flag */ | |
282 | val &= ~FLAG_TO_SET; | |
283 | else | |
284 | val |= FLAG_TO_SET; | |
285 | return fcntl( fd, F_SETFL, val); | |
286 | #undef FLAG_TO_SET | |
287 | } | |
6574b4f7 AT |
288 | |
289 | /**************************************************************************** | |
290 | create any necessary directories in fname. Unfortunately we don't know | |
291 | what perms to give the directory when this is called so we need to rely | |
292 | on the umask | |
293 | ****************************************************************************/ | |
294 | int create_directory_path(char *fname) | |
295 | { | |
296 | extern int orig_umask; | |
297 | char *p; | |
298 | ||
299 | while (*fname == '/') fname++; | |
300 | while (strncmp(fname,"./",2)==0) fname += 2; | |
301 | ||
302 | p = fname; | |
303 | while ((p=strchr(p,'/'))) { | |
304 | *p = 0; | |
1b2d733a | 305 | do_mkdir(fname,0777 & ~orig_umask); |
6574b4f7 AT |
306 | *p = '/'; |
307 | p++; | |
308 | } | |
309 | return 0; | |
310 | } | |
950ab32d AT |
311 | |
312 | ||
313 | /* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted. | |
314 | Return LEN upon success, write's (negative) error code otherwise. | |
315 | ||
316 | derived from GNU C's cccp.c. | |
317 | */ | |
318 | int full_write(int desc, char *ptr, int len) | |
319 | { | |
320 | int total_written; | |
321 | ||
322 | total_written = 0; | |
323 | while (len > 0) { | |
324 | int written = write (desc, ptr, len); | |
325 | if (written < 0) { | |
326 | #ifdef EINTR | |
327 | if (errno == EINTR) | |
328 | continue; | |
329 | #endif | |
330 | return written; | |
331 | } | |
332 | total_written += written; | |
333 | ptr += written; | |
334 | len -= written; | |
335 | } | |
336 | return total_written; | |
337 | } | |
338 | ||
339 | /* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted. | |
340 | Return the actual number of bytes read, zero for EOF, or negative | |
341 | for an error. | |
342 | ||
343 | derived from GNU C's cccp.c. */ | |
344 | int safe_read(int desc, char *ptr, int len) | |
345 | { | |
346 | int n_chars; | |
347 | ||
348 | if (len <= 0) | |
349 | return len; | |
350 | ||
351 | #ifdef EINTR | |
352 | do { | |
353 | n_chars = read(desc, ptr, len); | |
354 | } while (n_chars < 0 && errno == EINTR); | |
355 | #else | |
356 | n_chars = read(desc, ptr, len); | |
357 | #endif | |
358 | ||
359 | return n_chars; | |
360 | } | |
361 | ||
362 | ||
363 | /* copy a file - this is used in conjunction with the --temp-dir option */ | |
364 | int copy_file(char *source, char *dest, mode_t mode) | |
365 | { | |
366 | int ifd; | |
367 | int ofd; | |
368 | char buf[1024 * 8]; | |
369 | int len; /* Number of bytes read into `buf'. */ | |
370 | ||
371 | ifd = open(source, O_RDONLY); | |
372 | if (ifd == -1) { | |
9486289c | 373 | rprintf(FERROR,"open %s: %s\n", |
950ab32d AT |
374 | source,strerror(errno)); |
375 | return -1; | |
376 | } | |
377 | ||
31e12522 | 378 | if (do_unlink(dest) && errno != ENOENT) { |
9486289c | 379 | rprintf(FERROR,"unlink %s: %s\n", |
950ab32d AT |
380 | dest,strerror(errno)); |
381 | return -1; | |
382 | } | |
383 | ||
31e12522 | 384 | ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); |
950ab32d | 385 | if (ofd < 0) { |
9486289c | 386 | rprintf(FERROR,"open %s: %s\n", |
950ab32d AT |
387 | dest,strerror(errno)); |
388 | close(ifd); | |
389 | return -1; | |
390 | } | |
391 | ||
392 | while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) { | |
393 | if (full_write(ofd, buf, len) < 0) { | |
9486289c | 394 | rprintf(FERROR,"write %s: %s\n", |
950ab32d AT |
395 | dest,strerror(errno)); |
396 | close(ifd); | |
397 | close(ofd); | |
398 | return -1; | |
399 | } | |
400 | } | |
401 | ||
402 | close(ifd); | |
403 | close(ofd); | |
404 | ||
405 | if (len < 0) { | |
9486289c | 406 | rprintf(FERROR,"read %s: %s\n", |
950ab32d AT |
407 | source,strerror(errno)); |
408 | return -1; | |
409 | } | |
410 | ||
411 | return 0; | |
412 | } | |
feaa89c4 AT |
413 | |
414 | /* sleep for a while via select */ | |
415 | void u_sleep(int usec) | |
416 | { | |
417 | struct timeval tv; | |
418 | ||
419 | tv.tv_sec = 0; | |
420 | tv.tv_usec = usec; | |
421 | select(0, NULL, NULL, NULL, &tv); | |
422 | } | |
3ba62a83 AT |
423 | |
424 | ||
425 | static pid_t all_pids[10]; | |
426 | static int num_pids; | |
427 | ||
428 | /* fork and record the pid of the child */ | |
429 | pid_t do_fork(void) | |
430 | { | |
431 | pid_t newpid = fork(); | |
432 | ||
433 | if (newpid) { | |
434 | all_pids[num_pids++] = newpid; | |
435 | } | |
436 | return newpid; | |
437 | } | |
438 | ||
439 | /* kill all children */ | |
440 | void kill_all(int sig) | |
441 | { | |
442 | int i; | |
443 | for (i=0;i<num_pids;i++) { | |
444 | if (all_pids[i] != getpid()) | |
445 | kill(all_pids[i], sig); | |
446 | } | |
447 | } | |
9486289c | 448 | |
7a6421fa AT |
449 | /* like strncpy but does not 0 fill the buffer and always null |
450 | terminates (thus it can use maxlen+1 space in d) */ | |
451 | void strlcpy(char *d, char *s, int maxlen) | |
452 | { | |
453 | int len = strlen(s); | |
454 | if (len > maxlen) len = maxlen; | |
455 | memcpy(d, s, len); | |
456 | d[len] = 0; | |
457 | } | |
8ef4ffd6 AT |
458 | |
459 | /* turn a user name into a uid */ | |
460 | int name_to_uid(char *name, uid_t *uid) | |
461 | { | |
462 | struct passwd *pass; | |
463 | if (!name || !*name) return 0; | |
464 | pass = getpwnam(name); | |
465 | if (pass) { | |
466 | *uid = pass->pw_uid; | |
467 | return 1; | |
468 | } | |
469 | return 0; | |
470 | } | |
471 | ||
472 | /* turn a group name into a gid */ | |
473 | int name_to_gid(char *name, gid_t *gid) | |
474 | { | |
475 | struct group *grp; | |
476 | if (!name || !*name) return 0; | |
477 | grp = getgrnam(name); | |
478 | if (grp) { | |
479 | *gid = grp->gr_gid; | |
480 | return 1; | |
481 | } | |
482 | return 0; | |
483 | } | |
484 | ||
ff8b29b8 | 485 | |
0c515f17 AT |
486 | /**************************************************************************** |
487 | check if a process exists. | |
488 | ****************************************************************************/ | |
489 | int process_exists(int pid) | |
490 | { | |
491 | return(kill(pid,0) == 0 || errno != ESRCH); | |
492 | } | |
493 | ||
31593dd6 AT |
494 | /* lock a byte range in a open file */ |
495 | int lock_range(int fd, int offset, int len) | |
0c515f17 | 496 | { |
31593dd6 | 497 | struct flock lock; |
0c515f17 | 498 | |
31593dd6 AT |
499 | lock.l_type = F_WRLCK; |
500 | lock.l_whence = SEEK_SET; | |
501 | lock.l_start = offset; | |
502 | lock.l_len = len; | |
503 | lock.l_pid = 0; | |
504 | ||
505 | return fcntl(fd,F_SETLK,&lock) == 0; | |
0c515f17 | 506 | } |
874895d5 AT |
507 | |
508 | ||
509 | void glob_expand(char **argv, int *argc, int maxargs) | |
510 | { | |
511 | #ifndef HAVE_GLOB | |
512 | (*argc)++; | |
513 | return; | |
514 | #else | |
515 | glob_t globbuf; | |
516 | int i; | |
517 | ||
874895d5 AT |
518 | memset(&globbuf, 0, sizeof(globbuf)); |
519 | glob(argv[*argc], 0, NULL, &globbuf); | |
520 | if (globbuf.gl_pathc == 0) { | |
521 | (*argc)++; | |
522 | globfree(&globbuf); | |
523 | return; | |
524 | } | |
525 | for (i=0; i<(maxargs - (*argc)) && i<globbuf.gl_pathc;i++) { | |
526 | if (i == 0) free(argv[*argc]); | |
527 | argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]); | |
528 | if (!argv[(*argc) + i]) out_of_memory("glob_expand"); | |
529 | } | |
530 | globfree(&globbuf); | |
531 | (*argc) += i; | |
532 | #endif | |
533 | } | |
5a96ee05 AT |
534 | |
535 | ||
536 | /******************************************************************* | |
537 | convert a string to lower case | |
538 | ********************************************************************/ | |
539 | void strlower(char *s) | |
540 | { | |
541 | while (*s) { | |
542 | if (isupper(*s)) *s = tolower(*s); | |
543 | s++; | |
544 | } | |
545 | } |