]> Dogcows Code - chaz/tar/blob - src/system.c
(sys_compare_uid,sys_compare_gid): New functions
[chaz/tar] / src / system.c
1 /* System-dependent calls for tar.
2
3 Copyright (C) 2003 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 #include "system.h"
20
21 #include "common.h"
22 #include "rmt.h"
23 #include <signal.h>
24
25 #if MSDOS
26
27 bool
28 sys_get_archive_stat ()
29 {
30 return 0;
31 }
32
33 bool
34 sys_file_is_archive (struct tar_stat_info *p)
35 {
36 return false;
37 }
38
39 void
40 sys_save_archive_dev_ino ()
41 {
42 }
43
44 void
45 sys_detect_dev_null_output ()
46 {
47 static char const dev_null[] = "nul";
48
49 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
50 || (! _isrmt (archive)));
51 }
52
53 void
54 sys_drain_input_pipe ()
55 {
56 }
57
58 void
59 sys_wait_for_child (pid_t child_pid)
60 {
61 }
62
63 void
64 sys_spawn_shell ()
65 {
66 spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
67 }
68
69 /* stat() in djgpp's C library gives a constant number of 42 as the
70 uid and gid of a file. So, comparing an FTP'ed archive just after
71 unpack would fail on MSDOS. */
72
73 bool
74 sys_compare_uid (struct stat *a, struct stat *b)
75 {
76 return true;
77 }
78
79 bool
80 sys_compare_gid (struct stat *a, struct stat *b)
81 {
82 return true;
83 }
84
85 void
86 sys_compare_links (struct stat *link_data, struct stat *stat_data)
87 {
88 return true;
89 }
90
91 int
92 sys_truncate (int fd)
93 {
94 return write (fd, "", 0);
95 }
96
97 void
98 sys_reset_uid_gid ()
99 {
100 }
101
102 ssize_t
103 sys_write_archive_buffer (void)
104 {
105 ssize_t status;
106 ssize_t written = 0;
107
108 while (0 <= (status = full_write (archive, record_start->buffer + written,
109 record_size - written)))
110 {
111 written += status;
112 if (written == record_size)
113 break;
114 }
115
116 return written ? written : status;
117 }
118
119 /* Set ARCHIVE for writing, then compressing an archive. */
120 void
121 sys_child_open_for_compress (void)
122 {
123 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
124 }
125
126 /* Set ARCHIVE for uncompressing, then reading an archive. */
127 void
128 sys_child_open_for_uncompress (void)
129 {
130 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
131 }
132
133 #else
134
135 extern union block *record_start; /* FIXME */
136
137 static struct stat archive_stat; /* stat block for archive file */
138
139 bool
140 sys_get_archive_stat ()
141 {
142 return fstat (archive, &archive_stat) == 0;
143 }
144
145 bool
146 sys_file_is_archive (struct tar_stat_info *p)
147 {
148 return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
149 }
150
151 /* Save archive file inode and device numbers */
152 void
153 sys_save_archive_dev_ino ()
154 {
155 if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
156 {
157 ar_dev = archive_stat.st_dev;
158 ar_ino = archive_stat.st_ino;
159 }
160 else
161 ar_dev = 0;
162 }
163
164 /* Detect if outputting to "/dev/null". */
165 void
166 sys_detect_dev_null_output ()
167 {
168 static char const dev_null[] = "/dev/null";
169 struct stat dev_null_stat;
170
171 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
172 || (! _isrmt (archive)
173 && S_ISCHR (archive_stat.st_mode)
174 && stat (dev_null, &dev_null_stat) == 0
175 && archive_stat.st_dev == dev_null_stat.st_dev
176 && archive_stat.st_ino == dev_null_stat.st_ino));
177 }
178
179 /* Manage to fully drain a pipe we might be reading, so to not break it on
180 the producer after the EOF block. FIXME: one of these days, GNU tar
181 might become clever enough to just stop working, once there is no more
182 work to do, we might have to revise this area in such time. */
183
184 void
185 sys_drain_input_pipe ()
186 {
187 if (access_mode == ACCESS_READ
188 && ! _isrmt (archive)
189 && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
190 while (rmtread (archive, record_start->buffer, record_size) > 0)
191 continue;
192 }
193
194 void
195 sys_wait_for_child (pid_t child_pid)
196 {
197 if (child_pid)
198 {
199 int wait_status;
200
201 while (waitpid (child_pid, &wait_status, 0) == -1)
202 if (errno != EINTR)
203 {
204 waitpid_error (use_compress_program_option);
205 break;
206 }
207
208 if (WIFSIGNALED (wait_status))
209 ERROR ((0, 0, _("Child died with signal %d"),
210 WTERMSIG (wait_status)));
211 else if (WEXITSTATUS (wait_status) != 0)
212 ERROR ((0, 0, _("Child returned status %d"),
213 WEXITSTATUS (wait_status)));
214 }
215 }
216
217 void
218 sys_spawn_shell ()
219 {
220 pid_t child;
221 const char *shell = getenv ("SHELL");
222 if (! shell)
223 shell = "/bin/sh";
224 child = xfork ();
225 if (child == 0)
226 {
227 execlp (shell, "-sh", "-i", (char *) 0);
228 exec_fatal (shell);
229 }
230 else
231 {
232 int wait_status;
233 while (waitpid (child, &wait_status, 0) == -1)
234 if (errno != EINTR)
235 {
236 waitpid_error (shell);
237 break;
238 }
239 }
240 }
241
242 bool
243 sys_compare_uid (struct stat *a, struct stat *b)
244 {
245 return a->st_uid == b->st_uid;
246 }
247
248 bool
249 sys_compare_gid (struct stat *a, struct stat *b)
250 {
251 return a->st_gid == b->st_gid;
252 }
253
254 bool
255 sys_compare_links (struct stat *link_data, struct stat *stat_data)
256 {
257 return stat_data->st_dev == link_data->st_dev
258 && stat_data->st_ino == link_data->st_ino;
259 }
260
261 int
262 sys_truncate (int fd)
263 {
264 off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
265 return pos < 0 ? -1 : ftruncate (fd, pos);
266 }
267
268 void
269 sys_reset_uid_gid ()
270 {
271 setuid (getuid ());
272 setgid (getgid ());
273 }
274
275 /* Return nonzero if NAME is the name of a regular file, or if the file
276 does not exist (so it would be created as a regular file). */
277 static int
278 is_regular_file (const char *name)
279 {
280 struct stat stbuf;
281
282 if (stat (name, &stbuf) == 0)
283 return S_ISREG (stbuf.st_mode);
284 else
285 return errno == ENOENT;
286 }
287
288 ssize_t
289 sys_write_archive_buffer (void)
290 {
291 ssize_t status;
292 ssize_t written = 0;
293
294 while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
295 record_size - written)))
296 {
297 written += status;
298 if (written == record_size
299 || _isrmt (archive)
300 || ! (S_ISFIFO (archive_stat.st_mode)
301 || S_ISSOCK (archive_stat.st_mode)))
302 break;
303 }
304
305 return written ? written : status;
306 }
307
308 #define PREAD 0 /* read file descriptor from pipe() */
309 #define PWRITE 1 /* write file descriptor from pipe() */
310
311 /* Duplicate file descriptor FROM into becoming INTO.
312 INTO is closed first and has to be the next available slot. */
313 static void
314 xdup2 (int from, int into)
315 {
316 if (from != into)
317 {
318 int status = close (into);
319
320 if (status != 0 && errno != EBADF)
321 {
322 int e = errno;
323 FATAL_ERROR ((0, e, _("Cannot close")));
324 }
325 status = dup (from);
326 if (status != into)
327 {
328 if (status < 0)
329 {
330 int e = errno;
331 FATAL_ERROR ((0, e, _("Cannot dup")));
332 }
333 abort ();
334 }
335 xclose (from);
336 }
337 }
338
339 /* Set ARCHIVE for writing, then compressing an archive. */
340 pid_t
341 sys_child_open_for_compress (void)
342 {
343 int parent_pipe[2];
344 int child_pipe[2];
345 pid_t grandchild_pid;
346 pid_t child_pid;
347 int wait_status;
348
349 xpipe (parent_pipe);
350 child_pid = xfork ();
351
352 if (child_pid > 0)
353 {
354 /* The parent tar is still here! Just clean up. */
355
356 archive = parent_pipe[PWRITE];
357 xclose (parent_pipe[PREAD]);
358 return child_pid;
359 }
360
361 /* The new born child tar is here! */
362
363 program_name = _("tar (child)");
364
365 xdup2 (parent_pipe[PREAD], STDIN_FILENO);
366 xclose (parent_pipe[PWRITE]);
367
368 /* Check if we need a grandchild tar. This happens only if either:
369 a) we are writing stdout: to force reblocking;
370 b) the file is to be accessed by rmt: compressor doesn't know how;
371 c) the file is not a plain file. */
372
373 if (strcmp (archive_name_array[0], "-") != 0
374 && !_remdev (archive_name_array[0])
375 && is_regular_file (archive_name_array[0]))
376 {
377 if (backup_option)
378 maybe_backup_file (archive_name_array[0], 1);
379
380 /* We don't need a grandchild tar. Open the archive and launch the
381 compressor. */
382
383 archive = creat (archive_name_array[0], MODE_RW);
384 if (archive < 0)
385 {
386 int saved_errno = errno;
387
388 if (backup_option)
389 undo_last_backup ();
390 errno = saved_errno;
391 open_fatal (archive_name_array[0]);
392 }
393 xdup2 (archive, STDOUT_FILENO);
394 execlp (use_compress_program_option, use_compress_program_option,
395 (char *) 0);
396 exec_fatal (use_compress_program_option);
397 }
398
399 /* We do need a grandchild tar. */
400
401 xpipe (child_pipe);
402 grandchild_pid = xfork ();
403
404 if (grandchild_pid == 0)
405 {
406 /* The newborn grandchild tar is here! Launch the compressor. */
407
408 program_name = _("tar (grandchild)");
409
410 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
411 xclose (child_pipe[PREAD]);
412 execlp (use_compress_program_option, use_compress_program_option,
413 (char *) 0);
414 exec_fatal (use_compress_program_option);
415 }
416
417 /* The child tar is still here! */
418
419 /* Prepare for reblocking the data from the compressor into the archive. */
420
421 xdup2 (child_pipe[PREAD], STDIN_FILENO);
422 xclose (child_pipe[PWRITE]);
423
424 if (strcmp (archive_name_array[0], "-") == 0)
425 archive = STDOUT_FILENO;
426 else
427 {
428 archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
429 if (archive < 0)
430 open_fatal (archive_name_array[0]);
431 }
432
433 /* Let's read out of the stdin pipe and write an archive. */
434
435 while (1)
436 {
437 ssize_t status = 0;
438 char *cursor;
439 size_t length;
440
441 /* Assemble a record. */
442
443 for (length = 0, cursor = record_start->buffer;
444 length < record_size;
445 length += status, cursor += status)
446 {
447 size_t size = record_size - length;
448
449 status = safe_read (STDIN_FILENO, cursor, size);
450 if (status <= 0)
451 break;
452 }
453
454 if (status < 0)
455 read_fatal (use_compress_program_option);
456
457 /* Copy the record. */
458
459 if (status == 0)
460 {
461 /* We hit the end of the file. Write last record at
462 full length, as the only role of the grandchild is
463 doing proper reblocking. */
464
465 if (length > 0)
466 {
467 memset (record_start->buffer + length, 0, record_size - length);
468 status = sys_write_archive_buffer ();
469 if (status != record_size)
470 archive_write_error (status);
471 }
472
473 /* There is nothing else to read, break out. */
474 break;
475 }
476
477 status = sys_write_archive_buffer ();
478 if (status != record_size)
479 archive_write_error (status);
480 }
481
482 /* Propagate any failure of the grandchild back to the parent. */
483
484 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
485 if (errno != EINTR)
486 {
487 waitpid_error (use_compress_program_option);
488 break;
489 }
490
491 if (WIFSIGNALED (wait_status))
492 {
493 kill (child_pid, WTERMSIG (wait_status));
494 exit_status = TAREXIT_FAILURE;
495 }
496 else if (WEXITSTATUS (wait_status) != 0)
497 exit_status = WEXITSTATUS (wait_status);
498
499 exit (exit_status);
500 }
501
502 /* Set ARCHIVE for uncompressing, then reading an archive. */
503 pid_t
504 sys_child_open_for_uncompress (void)
505 {
506 int parent_pipe[2];
507 int child_pipe[2];
508 pid_t grandchild_pid;
509 pid_t child_pid;
510 int wait_status;
511
512 xpipe (parent_pipe);
513 child_pid = xfork ();
514
515 if (child_pid > 0)
516 {
517 /* The parent tar is still here! Just clean up. */
518
519 read_full_records_option = 1;
520 archive = parent_pipe[PREAD];
521 xclose (parent_pipe[PWRITE]);
522 return child_pid;
523 }
524
525 /* The newborn child tar is here! */
526
527 program_name = _("tar (child)");
528
529 xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
530 xclose (parent_pipe[PREAD]);
531
532 /* Check if we need a grandchild tar. This happens only if either:
533 a) we're reading stdin: to force unblocking;
534 b) the file is to be accessed by rmt: compressor doesn't know how;
535 c) the file is not a plain file. */
536
537 if (strcmp (archive_name_array[0], "-") != 0
538 && !_remdev (archive_name_array[0])
539 && is_regular_file (archive_name_array[0]))
540 {
541 /* We don't need a grandchild tar. Open the archive and lauch the
542 uncompressor. */
543
544 archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
545 if (archive < 0)
546 open_fatal (archive_name_array[0]);
547 xdup2 (archive, STDIN_FILENO);
548 execlp (use_compress_program_option, use_compress_program_option,
549 "-d", (char *) 0);
550 exec_fatal (use_compress_program_option);
551 }
552
553 /* We do need a grandchild tar. */
554
555 xpipe (child_pipe);
556 grandchild_pid = xfork ();
557
558 if (grandchild_pid == 0)
559 {
560 /* The newborn grandchild tar is here! Launch the uncompressor. */
561
562 program_name = _("tar (grandchild)");
563
564 xdup2 (child_pipe[PREAD], STDIN_FILENO);
565 xclose (child_pipe[PWRITE]);
566 execlp (use_compress_program_option, use_compress_program_option,
567 "-d", (char *) 0);
568 exec_fatal (use_compress_program_option);
569 }
570
571 /* The child tar is still here! */
572
573 /* Prepare for unblocking the data from the archive into the
574 uncompressor. */
575
576 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
577 xclose (child_pipe[PREAD]);
578
579 if (strcmp (archive_name_array[0], "-") == 0)
580 archive = STDIN_FILENO;
581 else
582 archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
583 MODE_RW, rsh_command_option);
584 if (archive < 0)
585 open_fatal (archive_name_array[0]);
586
587 /* Let's read the archive and pipe it into stdout. */
588
589 while (1)
590 {
591 char *cursor;
592 size_t maximum;
593 size_t count;
594 ssize_t status;
595
596 clear_read_error_count ();
597
598 error_loop:
599 status = rmtread (archive, record_start->buffer, record_size);
600 if (status < 0)
601 {
602 archive_read_error ();
603 goto error_loop;
604 }
605 if (status == 0)
606 break;
607 cursor = record_start->buffer;
608 maximum = status;
609 while (maximum)
610 {
611 count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
612 if (full_write (STDOUT_FILENO, cursor, count) != count)
613 write_error (use_compress_program_option);
614 cursor += count;
615 maximum -= count;
616 }
617 }
618
619 xclose (STDOUT_FILENO);
620
621 /* Propagate any failure of the grandchild back to the parent. */
622
623 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
624 if (errno != EINTR)
625 {
626 waitpid_error (use_compress_program_option);
627 break;
628 }
629
630 if (WIFSIGNALED (wait_status))
631 {
632 kill (child_pid, WTERMSIG (wait_status));
633 exit_status = TAREXIT_FAILURE;
634 }
635 else if (WEXITSTATUS (wait_status) != 0)
636 exit_status = WEXITSTATUS (wait_status);
637
638 exit (exit_status);
639 }
640
641 #endif /* not MSDOS */
642
This page took 0.060348 seconds and 5 git commands to generate.