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