6ff16f0a6eb7ded7a0ed827cdf321098644d6388
[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/time.h>
51 #include <sys/stat.h>
52 #include <sys/param.h>
53 #include <stdio.h>
54 #include <tzfile.h>
55 #include <utmp.h>
56 #include <unistd.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include "pax.h"
60 #include "extern.h"
61
62 /*
63  * a collection of general purpose subroutines used by pax
64  */
65
66 /*
67  * constants used by ls_list() when printing out archive members
68  */
69 #define MODELEN 20
70 #define DATELEN 64
71 #define SIXMONTHS        ((DAYSPERNYEAR / 2) * SECSPERDAY)
72 #define CURFRMT         "%b %e %H:%M"
73 #define OLDFRMT         "%b %e  %Y"
74 #ifndef UT_NAMESIZE
75 #define UT_NAMESIZE     8
76 #endif
77 #define UT_GRPSIZE      6
78
79 /*
80  * ls_list()
81  *      list the members of an archive in ls format
82  */
83
84 #ifdef __STDC__
85 void
86 ls_list(register ARCHD *arcn, time_t now, FILE *fp)
87 #else
88 void
89 ls_list(arcn, now, fp)
90         register ARCHD *arcn;
91         time_t now;
92         FILE *fp;
93 #endif
94 {
95         register struct stat *sbp;
96         char f_mode[MODELEN];
97         char f_date[DATELEN];
98         char *timefrmt;
99
100         /*
101          * if not verbose, just print the file name
102          */
103         if (!vflag) {
104                 (void)fprintf(fp, "%s\n", arcn->name);
105                 (void)fflush(fp);
106                 return;
107         }
108
109         /*
110          * user wants long mode
111          */
112         sbp = &(arcn->sb);
113         strmode(sbp->st_mode, f_mode);
114
115         if (ltmfrmt == NULL) {
116                 /*
117                  * no locale specified format. time format based on age
118                  * compared to the time pax was started.
119                  */
120                 if ((sbp->st_mtime + SIXMONTHS) <= now)
121                         timefrmt = OLDFRMT;
122                 else
123                         timefrmt = CURFRMT;
124         } else
125                 timefrmt = ltmfrmt;
126
127         /*
128          * print file mode, link count, uid, gid and time
129          */
130         if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
131                 f_date[0] = '\0';
132         (void)fprintf(fp, "%s%2u %-*s %-*s ", f_mode, sbp->st_nlink,
133                 UT_NAMESIZE, name_uid(sbp->st_uid, 1), UT_GRPSIZE,
134                 name_gid(sbp->st_gid, 1));
135
136         /*
137          * print device id's for devices, or sizes for other nodes
138          */
139         if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
140 #               ifdef NET2_STAT
141                 (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
142 #               else
143                 (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
144 #               endif
145                     (unsigned long)MINOR(sbp->st_rdev));
146         else {
147 #               ifdef NET2_STAT
148                 (void)fprintf(fp, "%9lu ", sbp->st_size);
149 #               else
150                 (void)fprintf(fp, "%9qu ", sbp->st_size);
151 #               endif
152         }
153
154         /*
155          * print name and link info for hard and soft links
156          */
157         (void)fprintf(fp, "%s %s", f_date, arcn->name);
158         if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
159                 (void)fprintf(fp, " == %s\n", arcn->ln_name);
160         else if (arcn->type == PAX_SLK)
161                 (void)fprintf(fp, " => %s\n", arcn->ln_name);
162         else
163                 (void)putc('\n', fp);
164         (void)fflush(fp);
165         return;
166 }
167
168 /*
169  * tty_ls()
170  *      print a short summary of file to tty.
171  */
172
173 #ifdef __STDC__
174 void
175 ls_tty(register ARCHD *arcn)
176 #else
177 void
178 ls_tty(arcn)
179         register ARCHD *arcn;
180 #endif
181 {
182         char f_date[DATELEN];
183         char f_mode[MODELEN];
184         char *timefrmt;
185
186         if (ltmfrmt == NULL) {
187                 /*
188                  * no locale specified format
189                  */
190                 if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
191                         timefrmt = OLDFRMT;
192                 else
193                         timefrmt = CURFRMT;
194         } else
195                 timefrmt = ltmfrmt;
196
197         /*
198          * convert time to string, and print
199          */
200         if (strftime(f_date, DATELEN, timefrmt,
201             localtime(&(arcn->sb.st_mtime))) == 0)
202                 f_date[0] = '\0';
203         strmode(arcn->sb.st_mode, f_mode);
204         tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
205         return;
206 }
207
208 /*
209  * l_strncpy()
210  *      copy src to dest up to len chars (stopping at first '\0').
211  *      when src is shorter than len, pads to len with '\0'. 
212  * Return:
213  *      number of chars copied. (Note this is a real performance win over
214  *      doing a strncpy(), a strlen(), and then a possible memset())
215  */
216
217 #ifdef __STDC__
218 int
219 l_strncpy(register char *dest, register char *src, int len)
220 #else
221 int
222 l_strncpy(dest, src, len)
223         register char *dest;
224         register char *src;
225         int len;
226 #endif
227 {
228         register char *stop;
229         register char *start;
230
231         stop = dest + len;
232         start = dest;
233         while ((dest < stop) && (*src != '\0'))
234                 *dest++ = *src++;
235         len = dest - start;
236         while (dest < stop)
237                 *dest++ = '\0';
238         return(len);
239 }
240
241 /*
242  * asc_ul()
243  *      convert hex/octal character string into a u_long. We do not have to
244  *      check for overflow! (the headers in all supported formats are not large
245  *      enough to create an overflow).
246  *      NOTE: strings passed to us are NOT TERMINATED.
247  * Return:
248  *      unsigned long value
249  */
250
251 #ifdef __STDC__
252 u_long
253 asc_ul(register char *str, int len, register int base)
254 #else
255 u_long
256 asc_ul(str, len, base)
257         register char *str;
258         int len;
259         register int base;
260 #endif
261 {
262         register char *stop;
263         u_long tval = 0;
264
265         stop = str + len;
266
267         /*
268          * skip over leading blanks and zeros
269          */
270         while ((str < stop) && ((*str == ' ') || (*str == '0')))
271                 ++str;
272
273         /*
274          * for each valid digit, shift running value (tval) over to next digit
275          * and add next digit
276          */
277         if (base == HEX) {
278                 while (str < stop) {
279                         if ((*str >= '0') && (*str <= '9'))
280                                 tval = (tval << 4) + (*str++ - '0');
281                         else if ((*str >= 'A') && (*str <= 'F'))
282                                 tval = (tval << 4) + 10 + (*str++ - 'A');
283                         else if ((*str >= 'a') && (*str <= 'f'))
284                                 tval = (tval << 4) + 10 + (*str++ - 'a');
285                         else
286                                 break;
287                 }
288         } else {
289                 while ((str < stop) && (*str >= '0') && (*str <= '7'))
290                         tval = (tval << 3) + (*str++ - '0');
291         }
292         return(tval);
293 }
294
295 /*
296  * ul_asc()
297  *      convert an unsigned long into an hex/oct ascii string. pads with LEADING
298  *      ascii 0's to fill string completely
299  *      NOTE: the string created is NOT TERMINATED.
300  */
301
302 #ifdef __STDC__
303 int
304 ul_asc(u_long val, register char *str, register int len, register int base)
305 #else
306 int
307 ul_asc(val, str, len, base)
308         u_long val;
309         register char *str;
310         register int len;
311         register int base;
312 #endif
313 {
314         register char *pt;
315         u_long digit;
316
317         /*
318          * WARNING str is not '\0' terminated by this routine
319          */
320         pt = str + len - 1;
321
322         /*
323          * do a tailwise conversion (start at right most end of string to place
324          * least significant digit). Keep shifting until conversion value goes
325          * to zero (all digits were converted)
326          */
327         if (base == HEX) {
328                 while (pt >= str) {
329                         if ((digit = (val & 0xf)) < 10)
330                                 *pt-- = '0' + (char)digit;
331                         else
332                                 *pt-- = 'a' + (char)(digit - 10);
333                         if ((val = (val >> 4)) == (u_long)0)
334                                 break;
335                 }
336         } else {
337                 while (pt >= str) {
338                         *pt-- = '0' + (char)(val & 0x7);
339                         if ((val = (val >> 3)) == (u_long)0)
340                                 break;
341                 }
342         }
343
344         /*
345          * pad with leading ascii ZEROS. We return -1 if we ran out of space.
346          */
347         while (pt >= str)
348                 *pt-- = '0';
349         if (val != (u_long)0)
350                 return(-1);
351         return(0);
352 }
353
354 #ifndef NET2_STAT
355 /*
356  * asc_uqd()
357  *      convert hex/octal character string into a u_quad_t. We do not have to
358  *      check for overflow! (the headers in all supported formats are not large
359  *      enough to create an overflow).
360  *      NOTE: strings passed to us are NOT TERMINATED.
361  * Return:
362  *      u_quad_t value
363  */
364
365 #ifdef __STDC__
366 u_quad_t
367 asc_uqd(register char *str, int len, register int base)
368 #else
369 u_quad_t
370 asc_uqd(str, len, base)
371         register char *str;
372         int len;
373         register int base;
374 #endif
375 {
376         register char *stop;
377         u_quad_t tval = 0;
378
379         stop = str + len;
380
381         /*
382          * skip over leading blanks and zeros
383          */
384         while ((str < stop) && ((*str == ' ') || (*str == '0')))
385                 ++str;
386
387         /*
388          * for each valid digit, shift running value (tval) over to next digit
389          * and add next digit
390          */
391         if (base == HEX) {
392                 while (str < stop) {
393                         if ((*str >= '0') && (*str <= '9'))
394                                 tval = (tval << 4) + (*str++ - '0');
395                         else if ((*str >= 'A') && (*str <= 'F'))
396                                 tval = (tval << 4) + 10 + (*str++ - 'A');
397                         else if ((*str >= 'a') && (*str <= 'f'))
398                                 tval = (tval << 4) + 10 + (*str++ - 'a');
399                         else
400                                 break;
401                 }
402         } else {
403                 while ((str < stop) && (*str >= '0') && (*str <= '7'))
404                         tval = (tval << 3) + (*str++ - '0');
405         }
406         return(tval);
407 }
408
409 /*
410  * uqd_asc()
411  *      convert an u_quad_t into a hex/oct ascii string. pads with LEADING
412  *      ascii 0's to fill string completely
413  *      NOTE: the string created is NOT TERMINATED.
414  */
415
416 #ifdef __STDC__
417 int
418 uqd_asc(u_quad_t val, register char *str, register int len, register int base)
419 #else
420 int
421 uqd_asc(val, str, len, base)
422         u_quad_t val;
423         register char *str;
424         register int len;
425         register int base;
426 #endif
427 {
428         register char *pt;
429         u_quad_t digit;
430
431         /*
432          * WARNING str is not '\0' terminated by this routine
433          */
434         pt = str + len - 1;
435
436         /*
437          * do a tailwise conversion (start at right most end of string to place
438          * least significant digit). Keep shifting until conversion value goes
439          * to zero (all digits were converted)
440          */
441         if (base == HEX) {
442                 while (pt >= str) {
443                         if ((digit = (val & 0xf)) < 10)
444                                 *pt-- = '0' + (char)digit;
445                         else
446                                 *pt-- = 'a' + (char)(digit - 10);
447                         if ((val = (val >> 4)) == (u_quad_t)0)
448                                 break;
449                 }
450         } else {
451                 while (pt >= str) {
452                         *pt-- = '0' + (char)(val & 0x7);
453                         if ((val = (val >> 3)) == (u_quad_t)0)
454                                 break;
455                 }
456         }
457
458         /*
459          * pad with leading ascii ZEROS. We return -1 if we ran out of space.
460          */
461         while (pt >= str)
462                 *pt-- = '0';
463         if (val != (u_quad_t)0)
464                 return(-1);
465         return(0);
466 }
467 #endif