1/*	$NetBSD: printquota.c,v 1.5 2011/03/07 11:46:55 bouyer Exp $ */
2
3/*
4 * Copyright (c) 1980, 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Robert Elz at The University of Melbourne.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef lint
37__COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
38 The Regents of the University of California.  All rights reserved.");
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)quota.c	8.4 (Berkeley) 4/28/95";
44#else
45__RCSID("$NetBSD: printquota.c,v 1.5 2011/03/07 11:46:55 bouyer Exp $");
46#endif
47#endif /* not lint */
48
49#include <sys/param.h>
50#include <sys/types.h>
51
52#include <ctype.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <time.h>
57#include <unistd.h>
58#include <errno.h>
59#include <limits.h>
60#include <inttypes.h>
61
62#include "printquota.h"
63
64/*
65 * convert 64bit value to a printable string
66 */
67const char *
68intprt(char *buf, size_t len, uint64_t val, int flags, int hflag)
69{
70	if (val == UQUAD_MAX)
71		return (len > sizeof("unlimited")) ? "unlimited" : "-";
72
73	if (flags & HN_B)
74		val = dbtob(val);
75
76	if (hflag) {
77		(void)humanize_number(buf, len, (int64_t)val, "", HN_AUTOSCALE,
78		    flags);
79		return buf;
80	}
81	if (flags & HN_B) {
82		/* traditionnal display: blocks are in kilobytes */
83		val = val / 1024;
84	}
85	(void)snprintf(buf, len, "%" PRId64, val);
86	return buf;
87}
88
89/*
90 * Calculate the grace period and return a user-friendly string for it.
91 */
92#define MINUTE	60
93#define HOUR	(MINUTE * 60)
94#define DAY	(HOUR * 24)
95#define WEEK	(DAY * 7)
96#define MONTH	(DAY * 30)
97#define YEAR	(DAY * 355)
98
99const char *
100timeprt(char *buf, size_t len, time_t now, time_t seconds)
101{
102	time_t years, months, weeks, days, hours, minutes;
103
104	if (now > seconds)
105		return "none";
106
107	seconds -= now;
108
109	minutes = (seconds + MINUTE / 2) / MINUTE;
110	hours = (seconds + HOUR / 2) / HOUR;
111	days = (seconds + DAY / 2) / DAY;
112	years = (seconds + YEAR / 2) / YEAR;
113	months = (seconds + MONTH / 2) / MONTH;
114	weeks = (seconds + WEEK / 2) / WEEK;
115
116	if (years >= 2) {
117		(void)snprintf(buf, len, "%" PRId64 "years", years);
118		return buf;
119	}
120	if (weeks > 9) {
121		(void)snprintf(buf, len, "%" PRId64 "months", months);
122		return buf;
123	}
124	if (days > 9) {
125		(void)snprintf(buf, len, "%" PRId64 "weeks", weeks);
126		return buf;
127	}
128	if (hours > 36) {
129		(void)snprintf(buf, len, "%" PRId64 "days", days);
130		return buf;
131	}
132	if (minutes > 60) {
133		(void)snprintf(buf, len, "%2d:%d",
134		    (int)(minutes / 60), (int)(minutes % 60));
135		return buf;
136	}
137	(void)snprintf(buf, len, "%2d", (int)minutes);
138	return buf;
139}
140
141/*
142 * Calculate the grace period and return a precise string for it,
143 * either in seconds or in format xWyDzHtMuS
144 */
145const char *
146timepprt(char *buf, size_t len, time_t seconds, int hflag)
147{
148	ssize_t i = 0;
149
150	if (hflag == 0) {
151		(void)snprintf(buf, len, "%" PRId64, seconds);
152		return buf;
153	}
154
155	if ((seconds / WEEK) > 0) {
156		i += snprintf(buf + i, len - i, "%" PRId64 "W", seconds / WEEK);
157		seconds = seconds % WEEK;
158	}
159
160	if (len - i < 3 || seconds == 0)
161		return buf;
162
163	if ((seconds / DAY) > 0) {
164		i += snprintf(buf + i, len - i, "%" PRId64 "D", seconds / DAY);
165		seconds = seconds % DAY;
166	}
167
168	if (len - i < 4 || seconds == 0)
169		return buf;
170
171	if ((seconds / HOUR) > 0) {
172		i += snprintf(buf + i, len - i, "%" PRId64 "H", seconds / HOUR);
173		seconds = seconds % HOUR;
174	}
175
176	if (len - i < 4 || seconds == 0)
177		return buf;
178
179	if ((seconds / MINUTE) > 0) {
180		i += snprintf(buf + i , len - i, "%" PRId64 "M",
181		    seconds / MINUTE);
182		seconds = seconds % MINUTE;
183	}
184
185	if (len - i < 4 || seconds == 0)
186		return buf;
187
188	(void)snprintf(buf + i, len - i, "%" PRId64 "S", seconds);
189	return buf;
190}
191
192/*
193 * convert a string of the form xWyDzHtMuS, or plain decimal, to
194 * a time in seconds
195 */
196int
197timeprd(const char *str, time_t *valp)
198{
199	char buf[20];
200	char *cur, *next, *end;
201	time_t val= 0;
202
203	strncpy(buf, str, sizeof(buf));
204	next = buf;
205	cur = strsep(&next, "Ww");
206	if (next != NULL) {
207		val = strtoumax(cur, &end, 10) * WEEK;
208		if (end[0] != '\0')
209			return EINVAL;
210	} else
211		next = cur;
212	cur = strsep(&next, "Dd");
213	if (next != NULL) {
214		val += strtoumax(cur, &end, 10) * DAY;
215		if (end[0] != '\0')
216			return EINVAL;
217	} else
218		next = cur;
219	cur = strsep(&next, "Hh");
220	if (next != NULL) {
221		val += strtoumax(cur, &end, 10) * HOUR;
222		if (end[0] != '\0')
223			return EINVAL;
224	} else
225		next = cur;
226	cur = strsep(&next, "Mm");
227	if (next != NULL) {
228		val += strtoumax(cur, &end, 10) * MINUTE;
229		if (end[0] != '\0')
230			return EINVAL;
231	} else
232		next = cur;
233	cur = strsep(&next, "Ss");
234	val += strtoumax(cur, &end, 10);
235	if (end[0] != '\0')
236		return EINVAL;
237	*valp = val;
238	return 0;
239}
240
241/*
242 * convert a string to a uint64 value
243 */
244int
245intrd(char *str, uint64_t *val, u_int flags)
246{
247	char *last = &str[strlen(str) - 1];
248	int ret;
249
250	if (*last >= '0' && *last <= '9') {
251		/* no unit provided, use default */
252		errno = 0;
253		*val = strtoumax(str, NULL, 10);
254		if (flags & HN_B) {
255			/* in kb, convert to disk blocks */
256			*val = btodb(*val * 1024);
257		}
258
259		return errno;
260	}
261	if (strcmp(str, "-") == 0 || strcmp(str, "unlimited") == 0) {
262		*val = UQUAD_MAX;
263		return 0;
264	}
265	if (flags & HN_B) {
266		if (*last == 'B' || *last == 'b')
267			*last = '\0';
268	}
269	ret = dehumanize_number(str, (int64_t *)val);
270	if (flags & HN_B)
271		*val = btodb(*val);
272	return ret;
273}
274
275int
276alldigits(const char *s)
277{
278	unsigned char c;
279
280	c = *s++;
281	do {
282		if (!isdigit(c))
283			return 0;
284	} while ((c = *s++) != 0);
285	return 1;
286}
287