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