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