~ubuntu-branches/ubuntu/vivid/lvm2/vivid

« back to all changes in this revision

Viewing changes to libdm/libdm-string.c

  • Committer: Package Import Robot
  • Author(s): Bastian Blank
  • Date: 2012-05-01 20:27:50 UTC
  • mto: (3.1.23 sid)
  • mto: This revision was merged to the branch mainline in revision 72.
  • Revision ID: package-import@ubuntu.com-20120501202750-gljjjtblowwq9mw8
Tags: upstream-2.02.95
ImportĀ upstreamĀ versionĀ 2.02.95

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved.
 
2
 * Copyright (C) 2006-2012 Red Hat, Inc. All rights reserved.
3
3
 *
4
4
 * This file is part of the device-mapper userspace tools.
5
5
 *
13
13
 */
14
14
 
15
15
#include "dmlib.h"
16
 
#include "libdevmapper.h"
17
16
 
18
17
#include <ctype.h>
19
18
 
132
131
 
133
132
int dm_asprintf(char **result, const char *format, ...)
134
133
{
135
 
        int n, ok = 0, size = 32;
 
134
        int i, n, size = 16;
136
135
        va_list ap;
137
136
        char *buf = dm_malloc(size);
138
137
 
141
140
        if (!buf)
142
141
                return -1;
143
142
 
144
 
        while (!ok) {
 
143
        for (i = 0;; i++) {
145
144
                va_start(ap, format);
146
145
                n = vsnprintf(buf, size, format, ap);
147
146
                va_end(ap);
148
147
 
149
148
                if (0 <= n && n < size)
150
 
                        ok = 1;
151
 
                else {
 
149
                        break;
 
150
 
 
151
                dm_free(buf);
 
152
                /* Up to glibc 2.0.6 returns -1 */
 
153
                size = (n < 0) ? size * 2 : n + 1;
 
154
                if (!(buf = dm_malloc(size)))
 
155
                        return -1;
 
156
        }
 
157
 
 
158
        if (i > 1) {
 
159
                /* Reallocating more then once? */
 
160
                if (!(*result = dm_strdup(buf))) {
152
161
                        dm_free(buf);
153
 
                        size *= 2;
154
 
                        buf = dm_malloc(size);
155
 
                        if (!buf)
156
 
                                return -1;
 
162
                        return -1;
157
163
                }
158
 
        }
 
164
                dm_free(buf);
 
165
        } else
 
166
                *result = buf;
159
167
 
160
 
        *result = dm_strdup(buf);
161
 
        dm_free(buf);
162
168
        return n + 1;
163
169
}
 
170
 
 
171
/*
 
172
 * Count occurences of 'c' in 'str' until we reach a null char.
 
173
 *
 
174
 * Returns:
 
175
 *  len - incremented for each char we encounter.
 
176
 *  count - number of occurrences of 'c' and 'c2'.
 
177
 */
 
178
static void _count_chars(const char *str, size_t *len, int *count,
 
179
                         const int c1, const int c2)
 
180
{
 
181
        const char *ptr;
 
182
 
 
183
        for (ptr = str; *ptr; ptr++, (*len)++)
 
184
                if (*ptr == c1 || *ptr == c2)
 
185
                        (*count)++;
 
186
}
 
187
 
 
188
/*
 
189
 * Count occurrences of 'c' in 'str' of length 'size'.
 
190
 *
 
191
 * Returns:
 
192
 *   Number of occurrences of 'c'
 
193
 */
 
194
unsigned dm_count_chars(const char *str, size_t len, const int c)
 
195
{
 
196
        size_t i;
 
197
        unsigned count = 0;
 
198
 
 
199
        for (i = 0; i < len; i++)
 
200
                if (str[i] == c)
 
201
                        count++;
 
202
 
 
203
        return count;
 
204
}
 
205
 
 
206
/*
 
207
 * Length of string after escaping double quotes and backslashes.
 
208
 */
 
209
size_t dm_escaped_len(const char *str)
 
210
{
 
211
        size_t len = 1;
 
212
        int count = 0;
 
213
 
 
214
        _count_chars(str, &len, &count, '\"', '\\');
 
215
 
 
216
        return count + len;
 
217
}
 
218
 
 
219
/*
 
220
 * Copies a string, quoting orig_char with quote_char.
 
221
 * Optionally also quote quote_char.
 
222
 */
 
223
static void _quote_characters(char **out, const char *src,
 
224
                              const int orig_char, const int quote_char,
 
225
                              int quote_quote_char)
 
226
{
 
227
        while (*src) {
 
228
                if (*src == orig_char ||
 
229
                    (*src == quote_char && quote_quote_char))
 
230
                        *(*out)++ = quote_char;
 
231
 
 
232
                *(*out)++ = *src++;
 
233
        }
 
234
}
 
235
 
 
236
static void _unquote_one_character(char *src, const char orig_char,
 
237
                                   const char quote_char)
 
238
{
 
239
        char *out;
 
240
        char s, n;
 
241
 
 
242
        /* Optimise for the common case where no changes are needed. */
 
243
        while ((s = *src++)) {
 
244
                if (s == quote_char &&
 
245
                    ((n = *src) == orig_char || n == quote_char)) {
 
246
                        out = src++;
 
247
                        *(out - 1) = n;
 
248
 
 
249
                        while ((s = *src++)) {
 
250
                                if (s == quote_char &&
 
251
                                    ((n = *src) == orig_char || n == quote_char)) {
 
252
                                        s = n;
 
253
                                        src++;
 
254
                                }
 
255
                                *out = s;
 
256
                                out++;
 
257
                        }
 
258
 
 
259
                        *out = '\0';
 
260
                        return;
 
261
                }
 
262
        }
 
263
}
 
264
 
 
265
/*
 
266
 * Unquote each character given in orig_char array and unquote quote_char
 
267
 * as well. Also save the first occurrence of each character from orig_char
 
268
 * that was found unquoted in arr_substr_first_unquoted array. This way we can
 
269
 * process several characters in one go.
 
270
 */
 
271
static void _unquote_characters(char *src, const char *orig_chars,
 
272
                                size_t num_orig_chars,
 
273
                                const char quote_char,
 
274
                                char *arr_substr_first_unquoted[])
 
275
{
 
276
        char *out = src;
 
277
        char c, s, n;
 
278
        unsigned i;
 
279
 
 
280
        while ((s = *src++)) {
 
281
                for (i = 0; i < num_orig_chars; i++) {
 
282
                        c = orig_chars[i];
 
283
                        if (s == quote_char &&
 
284
                            ((n = *src) == c || n == quote_char)) {
 
285
                                s = n;
 
286
                                src++;
 
287
                                break;
 
288
                        }
 
289
                        if (arr_substr_first_unquoted && (s == c) &&
 
290
                            !arr_substr_first_unquoted[i])
 
291
                                arr_substr_first_unquoted[i] = out;
 
292
                };
 
293
                *out++ = s;
 
294
        }
 
295
 
 
296
        *out = '\0';
 
297
}
 
298
 
 
299
/*
 
300
 * Copies a string, quoting hyphens with hyphens.
 
301
 */
 
302
static void _quote_hyphens(char **out, const char *src)
 
303
{
 
304
        _quote_characters(out, src, '-', '-', 0);
 
305
}
 
306
 
 
307
/*
 
308
 * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
 
309
 */
 
310
char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
 
311
                       const char *lvname, const char *layer)
 
312
{
 
313
        size_t len = 1;
 
314
        int hyphens = 1;
 
315
        char *r, *out;
 
316
 
 
317
        _count_chars(vgname, &len, &hyphens, '-', 0);
 
318
        _count_chars(lvname, &len, &hyphens, '-', 0);
 
319
 
 
320
        if (layer && *layer) {
 
321
                _count_chars(layer, &len, &hyphens, '-', 0);
 
322
                hyphens++;
 
323
        }
 
324
 
 
325
        len += hyphens;
 
326
 
 
327
        if (!(r = dm_pool_alloc(mem, len))) {
 
328
                log_error("build_dm_name: Allocation failed for %" PRIsize_t
 
329
                          " for %s %s %s.", len, vgname, lvname, layer);
 
330
                return NULL;
 
331
        }
 
332
 
 
333
        out = r;
 
334
        _quote_hyphens(&out, vgname);
 
335
        *out++ = '-';
 
336
        _quote_hyphens(&out, lvname);
 
337
 
 
338
        if (layer && *layer) {
 
339
                /* No hyphen if the layer begins with _ e.g. _mlog */
 
340
                if (*layer != '_')
 
341
                        *out++ = '-';
 
342
                _quote_hyphens(&out, layer);
 
343
        }
 
344
        *out = '\0';
 
345
 
 
346
        return r;
 
347
}
 
348
 
 
349
char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char *lvid, const char *layer)
 
350
{
 
351
        char *dmuuid;
 
352
        size_t len;
 
353
 
 
354
        if (!layer)
 
355
                layer = "";
 
356
 
 
357
        len = strlen(uuid_prefix) + strlen(lvid) + strlen(layer) + 2;
 
358
 
 
359
        if (!(dmuuid = dm_pool_alloc(mem, len))) {
 
360
                log_error("build_dm_name: Allocation failed for %" PRIsize_t
 
361
                          " %s %s.", len, lvid, layer);
 
362
                return NULL;
 
363
        }
 
364
 
 
365
        sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
 
366
 
 
367
        return dmuuid;
 
368
}
 
369
 
 
370
/*
 
371
 * Copies a string, quoting double quotes with backslashes.
 
372
 */
 
373
char *dm_escape_double_quotes(char *out, const char *src)
 
374
{
 
375
        char *buf = out;
 
376
 
 
377
        _quote_characters(&buf, src, '\"', '\\', 1);
 
378
        *buf = '\0';
 
379
 
 
380
        return out;
 
381
}
 
382
 
 
383
/*
 
384
 * Undo quoting in situ.
 
385
 */
 
386
void dm_unescape_double_quotes(char *src)
 
387
{
 
388
        _unquote_one_character(src, '\"', '\\');
 
389
}
 
390
 
 
391
/*
 
392
 * Unescape colons and "at" signs in situ and save the substrings
 
393
 * starting at the position of the first unescaped colon and the
 
394
 * first unescaped "at" sign. This is normally used to unescape
 
395
 * device names used as PVs.
 
396
 */
 
397
void dm_unescape_colons_and_at_signs(char *src,
 
398
                                     char **substr_first_unquoted_colon,
 
399
                                     char **substr_first_unquoted_at_sign)
 
400
{
 
401
        const char *orig_chars = ":@";
 
402
        char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
 
403
 
 
404
        _unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
 
405
 
 
406
        if (substr_first_unquoted_colon)
 
407
                *substr_first_unquoted_colon = arr_substr_first_unquoted[0];
 
408
 
 
409
        if (substr_first_unquoted_at_sign)
 
410
                *substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
 
411
}
 
412
 
 
413
int dm_strncpy(char *dest, const char *src, size_t n)
 
414
{
 
415
        if (memccpy(dest, src, 0, n))
 
416
                return 1;
 
417
 
 
418
        if (n > 0)
 
419
                dest[n - 1] = '\0';
 
420
 
 
421
        return 0;
 
422
}