source: freewrt/tools/paxmirabilis/src/gen_subs.c@ 0bb5b95

freewrt_2_0
Last change on this file since 0bb5b95 was a569125, checked in by Thorsten Glaser <tg@…>, 14 years ago

even FreeWRT 1.0-stable deserves paxmirabilis-20120216 compiled with LTO ☺

git-svn-id: svn://www.freewrt.org/branches/freewrt_1_0@3981 afb5a338-a214-0410-bd46-81f09a774fd1

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