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