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