source: trunk/essentials/app-arch/tar/src/system.c

Last change on this file was 3342, checked in by bird, 18 years ago

tar 1.16.1

File size: 18.4 KB
Line 
1/* System-dependent calls for tar.
2
3 Copyright (C) 2003, 2004, 2005, 2006 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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#include <system.h>
20#include <getline.h>
21#include <setenv.h>
22
23#include "common.h"
24#include <rmt.h>
25#include <signal.h>
26
27#if MSDOS
28
29bool
30sys_get_archive_stat (void)
31{
32 return 0;
33}
34
35bool
36sys_file_is_archive (struct tar_stat_info *p)
37{
38 return false;
39}
40
41void
42sys_save_archive_dev_ino (void)
43{
44}
45
46void
47sys_detect_dev_null_output (void)
48{
49 static char const dev_null[] = "nul";
50
51 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
52 || (! _isrmt (archive)));
53}
54
55void
56sys_drain_input_pipe (void)
57{
58}
59
60void
61sys_wait_for_child (pid_t child_pid)
62{
63}
64
65void
66sys_spawn_shell (void)
67{
68 spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
69}
70
71/* stat() in djgpp's C library gives a constant number of 42 as the
72 uid and gid of a file. So, comparing an FTP'ed archive just after
73 unpack would fail on MSDOS. */
74
75bool
76sys_compare_uid (struct stat *a, struct stat *b)
77{
78 return true;
79}
80
81bool
82sys_compare_gid (struct stat *a, struct stat *b)
83{
84 return true;
85}
86
87void
88sys_compare_links (struct stat *link_data, struct stat *stat_data)
89{
90 return true;
91}
92
93int
94sys_truncate (int fd)
95{
96 return write (fd, "", 0);
97}
98
99size_t
100sys_write_archive_buffer (void)
101{
102 return full_write (archive, record_start->buffer, record_size);
103}
104
105/* Set ARCHIVE for writing, then compressing an archive. */
106void
107sys_child_open_for_compress (void)
108{
109 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
110}
111
112/* Set ARCHIVE for uncompressing, then reading an archive. */
113void
114sys_child_open_for_uncompress (void)
115{
116 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
117}
118
119#else
120
121extern union block *record_start; /* FIXME */
122
123static struct stat archive_stat; /* stat block for archive file */
124
125bool
126sys_get_archive_stat (void)
127{
128 return fstat (archive, &archive_stat) == 0;
129}
130
131bool
132sys_file_is_archive (struct tar_stat_info *p)
133{
134 return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
135}
136
137/* Save archive file inode and device numbers */
138void
139sys_save_archive_dev_ino (void)
140{
141 if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
142 {
143 ar_dev = archive_stat.st_dev;
144 ar_ino = archive_stat.st_ino;
145 }
146 else
147 ar_dev = 0;
148}
149
150/* Detect if outputting to "/dev/null". */
151void
152sys_detect_dev_null_output (void)
153{
154 static char const dev_null[] = "/dev/null";
155 struct stat dev_null_stat;
156
157 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
158 || (! _isrmt (archive)
159 && S_ISCHR (archive_stat.st_mode)
160 && stat (dev_null, &dev_null_stat) == 0
161 && archive_stat.st_dev == dev_null_stat.st_dev
162 && archive_stat.st_ino == dev_null_stat.st_ino));
163}
164
165/* Manage to fully drain a pipe we might be reading, so to not break it on
166 the producer after the EOF block. FIXME: one of these days, GNU tar
167 might become clever enough to just stop working, once there is no more
168 work to do, we might have to revise this area in such time. */
169
170void
171sys_drain_input_pipe (void)
172{
173 size_t r;
174
175 if (access_mode == ACCESS_READ
176 && ! _isrmt (archive)
177 && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
178 while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
179 && r != SAFE_READ_ERROR)
180 continue;
181}
182
183void
184sys_wait_for_child (pid_t child_pid)
185{
186 if (child_pid)
187 {
188 int wait_status;
189
190 while (waitpid (child_pid, &wait_status, 0) == -1)
191 if (errno != EINTR)
192 {
193 waitpid_error (use_compress_program_option);
194 break;
195 }
196
197 if (WIFSIGNALED (wait_status))
198 ERROR ((0, 0, _("Child died with signal %d"),
199 WTERMSIG (wait_status)));
200 else if (WEXITSTATUS (wait_status) != 0)
201 ERROR ((0, 0, _("Child returned status %d"),
202 WEXITSTATUS (wait_status)));
203 }
204}
205
206void
207sys_spawn_shell (void)
208{
209 pid_t child;
210 const char *shell = getenv ("SHELL");
211 if (! shell)
212 shell = "/bin/sh";
213 child = xfork ();
214 if (child == 0)
215 {
216 execlp (shell, "-sh", "-i", (char *) 0);
217 exec_fatal (shell);
218 }
219 else
220 {
221 int wait_status;
222 while (waitpid (child, &wait_status, 0) == -1)
223 if (errno != EINTR)
224 {
225 waitpid_error (shell);
226 break;
227 }
228 }
229}
230
231bool
232sys_compare_uid (struct stat *a, struct stat *b)
233{
234 return a->st_uid == b->st_uid;
235}
236
237bool
238sys_compare_gid (struct stat *a, struct stat *b)
239{
240 return a->st_gid == b->st_gid;
241}
242
243bool
244sys_compare_links (struct stat *link_data, struct stat *stat_data)
245{
246 return stat_data->st_dev == link_data->st_dev
247 && stat_data->st_ino == link_data->st_ino;
248}
249
250int
251sys_truncate (int fd)
252{
253 off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
254 return pos < 0 ? -1 : ftruncate (fd, pos);
255}
256
257/* Return nonzero if NAME is the name of a regular file, or if the file
258 does not exist (so it would be created as a regular file). */
259static int
260is_regular_file (const char *name)
261{
262 struct stat stbuf;
263
264 if (stat (name, &stbuf) == 0)
265 return S_ISREG (stbuf.st_mode);
266 else
267 return errno == ENOENT;
268}
269
270size_t
271sys_write_archive_buffer (void)
272{
273 return rmtwrite (archive, record_start->buffer, record_size);
274}
275
276#define PREAD 0 /* read file descriptor from pipe() */
277#define PWRITE 1 /* write file descriptor from pipe() */
278
279/* Duplicate file descriptor FROM into becoming INTO.
280 INTO is closed first and has to be the next available slot. */
281static void
282xdup2 (int from, int into)
283{
284 if (from != into)
285 {
286 int status = close (into);
287
288 if (status != 0 && errno != EBADF)
289 {
290 int e = errno;
291 FATAL_ERROR ((0, e, _("Cannot close")));
292 }
293 status = dup (from);
294 if (status != into)
295 {
296 if (status < 0)
297 {
298 int e = errno;
299 FATAL_ERROR ((0, e, _("Cannot dup")));
300 }
301 abort ();
302 }
303 xclose (from);
304 }
305}
306
307/* Set ARCHIVE for writing, then compressing an archive. */
308pid_t
309sys_child_open_for_compress (void)
310{
311 int parent_pipe[2];
312 int child_pipe[2];
313 pid_t grandchild_pid;
314 pid_t child_pid;
315 int wait_status;
316
317 xpipe (parent_pipe);
318 child_pid = xfork ();
319
320 if (child_pid > 0)
321 {
322 /* The parent tar is still here! Just clean up. */
323
324 archive = parent_pipe[PWRITE];
325 xclose (parent_pipe[PREAD]);
326 return child_pid;
327 }
328
329 /* The new born child tar is here! */
330
331 program_name = _("tar (child)");
332
333 xdup2 (parent_pipe[PREAD], STDIN_FILENO);
334 xclose (parent_pipe[PWRITE]);
335
336 /* Check if we need a grandchild tar. This happens only if either:
337 a) the file is to be accessed by rmt: compressor doesn't know how;
338 b) the file is not a plain file. */
339
340 if (!_remdev (archive_name_array[0])
341 && is_regular_file (archive_name_array[0]))
342 {
343 if (backup_option)
344 maybe_backup_file (archive_name_array[0], 1);
345
346 /* We don't need a grandchild tar. Open the archive and launch the
347 compressor. */
348 if (strcmp (archive_name_array[0], "-"))
349 {
350 archive = creat (archive_name_array[0], MODE_RW);
351 if (archive < 0)
352 {
353 int saved_errno = errno;
354
355 if (backup_option)
356 undo_last_backup ();
357 errno = saved_errno;
358 open_fatal (archive_name_array[0]);
359 }
360 xdup2 (archive, STDOUT_FILENO);
361 }
362 execlp (use_compress_program_option, use_compress_program_option, NULL);
363 exec_fatal (use_compress_program_option);
364 }
365
366 /* We do need a grandchild tar. */
367
368 xpipe (child_pipe);
369 grandchild_pid = xfork ();
370
371 if (grandchild_pid == 0)
372 {
373 /* The newborn grandchild tar is here! Launch the compressor. */
374
375 program_name = _("tar (grandchild)");
376
377 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
378 xclose (child_pipe[PREAD]);
379 execlp (use_compress_program_option, use_compress_program_option,
380 (char *) 0);
381 exec_fatal (use_compress_program_option);
382 }
383
384 /* The child tar is still here! */
385
386 /* Prepare for reblocking the data from the compressor into the archive. */
387
388 xdup2 (child_pipe[PREAD], STDIN_FILENO);
389 xclose (child_pipe[PWRITE]);
390
391 if (strcmp (archive_name_array[0], "-") == 0)
392 archive = STDOUT_FILENO;
393 else
394 {
395 archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
396 if (archive < 0)
397 open_fatal (archive_name_array[0]);
398 }
399
400 /* Let's read out of the stdin pipe and write an archive. */
401
402 while (1)
403 {
404 size_t status = 0;
405 char *cursor;
406 size_t length;
407
408 /* Assemble a record. */
409
410 for (length = 0, cursor = record_start->buffer;
411 length < record_size;
412 length += status, cursor += status)
413 {
414 size_t size = record_size - length;
415
416 status = safe_read (STDIN_FILENO, cursor, size);
417 if (status == SAFE_READ_ERROR)
418 read_fatal (use_compress_program_option);
419 if (status == 0)
420 break;
421 }
422
423 /* Copy the record. */
424
425 if (status == 0)
426 {
427 /* We hit the end of the file. Write last record at
428 full length, as the only role of the grandchild is
429 doing proper reblocking. */
430
431 if (length > 0)
432 {
433 memset (record_start->buffer + length, 0, record_size - length);
434 status = sys_write_archive_buffer ();
435 if (status != record_size)
436 archive_write_error (status);
437 }
438
439 /* There is nothing else to read, break out. */
440 break;
441 }
442
443 status = sys_write_archive_buffer ();
444 if (status != record_size)
445 archive_write_error (status);
446 }
447
448 /* Propagate any failure of the grandchild back to the parent. */
449
450 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
451 if (errno != EINTR)
452 {
453 waitpid_error (use_compress_program_option);
454 break;
455 }
456
457 if (WIFSIGNALED (wait_status))
458 {
459 kill (child_pid, WTERMSIG (wait_status));
460 exit_status = TAREXIT_FAILURE;
461 }
462 else if (WEXITSTATUS (wait_status) != 0)
463 exit_status = WEXITSTATUS (wait_status);
464
465 exit (exit_status);
466}
467
468/* Set ARCHIVE for uncompressing, then reading an archive. */
469pid_t
470sys_child_open_for_uncompress (void)
471{
472 int parent_pipe[2];
473 int child_pipe[2];
474 pid_t grandchild_pid;
475 pid_t child_pid;
476 int wait_status;
477
478 xpipe (parent_pipe);
479 child_pid = xfork ();
480
481 if (child_pid > 0)
482 {
483 /* The parent tar is still here! Just clean up. */
484
485 archive = parent_pipe[PREAD];
486 xclose (parent_pipe[PWRITE]);
487 return child_pid;
488 }
489
490 /* The newborn child tar is here! */
491
492 program_name = _("tar (child)");
493
494 xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
495 xclose (parent_pipe[PREAD]);
496
497 /* Check if we need a grandchild tar. This happens only if either:
498 a) we're reading stdin: to force unblocking;
499 b) the file is to be accessed by rmt: compressor doesn't know how;
500 c) the file is not a plain file. */
501
502 if (strcmp (archive_name_array[0], "-") != 0
503 && !_remdev (archive_name_array[0])
504 && is_regular_file (archive_name_array[0]))
505 {
506 /* We don't need a grandchild tar. Open the archive and lauch the
507 uncompressor. */
508
509 archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
510 if (archive < 0)
511 open_fatal (archive_name_array[0]);
512 xdup2 (archive, STDIN_FILENO);
513 execlp (use_compress_program_option, use_compress_program_option,
514 "-d", (char *) 0);
515 exec_fatal (use_compress_program_option);
516 }
517
518 /* We do need a grandchild tar. */
519
520 xpipe (child_pipe);
521 grandchild_pid = xfork ();
522
523 if (grandchild_pid == 0)
524 {
525 /* The newborn grandchild tar is here! Launch the uncompressor. */
526
527 program_name = _("tar (grandchild)");
528
529 xdup2 (child_pipe[PREAD], STDIN_FILENO);
530 xclose (child_pipe[PWRITE]);
531 execlp (use_compress_program_option, use_compress_program_option,
532 "-d", (char *) 0);
533 exec_fatal (use_compress_program_option);
534 }
535
536 /* The child tar is still here! */
537
538 /* Prepare for unblocking the data from the archive into the
539 uncompressor. */
540
541 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
542 xclose (child_pipe[PREAD]);
543
544 if (strcmp (archive_name_array[0], "-") == 0)
545 archive = STDIN_FILENO;
546 else
547 archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
548 MODE_RW, rsh_command_option);
549 if (archive < 0)
550 open_fatal (archive_name_array[0]);
551
552 /* Let's read the archive and pipe it into stdout. */
553
554 while (1)
555 {
556 char *cursor;
557 size_t maximum;
558 size_t count;
559 size_t status;
560
561 clear_read_error_count ();
562
563 error_loop:
564 status = rmtread (archive, record_start->buffer, record_size);
565 if (status == SAFE_READ_ERROR)
566 {
567 archive_read_error ();
568 goto error_loop;
569 }
570 if (status == 0)
571 break;
572 cursor = record_start->buffer;
573 maximum = status;
574 while (maximum)
575 {
576 count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
577 if (full_write (STDOUT_FILENO, cursor, count) != count)
578 write_error (use_compress_program_option);
579 cursor += count;
580 maximum -= count;
581 }
582 }
583
584 xclose (STDOUT_FILENO);
585
586 /* Propagate any failure of the grandchild back to the parent. */
587
588 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
589 if (errno != EINTR)
590 {
591 waitpid_error (use_compress_program_option);
592 break;
593 }
594
595 if (WIFSIGNALED (wait_status))
596 {
597 kill (child_pid, WTERMSIG (wait_status));
598 exit_status = TAREXIT_FAILURE;
599 }
600 else if (WEXITSTATUS (wait_status) != 0)
601 exit_status = WEXITSTATUS (wait_status);
602
603 exit (exit_status);
604}
605
606
607
608
609static void
610dec_to_env (char *envar, uintmax_t num)
611{
612 char buf[UINTMAX_STRSIZE_BOUND];
613 char *numstr;
614
615 numstr = STRINGIFY_BIGINT (num, buf);
616 if (setenv (envar, numstr, 1) != 0)
617 xalloc_die ();
618}
619
620static void
621time_to_env (char *envar, struct timespec t)
622{
623 char buf[TIMESPEC_STRSIZE_BOUND];
624 if (setenv (envar, code_timespec (t, buf), 1) != 0)
625 xalloc_die ();
626}
627
628static void
629oct_to_env (char *envar, unsigned long num)
630{
631 char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
632
633 snprintf (buf, sizeof buf, "0%lo", num);
634 if (setenv (envar, buf, 1) != 0)
635 xalloc_die ();
636}
637
638static void
639str_to_env (char *envar, char const *str)
640{
641 if (str)
642 {
643 if (setenv (envar, str, 1) != 0)
644 xalloc_die ();
645 }
646 else
647 unsetenv (envar);
648}
649
650static void
651chr_to_env (char *envar, char c)
652{
653 char buf[2];
654 buf[0] = c;
655 buf[1] = 0;
656 if (setenv (envar, buf, 1) != 0)
657 xalloc_die ();
658}
659
660static void
661stat_to_env (char *name, char type, struct tar_stat_info *st)
662{
663 str_to_env ("TAR_VERSION", PACKAGE_VERSION);
664 chr_to_env ("TAR_FILETYPE", type);
665 oct_to_env ("TAR_MODE", st->stat.st_mode);
666 str_to_env ("TAR_FILENAME", name);
667 str_to_env ("TAR_REALNAME", st->file_name);
668 str_to_env ("TAR_UNAME", st->uname);
669 str_to_env ("TAR_GNAME", st->gname);
670 time_to_env ("TAR_ATIME", st->atime);
671 time_to_env ("TAR_MTIME", st->mtime);
672 time_to_env ("TAR_CTIME", st->ctime);
673 dec_to_env ("TAR_SIZE", st->stat.st_size);
674 dec_to_env ("TAR_UID", st->stat.st_uid);
675 dec_to_env ("TAR_GID", st->stat.st_gid);
676
677 switch (type)
678 {
679 case 'b':
680 case 'c':
681 dec_to_env ("TAR_MINOR", minor (st->stat.st_rdev));
682 dec_to_env ("TAR_MAJOR", major (st->stat.st_rdev));
683 unsetenv ("TAR_LINKNAME");
684 break;
685
686 case 'l':
687 case 'h':
688 unsetenv ("TAR_MINOR");
689 unsetenv ("TAR_MAJOR");
690 str_to_env ("TAR_LINKNAME", st->link_name);
691 break;
692
693 default:
694 unsetenv ("TAR_MINOR");
695 unsetenv ("TAR_MAJOR");
696 unsetenv ("TAR_LINKNAME");
697 break;
698 }
699}
700
701static pid_t pid;
702static RETSIGTYPE (*pipe_handler) (int sig);
703
704int
705sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
706{
707 int p[2];
708 char *argv[4];
709
710 xpipe (p);
711 pipe_handler = signal (SIGPIPE, SIG_IGN);
712 pid = xfork ();
713
714 if (pid != 0)
715 {
716 xclose (p[PREAD]);
717 return p[PWRITE];
718 }
719
720 /* Child */
721 xdup2 (p[PREAD], STDIN_FILENO);
722 xclose (p[PWRITE]);
723
724 stat_to_env (file_name, typechar, st);
725
726 argv[0] = "/bin/sh";
727 argv[1] = "-c";
728 argv[2] = to_command_option;
729 argv[3] = NULL;
730
731 execv ("/bin/sh", argv);
732
733 exec_fatal (file_name);
734}
735
736void
737sys_wait_command (void)
738{
739 int status;
740
741 if (pid < 0)
742 return;
743
744 signal (SIGPIPE, pipe_handler);
745 while (waitpid (pid, &status, 0) == -1)
746 if (errno != EINTR)
747 {
748 pid = -1;
749 waitpid_error (to_command_option);
750 return;
751 }
752
753 if (WIFEXITED (status))
754 {
755 if (!ignore_command_error_option && WEXITSTATUS (status))
756 ERROR ((0, 0, _("%lu: Child returned status %d"),
757 (unsigned long) pid, WEXITSTATUS (status)));
758 }
759 else if (WIFSIGNALED (status))
760 {
761 WARN ((0, 0, _("%lu: Child terminated on signal %d"),
762 (unsigned long) pid, WTERMSIG (status)));
763 }
764 else
765 ERROR ((0, 0, _("%lu: Child terminated on unknown reason"),
766 (unsigned long) pid));
767
768 pid = -1;
769}
770
771int
772sys_exec_info_script (const char **archive_name, int volume_number)
773{
774 pid_t pid;
775 char *argv[4];
776 char uintbuf[UINTMAX_STRSIZE_BOUND];
777 int p[2];
778
779 xpipe (p);
780 pipe_handler = signal (SIGPIPE, SIG_IGN);
781
782 pid = xfork ();
783
784 if (pid != 0)
785 {
786 /* Master */
787
788 int rc;
789 int status;
790 char *buf;
791 size_t size = 0;
792 FILE *fp;
793
794 xclose (p[PWRITE]);
795 fp = fdopen (p[PREAD], "r");
796 rc = getline (&buf, &size, fp);
797 fclose (fp);
798
799 if (rc > 0 && buf[rc-1] == '\n')
800 buf[--rc] = 0;
801
802 while (waitpid (pid, &status, 0) == -1)
803 if (errno != EINTR)
804 {
805 waitpid_error (info_script_option);
806 return -1;
807 }
808
809 if (WIFEXITED (status))
810 {
811 if (WEXITSTATUS (status) == 0 && rc > 0)
812 *archive_name = buf;
813 else
814 free (buf);
815 return WEXITSTATUS (status);
816 }
817
818 free (buf);
819 return -1;
820 }
821
822 /* Child */
823 setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
824 setenv ("TAR_ARCHIVE", *archive_name, 1);
825 setenv ("TAR_VOLUME", STRINGIFY_BIGINT (volume_number, uintbuf), 1);
826 setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
827 setenv ("TAR_FORMAT",
828 archive_format_string (current_format == DEFAULT_FORMAT ?
829 archive_format : current_format), 1);
830
831 xclose (p[PREAD]);
832 xdup2 (p[PWRITE], 3);
833
834 argv[0] = "/bin/sh";
835 argv[1] = "-c";
836 argv[2] = (char*) info_script_option;
837 argv[3] = NULL;
838
839 execv (argv[0], argv);
840
841 exec_fatal (info_script_option);
842}
843
844
845#endif /* not MSDOS */
Note: See TracBrowser for help on using the repository browser.