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