Imported Debian patch 1.5-16
[debian/pax] / gen_subs.c
1 /*      $OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $    */
2 /*      $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */
3
4 /*-
5  * Copyright (c) 1992 Keith Muller.
6  * Copyright (c) 1992, 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Keith Muller of the University of California, San Diego.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the University of
23  *      California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)gen_subs.c  8.1 (Berkeley) 5/31/93";
44 #else
45 static char rcsid[] = "$OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $";
46 #endif
47 #endif /* not lint */
48
49 #include <sys/types.h>
50 #include <sys/sysmacros.h>
51 #include <sys/time.h>
52 #include <time.h>
53 #include <sys/stat.h>
54 #include <sys/param.h>
55 #include <stdio.h>
56 #include "tzfile.h"
57 #include <utmp.h>
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include "pax.h"
62 #include "extern.h"
63
64 #include "strmode.h"
65
66 /*
67  * a collection of general purpose subroutines used by pax
68  */
69
70 /*
71  * constants used by ls_list() when printing out archive members
72  */
73 #define MODELEN 20
74 #define DATELEN 64
75 #define SIXMONTHS        ((DAYSPERNYEAR / 2) * SECSPERDAY)
76 #define CURFRMT         "%b %e %H:%M"
77 #define OLDFRMT         "%b %e  %Y"
78 #ifndef UT_NAMESIZE
79 #define UT_NAMESIZE     8
80 #endif
81 #define UT_GRPSIZE      6
82
83 /*
84  * ls_list()
85  *      list the members of an archive in ls format
86  */
87
88 #ifdef __STDC__
89 void
90 ls_list(register ARCHD *arcn, time_t now, FILE *fp)
91 #else
92 void
93 ls_list(arcn, now, fp)
94         register ARCHD *arcn;
95         time_t now;
96         FILE *fp;
97 #endif
98 {
99         register struct stat *sbp;
100         char f_mode[MODELEN];
101         char f_date[DATELEN];
102         char *timefrmt;
103
104         /*
105          * if not verbose, just print the file name
106          */
107         if (!vflag) {
108                 (void)fprintf(fp, "%s\n", arcn->name);
109                 (void)fflush(fp);
110                 return;
111         }
112
113         /*
114          * user wants long mode
115          */
116         sbp = &(arcn->sb);
117         strmode(sbp->st_mode, f_mode);
118
119         if (ltmfrmt == NULL) {
120                 /*
121                  * no locale specified format. time format based on age
122                  * compared to the time pax was started.
123                  */
124                 if ((sbp->st_mtime + SIXMONTHS) <= now)
125                         timefrmt = OLDFRMT;
126                 else
127                         timefrmt = CURFRMT;
128         } else
129                 timefrmt = ltmfrmt;
130
131         /*
132          * print file mode, link count, uid, gid and time
133          */
134         if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
135                 f_date[0] = '\0';
136         (void)fprintf(fp, "%s%2u %-*s %-*s ", f_mode, sbp->st_nlink,
137                 UT_NAMESIZE, name_uid(sbp->st_uid, 1), UT_GRPSIZE,
138                 name_gid(sbp->st_gid, 1));
139
140         /*
141          * print device id's for devices, or sizes for other nodes
142          */
143         if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
144 #               ifdef NET2_STAT
145                 (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
146 #               else
147                 (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
148 #               endif
149                     (unsigned long)MINOR(sbp->st_rdev));
150         else {
151 #               ifdef NET2_STAT
152                 (void)fprintf(fp, "%9lu ", sbp->st_size);
153 #               else
154                 (void)fprintf(fp, "%9qu ", sbp->st_size);
155 #               endif
156         }
157
158         /*
159          * print name and link info for hard and soft links
160          */
161         (void)fprintf(fp, "%s %s", f_date, arcn->name);
162         if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
163                 (void)fprintf(fp, " == %s\n", arcn->ln_name);
164         else if (arcn->type == PAX_SLK)
165                 (void)fprintf(fp, " => %s\n", arcn->ln_name);
166         else
167                 (void)putc('\n', fp);
168         (void)fflush(fp);
169         return;
170 }
171
172 /*
173  * tty_ls()
174  *      print a short summary of file to tty.
175  */
176
177 #ifdef __STDC__
178 void
179 ls_tty(register ARCHD *arcn)
180 #else
181 void
182 ls_tty(arcn)
183         register ARCHD *arcn;
184 #endif
185 {
186         char f_date[DATELEN];
187         char f_mode[MODELEN];
188         char *timefrmt;
189
190         if (ltmfrmt == NULL) {
191                 /*
192                  * no locale specified format
193                  */
194                 if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
195                         timefrmt = OLDFRMT;
196                 else
197                         timefrmt = CURFRMT;
198         } else
199                 timefrmt = ltmfrmt;
200
201         /*
202          * convert time to string, and print
203          */
204         if (strftime(f_date, DATELEN, timefrmt,
205             localtime(&(arcn->sb.st_mtime))) == 0)
206                 f_date[0] = '\0';
207         strmode(arcn->sb.st_mode, f_mode);
208         tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
209         return;
210 }
211
212 /*
213  * l_strncpy()
214  *      copy src to dest up to len chars (stopping at first '\0').
215  *      when src is shorter than len, pads to len with '\0'. 
216  * Return:
217  *      number of chars copied. (Note this is a real performance win over
218  *      doing a strncpy(), a strlen(), and then a possible memset())
219  */
220
221 #ifdef __STDC__
222 int
223 l_strncpy(register char *dest, register char *src, int len)
224 #else
225 int
226 l_strncpy(dest, src, len)
227         register char *dest;
228         register char *src;
229         int len;
230 #endif
231 {
232         register char *stop;
233         register char *start;
234
235         stop = dest + len;
236         start = dest;
237         while ((dest < stop) && (*src != '\0'))
238                 *dest++ = *src++;
239         len = dest - start;
240         while (dest < stop)
241                 *dest++ = '\0';
242         return(len);
243 }
244
245 /*
246  * asc_ul()
247  *      convert hex/octal character string into a u_long. We do not have to
248  *      check for overflow! (the headers in all supported formats are not large
249  *      enough to create an overflow).
250  *      NOTE: strings passed to us are NOT TERMINATED.
251  * Return:
252  *      unsigned long value
253  */
254
255 #ifdef __STDC__
256 u_long
257 asc_ul(register char *str, int len, register int base)
258 #else
259 u_long
260 asc_ul(str, len, base)
261         register char *str;
262         int len;
263         register int base;
264 #endif
265 {
266         register char *stop;
267         u_long tval = 0;
268
269         stop = str + len;
270
271         /*
272          * skip over leading blanks and zeros
273          */
274         while ((str < stop) && ((*str == ' ') || (*str == '0')))
275                 ++str;
276
277         /*
278          * for each valid digit, shift running value (tval) over to next digit
279          * and add next digit
280          */
281         if (base == HEX) {
282                 while (str < stop) {
283                         if ((*str >= '0') && (*str <= '9'))
284                                 tval = (tval << 4) + (*str++ - '0');
285                         else if ((*str >= 'A') && (*str <= 'F'))
286                                 tval = (tval << 4) + 10 + (*str++ - 'A');
287                         else if ((*str >= 'a') && (*str <= 'f'))
288                                 tval = (tval << 4) + 10 + (*str++ - 'a');
289                         else
290                                 break;
291                 }
292         } else {
293                 while ((str < stop) && (*str >= '0') && (*str <= '7'))
294                         tval = (tval << 3) + (*str++ - '0');
295         }
296         return(tval);
297 }
298
299 /*
300  * ul_asc()
301  *      convert an unsigned long into an hex/oct ascii string. pads with LEADING
302  *      ascii 0's to fill string completely
303  *      NOTE: the string created is NOT TERMINATED.
304  */
305
306 #ifdef __STDC__
307 int
308 ul_asc(u_long val, register char *str, register int len, register int base)
309 #else
310 int
311 ul_asc(val, str, len, base)
312         u_long val;
313         register char *str;
314         register int len;
315         register int base;
316 #endif
317 {
318         register char *pt;
319         u_long digit;
320
321         /*
322          * WARNING str is not '\0' terminated by this routine
323          */
324         pt = str + len - 1;
325
326         /*
327          * do a tailwise conversion (start at right most end of string to place
328          * least significant digit). Keep shifting until conversion value goes
329          * to zero (all digits were converted)
330          */
331         if (base == HEX) {
332                 while (pt >= str) {
333                         if ((digit = (val & 0xf)) < 10)
334                                 *pt-- = '0' + (char)digit;
335                         else
336                                 *pt-- = 'a' + (char)(digit - 10);
337                         if ((val = (val >> 4)) == (u_long)0)
338                                 break;
339                 }
340         } else {
341                 while (pt >= str) {
342                         *pt-- = '0' + (char)(val & 0x7);
343                         if ((val = (val >> 3)) == (u_long)0)
344                                 break;
345                 }
346         }
347
348         /*
349          * pad with leading ascii ZEROS. We return -1 if we ran out of space.
350          */
351         while (pt >= str)
352                 *pt-- = '0';
353         if (val != (u_long)0)
354                 return(-1);
355         return(0);
356 }
357
358 #ifndef NET2_STAT
359 /*
360  * asc_uqd()
361  *      convert hex/octal character string into a u_quad_t. We do not have to
362  *      check for overflow! (the headers in all supported formats are not large
363  *      enough to create an overflow).
364  *      NOTE: strings passed to us are NOT TERMINATED.
365  * Return:
366  *      u_quad_t value
367  */
368
369 #ifdef __STDC__
370 u_quad_t
371 asc_uqd(register char *str, int len, register int base)
372 #else
373 u_quad_t
374 asc_uqd(str, len, base)
375         register char *str;
376         int len;
377         register int base;
378 #endif
379 {
380         register char *stop;
381         u_quad_t tval = 0;
382
383         stop = str + len;
384
385         /*
386          * skip over leading blanks and zeros
387          */
388         while ((str < stop) && ((*str == ' ') || (*str == '0')))
389                 ++str;
390
391         /*
392          * for each valid digit, shift running value (tval) over to next digit
393          * and add next digit
394          */
395         if (base == HEX) {
396                 while (str < stop) {
397                         if ((*str >= '0') && (*str <= '9'))
398                                 tval = (tval << 4) + (*str++ - '0');
399                         else if ((*str >= 'A') && (*str <= 'F'))
400                                 tval = (tval << 4) + 10 + (*str++ - 'A');
401                         else if ((*str >= 'a') && (*str <= 'f'))
402                                 tval = (tval << 4) + 10 + (*str++ - 'a');
403                         else
404                                 break;
405                 }
406         } else {
407                 while ((str < stop) && (*str >= '0') && (*str <= '7'))
408                         tval = (tval << 3) + (*str++ - '0');
409         }
410         return(tval);
411 }
412
413 /*
414  * uqd_asc()
415  *      convert an u_quad_t into a hex/oct ascii string. pads with LEADING
416  *      ascii 0's to fill string completely
417  *      NOTE: the string created is NOT TERMINATED.
418  */
419
420 #ifdef __STDC__
421 int
422 uqd_asc(u_quad_t val, register char *str, register int len, register int base)
423 #else
424 int
425 uqd_asc(val, str, len, base)
426         u_quad_t val;
427         register char *str;
428         register int len;
429         register int base;
430 #endif
431 {
432         register char *pt;
433         u_quad_t digit;
434
435         /*
436          * WARNING str is not '\0' terminated by this routine
437          */
438         pt = str + len - 1;
439
440         /*
441          * do a tailwise conversion (start at right most end of string to place
442          * least significant digit). Keep shifting until conversion value goes
443          * to zero (all digits were converted)
444          */
445         if (base == HEX) {
446                 while (pt >= str) {
447                         if ((digit = (val & 0xf)) < 10)
448                                 *pt-- = '0' + (char)digit;
449                         else
450                                 *pt-- = 'a' + (char)(digit - 10);
451                         if ((val = (val >> 4)) == (u_quad_t)0)
452                                 break;
453                 }
454         } else {
455                 while (pt >= str) {
456                         *pt-- = '0' + (char)(val & 0x7);
457                         if ((val = (val >> 3)) == (u_quad_t)0)
458                                 break;
459                 }
460         }
461
462         /*
463          * pad with leading ascii ZEROS. We return -1 if we ran out of space.
464          */
465         while (pt >= str)
466                 *pt-- = '0';
467         if (val != (u_quad_t)0)
468                 return(-1);
469         return(0);
470 }
471 #endif