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