]> Dogcows Code - chaz/tar/blob - src/system.c
(sys_exec_info_script): Store the inter-communication fd in the environment variable...
[chaz/tar] / src / system.c
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
29 bool
30 sys_get_archive_stat (void)
31 {
32 return 0;
33 }
34
35 bool
36 sys_file_is_archive (struct tar_stat_info *p)
37 {
38 return false;
39 }
40
41 void
42 sys_save_archive_dev_ino (void)
43 {
44 }
45
46 void
47 sys_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
55 void
56 sys_drain_input_pipe (void)
57 {
58 }
59
60 void
61 sys_wait_for_child (pid_t child_pid)
62 {
63 }
64
65 void
66 sys_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
75 bool
76 sys_compare_uid (struct stat *a, struct stat *b)
77 {
78 return true;
79 }
80
81 bool
82 sys_compare_gid (struct stat *a, struct stat *b)
83 {
84 return true;
85 }
86
87 void
88 sys_compare_links (struct stat *link_data, struct stat *stat_data)
89 {
90 return true;
91 }
92
93 int
94 sys_truncate (int fd)
95 {
96 return write (fd, "", 0);
97 }
98
99 size_t
100 sys_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. */
106 void
107 sys_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. */
113 void
114 sys_child_open_for_uncompress (void)
115 {
116 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
117 }
118
119 #else
120
121 extern union block *record_start; /* FIXME */
122
123 static struct stat archive_stat; /* stat block for archive file */
124
125 bool
126 sys_get_archive_stat (void)
127 {
128 return fstat (archive, &archive_stat) == 0;
129 }
130
131 bool
132 sys_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 */
138 void
139 sys_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". */
151 void
152 sys_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
170 void
171 sys_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
183 void
184 sys_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
206 void
207 sys_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
231 bool
232 sys_compare_uid (struct stat *a, struct stat *b)
233 {
234 return a->st_uid == b->st_uid;
235 }
236
237 bool
238 sys_compare_gid (struct stat *a, struct stat *b)
239 {
240 return a->st_gid == b->st_gid;
241 }
242
243 bool
244 sys_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
250 int
251 sys_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). */
259 static int
260 is_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
270 size_t
271 sys_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. */
281 static void
282 xdup2 (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. */
308 pid_t
309 sys_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. */
469 pid_t
470 sys_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 \f
607
608 static void
609 dec_to_env (char *envar, uintmax_t num)
610 {
611 char buf[UINTMAX_STRSIZE_BOUND];
612 char *numstr;
613
614 numstr = STRINGIFY_BIGINT (num, buf);
615 if (setenv (envar, numstr, 1) != 0)
616 xalloc_die ();
617 }
618
619 static void
620 time_to_env (char *envar, struct timespec t)
621 {
622 char buf[TIMESPEC_STRSIZE_BOUND];
623 if (setenv (envar, code_timespec (t, buf), 1) != 0)
624 xalloc_die ();
625 }
626
627 static void
628 oct_to_env (char *envar, unsigned long num)
629 {
630 char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
631
632 snprintf (buf, sizeof buf, "0%lo", num);
633 if (setenv (envar, buf, 1) != 0)
634 xalloc_die ();
635 }
636
637 static void
638 str_to_env (char *envar, char const *str)
639 {
640 if (str)
641 {
642 if (setenv (envar, str, 1) != 0)
643 xalloc_die ();
644 }
645 else
646 unsetenv (envar);
647 }
648
649 static void
650 chr_to_env (char *envar, char c)
651 {
652 char buf[2];
653 buf[0] = c;
654 buf[1] = 0;
655 if (setenv (envar, buf, 1) != 0)
656 xalloc_die ();
657 }
658
659 static void
660 stat_to_env (char *name, char type, struct tar_stat_info *st)
661 {
662 str_to_env ("TAR_VERSION", PACKAGE_VERSION);
663 chr_to_env ("TAR_FILETYPE", type);
664 oct_to_env ("TAR_MODE", st->stat.st_mode);
665 str_to_env ("TAR_FILENAME", name);
666 str_to_env ("TAR_REALNAME", st->file_name);
667 str_to_env ("TAR_UNAME", st->uname);
668 str_to_env ("TAR_GNAME", st->gname);
669 time_to_env ("TAR_ATIME", st->atime);
670 time_to_env ("TAR_MTIME", st->mtime);
671 time_to_env ("TAR_CTIME", st->ctime);
672 dec_to_env ("TAR_SIZE", st->stat.st_size);
673 dec_to_env ("TAR_UID", st->stat.st_uid);
674 dec_to_env ("TAR_GID", st->stat.st_gid);
675
676 switch (type)
677 {
678 case 'b':
679 case 'c':
680 dec_to_env ("TAR_MINOR", minor (st->stat.st_rdev));
681 dec_to_env ("TAR_MAJOR", major (st->stat.st_rdev));
682 unsetenv ("TAR_LINKNAME");
683 break;
684
685 case 'l':
686 case 'h':
687 unsetenv ("TAR_MINOR");
688 unsetenv ("TAR_MAJOR");
689 str_to_env ("TAR_LINKNAME", st->link_name);
690 break;
691
692 default:
693 unsetenv ("TAR_MINOR");
694 unsetenv ("TAR_MAJOR");
695 unsetenv ("TAR_LINKNAME");
696 break;
697 }
698 }
699
700 static pid_t pid;
701 static RETSIGTYPE (*pipe_handler) (int sig);
702
703 int
704 sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
705 {
706 int p[2];
707 char *argv[4];
708
709 xpipe (p);
710 pipe_handler = signal (SIGPIPE, SIG_IGN);
711 pid = xfork ();
712
713 if (pid != 0)
714 {
715 xclose (p[PREAD]);
716 return p[PWRITE];
717 }
718
719 /* Child */
720 xdup2 (p[PREAD], STDIN_FILENO);
721 xclose (p[PWRITE]);
722
723 stat_to_env (file_name, typechar, st);
724
725 argv[0] = "/bin/sh";
726 argv[1] = "-c";
727 argv[2] = to_command_option;
728 argv[3] = NULL;
729
730 execv ("/bin/sh", argv);
731
732 exec_fatal (file_name);
733 }
734
735 void
736 sys_wait_command (void)
737 {
738 int status;
739
740 if (pid < 0)
741 return;
742
743 signal (SIGPIPE, pipe_handler);
744 while (waitpid (pid, &status, 0) == -1)
745 if (errno != EINTR)
746 {
747 pid = -1;
748 waitpid_error (to_command_option);
749 return;
750 }
751
752 if (WIFEXITED (status))
753 {
754 if (!ignore_command_error_option && WEXITSTATUS (status))
755 ERROR ((0, 0, _("%lu: Child returned status %d"),
756 (unsigned long) pid, WEXITSTATUS (status)));
757 }
758 else if (WIFSIGNALED (status))
759 {
760 WARN ((0, 0, _("%lu: Child terminated on signal %d"),
761 (unsigned long) pid, WTERMSIG (status)));
762 }
763 else
764 ERROR ((0, 0, _("%lu: Child terminated on unknown reason"),
765 (unsigned long) pid));
766
767 pid = -1;
768 }
769
770 int
771 sys_exec_info_script (const char **archive_name, int volume_number)
772 {
773 pid_t pid;
774 char *argv[4];
775 char uintbuf[UINTMAX_STRSIZE_BOUND];
776 int p[2];
777
778 xpipe (p);
779 pipe_handler = signal (SIGPIPE, SIG_IGN);
780
781 pid = xfork ();
782
783 if (pid != 0)
784 {
785 /* Master */
786
787 int rc;
788 int status;
789 char *buf;
790 size_t size = 0;
791 FILE *fp;
792
793 xclose (p[PWRITE]);
794 fp = fdopen (p[PREAD], "r");
795 rc = getline (&buf, &size, fp);
796 fclose (fp);
797
798 if (rc > 0 && buf[rc-1] == '\n')
799 buf[--rc] = 0;
800
801 while (waitpid (pid, &status, 0) == -1)
802 if (errno != EINTR)
803 {
804 waitpid_error (info_script_option);
805 return -1;
806 }
807
808 if (WIFEXITED (status))
809 {
810 if (WEXITSTATUS (status) == 0 && rc > 0)
811 *archive_name = buf;
812 else
813 free (buf);
814 return WEXITSTATUS (status);
815 }
816
817 free (buf);
818 return -1;
819 }
820
821 /* Child */
822 setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
823 setenv ("TAR_ARCHIVE", *archive_name, 1);
824 setenv ("TAR_VOLUME", STRINGIFY_BIGINT (volume_number, uintbuf), 1);
825 setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
826 setenv ("TAR_FORMAT",
827 archive_format_string (current_format == DEFAULT_FORMAT ?
828 archive_format : current_format), 1);
829 setenv ("TAR_FD", STRINGIFY_BIGINT (p[PWRITE], uintbuf), 1);
830
831 xclose (p[PREAD]);
832
833 argv[0] = "/bin/sh";
834 argv[1] = "-c";
835 argv[2] = (char*) info_script_option;
836 argv[3] = NULL;
837
838 execv (argv[0], argv);
839
840 exec_fatal (info_script_option);
841 }
842
843
844 #endif /* not MSDOS */
This page took 0.06888 seconds and 5 git commands to generate.