]> Dogcows Code - chaz/tar/blob - src/system.c
(start_header): Removed debugging hook
[chaz/tar] / src / system.c
1 /* System-dependent calls for tar.
2
3 Copyright (C) 2003 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 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ()
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 ()
41 {
42 }
43
44 void
45 sys_detect_dev_null_output ()
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 ()
55 {
56 }
57
58 void
59 sys_wait_for_child (pid_t child_pid)
60 {
61 }
62
63 void
64 sys_spawn_shell ()
65 {
66 spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
67 }
68
69 void
70 sys_compare_uid_gid (struct stat *a, struct stat *b)
71 {
72 /* stat() in djgpp's C library gives a constant number of 42 as the
73 uid and gid of a file. So, comparing an FTP'ed archive just after
74 unpack would fail on MSDOS. */
75 }
76
77 void
78 sys_compare_links (struct stat *link_data, struct stat *stat_data)
79 {
80 }
81
82 int
83 sys_truncate (int fd)
84 {
85 return write (fd, "", 0);
86 }
87
88 void
89 sys_reset_uid_gid ()
90 {
91 }
92
93 ssize_t
94 sys_write_archive_buffer (void)
95 {
96 ssize_t status;
97 ssize_t written = 0;
98
99 while (0 <= (status = full_write (archive, record_start->buffer + written,
100 record_size - written)))
101 {
102 written += status;
103 if (written == record_size)
104 break;
105 }
106
107 return written ? written : status;
108 }
109
110 /* Set ARCHIVE for writing, then compressing an archive. */
111 void
112 sys_child_open_for_compress (void)
113 {
114 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
115 }
116
117 /* Set ARCHIVE for uncompressing, then reading an archive. */
118 void
119 sys_child_open_for_uncompress (void)
120 {
121 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
122 }
123
124 #else
125
126 extern union block *record_start; /* FIXME */
127
128 static struct stat archive_stat; /* stat block for archive file */
129
130 bool
131 sys_get_archive_stat ()
132 {
133 return fstat (archive, &archive_stat) == 0;
134 }
135
136 bool
137 sys_file_is_archive (struct tar_stat_info *p)
138 {
139 return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
140 }
141
142 /* Save archive file inode and device numbers */
143 void
144 sys_save_archive_dev_ino ()
145 {
146 if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
147 {
148 ar_dev = archive_stat.st_dev;
149 ar_ino = archive_stat.st_ino;
150 }
151 else
152 ar_dev = 0;
153 }
154
155 /* Detect if outputting to "/dev/null". */
156 void
157 sys_detect_dev_null_output ()
158 {
159 static char const dev_null[] = "/dev/null";
160 struct stat dev_null_stat;
161
162 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
163 || (! _isrmt (archive)
164 && S_ISCHR (archive_stat.st_mode)
165 && stat (dev_null, &dev_null_stat) == 0
166 && archive_stat.st_dev == dev_null_stat.st_dev
167 && archive_stat.st_ino == dev_null_stat.st_ino));
168 }
169
170 /* Manage to fully drain a pipe we might be reading, so to not break it on
171 the producer after the EOF block. FIXME: one of these days, GNU tar
172 might become clever enough to just stop working, once there is no more
173 work to do, we might have to revise this area in such time. */
174
175 void
176 sys_drain_input_pipe ()
177 {
178 if (access_mode == ACCESS_READ
179 && ! _isrmt (archive)
180 && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
181 while (rmtread (archive, record_start->buffer, record_size) > 0)
182 continue;
183 }
184
185 void
186 sys_wait_for_child (pid_t child_pid)
187 {
188 if (child_pid)
189 {
190 int wait_status;
191
192 while (waitpid (child_pid, &wait_status, 0) == -1)
193 if (errno != EINTR)
194 {
195 waitpid_error (use_compress_program_option);
196 break;
197 }
198
199 if (WIFSIGNALED (wait_status))
200 ERROR ((0, 0, _("Child died with signal %d"),
201 WTERMSIG (wait_status)));
202 else if (WEXITSTATUS (wait_status) != 0)
203 ERROR ((0, 0, _("Child returned status %d"),
204 WEXITSTATUS (wait_status)));
205 }
206 }
207
208 void
209 sys_spawn_shell ()
210 {
211 pid_t child;
212 const char *shell = getenv ("SHELL");
213 if (! shell)
214 shell = "/bin/sh";
215 child = xfork ();
216 if (child == 0)
217 {
218 execlp (shell, "-sh", "-i", (char *) 0);
219 exec_fatal (shell);
220 }
221 else
222 {
223 int wait_status;
224 while (waitpid (child, &wait_status, 0) == -1)
225 if (errno != EINTR)
226 {
227 waitpid_error (shell);
228 break;
229 }
230 }
231 }
232
233 void
234 sys_compare_uid_gid (struct stat *a, struct stat *b)
235 {
236 if (a->st_uid != b->st_uid)
237 report_difference (_("Uid differs"));
238 if (a->st_gid != b->st_gid)
239 report_difference (_("Gid differs"));
240 }
241
242 void
243 sys_compare_links (struct stat *link_data, struct stat *stat_data)
244 {
245 if (stat_data->st_dev != link_data->st_dev
246 || stat_data->st_ino != link_data->st_ino)
247 {
248 report_difference (_("Not linked to %s"),
249 quote (current_stat_info.link_name));
250 }
251 }
252
253 int
254 sys_truncate (int fd)
255 {
256 off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
257 return pos < 0 ? -1 : ftruncate (fd, pos);
258 }
259
260 void
261 sys_reset_uid_gid ()
262 {
263 setuid (getuid ());
264 setgid (getgid ());
265 }
266
267 /* Return nonzero if NAME is the name of a regular file, or if the file
268 does not exist (so it would be created as a regular file). */
269 static int
270 is_regular_file (const char *name)
271 {
272 struct stat stbuf;
273
274 if (stat (name, &stbuf) == 0)
275 return S_ISREG (stbuf.st_mode);
276 else
277 return errno == ENOENT;
278 }
279
280 ssize_t
281 sys_write_archive_buffer (void)
282 {
283 ssize_t status;
284 ssize_t written = 0;
285
286 while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
287 record_size - written)))
288 {
289 written += status;
290 if (written == record_size
291 || _isrmt (archive)
292 || ! (S_ISFIFO (archive_stat.st_mode)
293 || S_ISSOCK (archive_stat.st_mode)))
294 break;
295 }
296
297 return written ? written : status;
298 }
299
300 #define PREAD 0 /* read file descriptor from pipe() */
301 #define PWRITE 1 /* write file descriptor from pipe() */
302
303 /* Duplicate file descriptor FROM into becoming INTO.
304 INTO is closed first and has to be the next available slot. */
305 static void
306 xdup2 (int from, int into)
307 {
308 if (from != into)
309 {
310 int status = close (into);
311
312 if (status != 0 && errno != EBADF)
313 {
314 int e = errno;
315 FATAL_ERROR ((0, e, _("Cannot close")));
316 }
317 status = dup (from);
318 if (status != into)
319 {
320 if (status < 0)
321 {
322 int e = errno;
323 FATAL_ERROR ((0, e, _("Cannot dup")));
324 }
325 abort ();
326 }
327 xclose (from);
328 }
329 }
330
331 /* Set ARCHIVE for writing, then compressing an archive. */
332 pid_t
333 sys_child_open_for_compress (void)
334 {
335 int parent_pipe[2];
336 int child_pipe[2];
337 pid_t grandchild_pid;
338 pid_t child_pid;
339 int wait_status;
340
341 xpipe (parent_pipe);
342 child_pid = xfork ();
343
344 if (child_pid > 0)
345 {
346 /* The parent tar is still here! Just clean up. */
347
348 archive = parent_pipe[PWRITE];
349 xclose (parent_pipe[PREAD]);
350 return child_pid;
351 }
352
353 /* The new born child tar is here! */
354
355 program_name = _("tar (child)");
356
357 xdup2 (parent_pipe[PREAD], STDIN_FILENO);
358 xclose (parent_pipe[PWRITE]);
359
360 /* Check if we need a grandchild tar. This happens only if either:
361 a) we are writing stdout: to force reblocking;
362 b) the file is to be accessed by rmt: compressor doesn't know how;
363 c) the file is not a plain file. */
364
365 if (strcmp (archive_name_array[0], "-") != 0
366 && !_remdev (archive_name_array[0])
367 && is_regular_file (archive_name_array[0]))
368 {
369 if (backup_option)
370 maybe_backup_file (archive_name_array[0], 1);
371
372 /* We don't need a grandchild tar. Open the archive and launch the
373 compressor. */
374
375 archive = creat (archive_name_array[0], MODE_RW);
376 if (archive < 0)
377 {
378 int saved_errno = errno;
379
380 if (backup_option)
381 undo_last_backup ();
382 errno = saved_errno;
383 open_fatal (archive_name_array[0]);
384 }
385 xdup2 (archive, STDOUT_FILENO);
386 execlp (use_compress_program_option, use_compress_program_option,
387 (char *) 0);
388 exec_fatal (use_compress_program_option);
389 }
390
391 /* We do need a grandchild tar. */
392
393 xpipe (child_pipe);
394 grandchild_pid = xfork ();
395
396 if (grandchild_pid == 0)
397 {
398 /* The newborn grandchild tar is here! Launch the compressor. */
399
400 program_name = _("tar (grandchild)");
401
402 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
403 xclose (child_pipe[PREAD]);
404 execlp (use_compress_program_option, use_compress_program_option,
405 (char *) 0);
406 exec_fatal (use_compress_program_option);
407 }
408
409 /* The child tar is still here! */
410
411 /* Prepare for reblocking the data from the compressor into the archive. */
412
413 xdup2 (child_pipe[PREAD], STDIN_FILENO);
414 xclose (child_pipe[PWRITE]);
415
416 if (strcmp (archive_name_array[0], "-") == 0)
417 archive = STDOUT_FILENO;
418 else
419 {
420 archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
421 if (archive < 0)
422 open_fatal (archive_name_array[0]);
423 }
424
425 /* Let's read out of the stdin pipe and write an archive. */
426
427 while (1)
428 {
429 ssize_t status = 0;
430 char *cursor;
431 size_t length;
432
433 /* Assemble a record. */
434
435 for (length = 0, cursor = record_start->buffer;
436 length < record_size;
437 length += status, cursor += status)
438 {
439 size_t size = record_size - length;
440
441 status = safe_read (STDIN_FILENO, cursor, size);
442 if (status <= 0)
443 break;
444 }
445
446 if (status < 0)
447 read_fatal (use_compress_program_option);
448
449 /* Copy the record. */
450
451 if (status == 0)
452 {
453 /* We hit the end of the file. Write last record at
454 full length, as the only role of the grandchild is
455 doing proper reblocking. */
456
457 if (length > 0)
458 {
459 memset (record_start->buffer + length, 0, record_size - length);
460 status = sys_write_archive_buffer ();
461 if (status != record_size)
462 archive_write_error (status);
463 }
464
465 /* There is nothing else to read, break out. */
466 break;
467 }
468
469 status = sys_write_archive_buffer ();
470 if (status != record_size)
471 archive_write_error (status);
472 }
473
474 /* Propagate any failure of the grandchild back to the parent. */
475
476 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
477 if (errno != EINTR)
478 {
479 waitpid_error (use_compress_program_option);
480 break;
481 }
482
483 if (WIFSIGNALED (wait_status))
484 {
485 kill (child_pid, WTERMSIG (wait_status));
486 exit_status = TAREXIT_FAILURE;
487 }
488 else if (WEXITSTATUS (wait_status) != 0)
489 exit_status = WEXITSTATUS (wait_status);
490
491 exit (exit_status);
492 }
493
494 /* Set ARCHIVE for uncompressing, then reading an archive. */
495 pid_t
496 sys_child_open_for_uncompress (void)
497 {
498 int parent_pipe[2];
499 int child_pipe[2];
500 pid_t grandchild_pid;
501 pid_t child_pid;
502 int wait_status;
503
504 xpipe (parent_pipe);
505 child_pid = xfork ();
506
507 if (child_pid > 0)
508 {
509 /* The parent tar is still here! Just clean up. */
510
511 read_full_records_option = 1;
512 archive = parent_pipe[PREAD];
513 xclose (parent_pipe[PWRITE]);
514 return child_pid;
515 }
516
517 /* The newborn child tar is here! */
518
519 program_name = _("tar (child)");
520
521 xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
522 xclose (parent_pipe[PREAD]);
523
524 /* Check if we need a grandchild tar. This happens only if either:
525 a) we're reading stdin: to force unblocking;
526 b) the file is to be accessed by rmt: compressor doesn't know how;
527 c) the file is not a plain file. */
528
529 if (strcmp (archive_name_array[0], "-") != 0
530 && !_remdev (archive_name_array[0])
531 && is_regular_file (archive_name_array[0]))
532 {
533 /* We don't need a grandchild tar. Open the archive and lauch the
534 uncompressor. */
535
536 archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
537 if (archive < 0)
538 open_fatal (archive_name_array[0]);
539 xdup2 (archive, STDIN_FILENO);
540 execlp (use_compress_program_option, use_compress_program_option,
541 "-d", (char *) 0);
542 exec_fatal (use_compress_program_option);
543 }
544
545 /* We do need a grandchild tar. */
546
547 xpipe (child_pipe);
548 grandchild_pid = xfork ();
549
550 if (grandchild_pid == 0)
551 {
552 /* The newborn grandchild tar is here! Launch the uncompressor. */
553
554 program_name = _("tar (grandchild)");
555
556 xdup2 (child_pipe[PREAD], STDIN_FILENO);
557 xclose (child_pipe[PWRITE]);
558 execlp (use_compress_program_option, use_compress_program_option,
559 "-d", (char *) 0);
560 exec_fatal (use_compress_program_option);
561 }
562
563 /* The child tar is still here! */
564
565 /* Prepare for unblocking the data from the archive into the
566 uncompressor. */
567
568 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
569 xclose (child_pipe[PREAD]);
570
571 if (strcmp (archive_name_array[0], "-") == 0)
572 archive = STDIN_FILENO;
573 else
574 archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
575 MODE_RW, rsh_command_option);
576 if (archive < 0)
577 open_fatal (archive_name_array[0]);
578
579 /* Let's read the archive and pipe it into stdout. */
580
581 while (1)
582 {
583 char *cursor;
584 size_t maximum;
585 size_t count;
586 ssize_t status;
587
588 clear_read_error_count ();
589
590 error_loop:
591 status = rmtread (archive, record_start->buffer, record_size);
592 if (status < 0)
593 {
594 archive_read_error ();
595 goto error_loop;
596 }
597 if (status == 0)
598 break;
599 cursor = record_start->buffer;
600 maximum = status;
601 while (maximum)
602 {
603 count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
604 if (full_write (STDOUT_FILENO, cursor, count) != count)
605 write_error (use_compress_program_option);
606 cursor += count;
607 maximum -= count;
608 }
609 }
610
611 xclose (STDOUT_FILENO);
612
613 /* Propagate any failure of the grandchild back to the parent. */
614
615 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
616 if (errno != EINTR)
617 {
618 waitpid_error (use_compress_program_option);
619 break;
620 }
621
622 if (WIFSIGNALED (wait_status))
623 {
624 kill (child_pid, WTERMSIG (wait_status));
625 exit_status = TAREXIT_FAILURE;
626 }
627 else if (WEXITSTATUS (wait_status) != 0)
628 exit_status = WEXITSTATUS (wait_status);
629
630 exit (exit_status);
631 }
632
633 #endif /* not MSDOS */
634
This page took 0.0589 seconds and 4 git commands to generate.