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