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