libfstools: properly label ext4 overlay
[project/fstools.git] / libubi / ubiutils-common.c
1 /*
2 * Copyright (C) 2007, 2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 /*
20 * This file contains various common stuff used by UBI utilities.
21 *
22 * Authors: Artem Bityutskiy
23 * Adrian Hunter
24 */
25
26 #define PROGRAM_NAME "ubiutils"
27
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include "libubi.h"
36
37 /**
38 * get_multiplier - convert size specifier to an integer multiplier.
39 * @str: the size specifier string
40 *
41 * This function parses the @str size specifier, which may be one of
42 * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
43 * size multiplier in case of success and %-1 in case of failure.
44 */
45 static int get_multiplier(const char *str)
46 {
47 if (!str)
48 return 1;
49
50 /* Remove spaces before the specifier */
51 while (*str == ' ' || *str == '\t')
52 str += 1;
53
54 if (!strcmp(str, "KiB"))
55 return 1024;
56 if (!strcmp(str, "MiB"))
57 return 1024 * 1024;
58 if (!strcmp(str, "GiB"))
59 return 1024 * 1024 * 1024;
60
61 return -1;
62 }
63
64 /**
65 * ubiutils_get_bytes - convert a string containing amount of bytes into an
66 * integer
67 * @str: string to convert
68 *
69 * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
70 * size specifiers. Returns positive amount of bytes in case of success and %-1
71 * in case of failure.
72 */
73 long long ubiutils_get_bytes(const char *str)
74 {
75 char *endp;
76 long long bytes = strtoull(str, &endp, 0);
77
78 if (endp == str || bytes < 0) {
79 fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
80 return -1;
81 }
82
83 if (*endp != '\0') {
84 int mult = get_multiplier(endp);
85
86 if (mult == -1) {
87 fprintf(stderr, "bad size specifier: \"%s\" - "
88 "should be 'KiB', 'MiB' or 'GiB'\n", endp);
89 return -1;
90 }
91 bytes *= mult;
92 }
93
94 return bytes;
95 }
96
97 /**
98 * ubiutils_print_bytes - print bytes.
99 * @bytes: variable to print
100 * @bracket: whether brackets have to be put or not
101 *
102 * This is a helper function which prints amount of bytes in a human-readable
103 * form, i.e., it prints the exact amount of bytes following by the approximate
104 * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
105 * is.
106 */
107 void ubiutils_print_bytes(long long bytes, int bracket)
108 {
109 const char *p;
110
111 if (bracket)
112 p = " (";
113 else
114 p = ", ";
115
116 printf("%lld bytes", bytes);
117
118 if (bytes > 1024 * 1024 * 1024)
119 printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
120 else if (bytes > 1024 * 1024)
121 printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
122 else if (bytes > 1024 && bytes != 0)
123 printf("%s%.1f KiB", p, (double)bytes / 1024);
124 else
125 return;
126
127 if (bracket)
128 printf(")");
129 }
130
131 /**
132 * ubiutils_print_text - print text and fold it.
133 * @stream: file stream to print to
134 * @text: text to print
135 * @width: maximum allowed text width
136 *
137 * Print text and fold it so that each line would not have more then @width
138 * characters.
139 */
140 void ubiutils_print_text(FILE *stream, const char *text, int width)
141 {
142 int pos, bpos = 0;
143 const char *p;
144 char line[1024];
145
146 if (width > 1023) {
147 fprintf(stream, "%s\n", text);
148 return;
149 }
150 p = text;
151 pos = 0;
152 while (p[pos]) {
153 while (!isspace(p[pos])) {
154 line[pos] = p[pos];
155 if (!p[pos])
156 break;
157 ++pos;
158 if (pos == width) {
159 line[pos] = '\0';
160 fprintf(stream, "%s\n", line);
161 p += pos;
162 pos = 0;
163 }
164 }
165 while (pos < width) {
166 line[pos] = p[pos];
167 if (!p[pos]) {
168 bpos = pos;
169 break;
170 }
171 if (isspace(p[pos]))
172 bpos = pos;
173 ++pos;
174 }
175 line[bpos] = '\0';
176 fprintf(stream, "%s\n", line);
177 p += bpos;
178 pos = 0;
179 while (p[pos] && isspace(p[pos]))
180 ++p;
181 }
182 }
183
184 /**
185 * ubiutils_srand - randomly seed the standard pseudo-random generator.
186 *
187 * This helper function seeds the standard libc pseudo-random generator with a
188 * more or less random value to make sure the 'rand()' call does not return the
189 * same sequence every time UBI utilities run. Returns zero in case of success
190 * and a %-1 in case of error.
191 */
192 int ubiutils_srand(void)
193 {
194 struct timeval tv;
195 struct timezone tz;
196 unsigned int seed;
197
198 /*
199 * Just assume that a combination of the PID + current time is a
200 * reasonably random number.
201 */
202 if (gettimeofday(&tv, &tz))
203 return -1;
204
205 seed = (unsigned int)tv.tv_sec;
206 seed += (unsigned int)tv.tv_usec;
207 seed *= getpid();
208 seed %= RAND_MAX;
209 srand(seed);
210 return 0;
211 }