]> Dogcows Code - chaz/tar/blob - src/system.c
Carefully crafted invalid headers can cause buffer overrun.
[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) we are writing stdout: to force reblocking;
336 b) the file is to be accessed by rmt: compressor doesn't know how;
337 c) the file is not a plain file. */
338
339 if (strcmp (archive_name_array[0], "-") != 0
340 && !_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
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 execlp (use_compress_program_option, use_compress_program_option,
361 (char *) 0);
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 setenv (envar, numstr, 1);
615 }
616
617 static void
618 oct_to_env (char *envar, unsigned long num)
619 {
620 char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
621
622 snprintf (buf, sizeof buf, "0%lo", num);
623 setenv (envar, buf, 1);
624 }
625
626 static void
627 str_to_env (char *envar, char const *str)
628 {
629 if (str)
630 setenv (envar, str, 1);
631 else
632 unsetenv (envar);
633 }
634
635 static void
636 chr_to_env (char *envar, char c)
637 {
638 char buf[2];
639 buf[0] = c;
640 buf[1] = 0;
641 setenv (envar, buf, 1);
642 }
643
644 static void
645 stat_to_env (char *name, char type, struct tar_stat_info *st)
646 {
647 chr_to_env ("TAR_FILETYPE", type);
648 oct_to_env ("TAR_MODE", st->stat.st_mode);
649 str_to_env ("TAR_FILENAME", name);
650 str_to_env ("TAR_REALNAME", st->file_name);
651 str_to_env ("TAR_UNAME", st->uname);
652 str_to_env ("TAR_GNAME", st->gname);
653 dec_to_env ("TAR_MTIME", st->stat.st_mtime);
654 dec_to_env ("TAR_ATIME", st->stat.st_atime);
655 dec_to_env ("TAR_CTIME", st->stat.st_ctime);
656 dec_to_env ("TAR_SIZE", st->stat.st_size);
657 dec_to_env ("TAR_UID", st->stat.st_uid);
658 dec_to_env ("TAR_GID", st->stat.st_gid);
659
660 switch (type)
661 {
662 case 'b':
663 case 'c':
664 dec_to_env ("TAR_MINOR", minor (st->stat.st_rdev));
665 dec_to_env ("TAR_MAJOR", major (st->stat.st_rdev));
666 unsetenv ("TAR_LINKNAME");
667 break;
668
669 case 'l':
670 case 'h':
671 unsetenv ("TAR_MINOR");
672 unsetenv ("TAR_MAJOR");
673 str_to_env ("TAR_LINKNAME", st->link_name);
674 break;
675
676 default:
677 unsetenv ("TAR_MINOR");
678 unsetenv ("TAR_MAJOR");
679 unsetenv ("TAR_LINKNAME");
680 break;
681 }
682 }
683
684 static pid_t pid;
685 static RETSIGTYPE (*pipe_handler) (int sig);
686
687 int
688 sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
689 {
690 int p[2];
691 char *argv[4];
692
693 xpipe (p);
694 pipe_handler = signal (SIGPIPE, SIG_IGN);
695 pid = xfork ();
696
697 if (pid != 0)
698 {
699 xclose (p[PREAD]);
700 return p[PWRITE];
701 }
702
703 /* Child */
704 xdup2 (p[PREAD], STDIN_FILENO);
705 xclose (p[PWRITE]);
706
707 stat_to_env (file_name, typechar, st);
708
709 argv[0] = "/bin/sh";
710 argv[1] = "-c";
711 argv[2] = to_command_option;
712 argv[3] = NULL;
713
714 execv ("/bin/sh", argv);
715
716 exec_fatal (file_name);
717 }
718
719 void
720 sys_wait_command (void)
721 {
722 int status;
723
724 if (pid < 0)
725 return;
726
727 signal (SIGPIPE, pipe_handler);
728 while (waitpid (pid, &status, 0) == -1)
729 if (errno != EINTR)
730 {
731 pid = -1;
732 waitpid_error (to_command_option);
733 return;
734 }
735
736 if (WIFEXITED (status))
737 {
738 if (!ignore_command_error_option && WEXITSTATUS (status))
739 ERROR ((0, 0, _("%lu: Child returned status %d"),
740 (unsigned long) pid, WEXITSTATUS (status)));
741 }
742 else if (WIFSIGNALED (status))
743 {
744 WARN ((0, 0, _("%lu: Child terminated on signal %d"),
745 (unsigned long) pid, WTERMSIG (status)));
746 }
747 else
748 ERROR ((0, 0, _("%lu: Child terminated on unknown reason"),
749 (unsigned long) pid));
750
751 pid = -1;
752 }
753
754 #endif /* not MSDOS */
This page took 0.064448 seconds and 5 git commands to generate.