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