]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/unit-name.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / unit-name.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
9e2f7c11
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
9e2f7c11
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
9e2f7c11 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
9e2f7c11
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
11c3a366
TA
22#include <stddef.h>
23#include <stdint.h>
24#include <stdlib.h>
9e2f7c11
LP
25#include <string.h>
26
b5efdb8a 27#include "alloc-util.h"
2aaafcf5 28#include "glob-util.h"
8b43440b 29#include "hexdecoct.h"
93cc7779 30#include "path-util.h"
07630cea 31#include "string-util.h"
b9a33026 32#include "strv.h"
07630cea 33#include "unit-name.h"
9e2f7c11 34
2aaafcf5 35/* Characters valid in a unit name. */
9e2f7c11 36#define VALID_CHARS \
2aaafcf5
LP
37 DIGITS \
38 LETTERS \
4f2d528d 39 ":-_.\\"
9e2f7c11 40
2aaafcf5
LP
41/* The same, but also permits the single @ character that may appear */
42#define VALID_CHARS_WITH_AT \
43 "@" \
44 VALID_CHARS
45
46/* All chars valid in a unit name glob */
47#define VALID_CHARS_GLOB \
48 VALID_CHARS_WITH_AT \
49 "[]!-*?"
50
7410616c 51bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
9e2f7c11
LP
52 const char *e, *i, *at;
53
7410616c 54 assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
9e2f7c11 55
7410616c
LP
56 if (_unlikely_(flags == 0))
57 return false;
9e2f7c11 58
b9a33026
LP
59 if (isempty(n))
60 return false;
61
9e2f7c11
LP
62 if (strlen(n) >= UNIT_NAME_MAX)
63 return false;
64
71fad675
LP
65 e = strrchr(n, '.');
66 if (!e || e == n)
9e2f7c11
LP
67 return false;
68
5f739699
LP
69 if (unit_type_from_string(e + 1) < 0)
70 return false;
71
9e2f7c11
LP
72 for (i = n, at = NULL; i < e; i++) {
73
74 if (*i == '@' && !at)
75 at = i;
76
77 if (!strchr("@" VALID_CHARS, *i))
78 return false;
79 }
80
7410616c
LP
81 if (at == n)
82 return false;
9e2f7c11 83
7410616c
LP
84 if (flags & UNIT_NAME_PLAIN)
85 if (!at)
86 return true;
9e2f7c11 87
7410616c
LP
88 if (flags & UNIT_NAME_INSTANCE)
89 if (at && e > at + 1)
90 return true;
91
92 if (flags & UNIT_NAME_TEMPLATE)
93 if (at && e == at + 1)
94 return true;
95
96 return false;
97}
98
99bool unit_prefix_is_valid(const char *p) {
100
101 /* We don't allow additional @ in the prefix string */
102
103 if (isempty(p))
104 return false;
105
106 return in_charset(p, VALID_CHARS);
9e2f7c11
LP
107}
108
109bool unit_instance_is_valid(const char *i) {
9e2f7c11
LP
110
111 /* The max length depends on the length of the string, so we
112 * don't really check this here. */
113
b9a33026 114 if (isempty(i))
9e2f7c11
LP
115 return false;
116
117 /* We allow additional @ in the instance string, we do not
118 * allow them in the prefix! */
119
b9a33026 120 return in_charset(i, "@" VALID_CHARS);
9e2f7c11
LP
121}
122
7410616c
LP
123bool unit_suffix_is_valid(const char *s) {
124 if (isempty(s))
125 return false;
9e2f7c11 126
7410616c
LP
127 if (s[0] != '.')
128 return false;
9e2f7c11 129
7410616c 130 if (unit_type_from_string(s + 1) < 0)
9e2f7c11
LP
131 return false;
132
7410616c
LP
133 return true;
134}
135
136int unit_name_to_prefix(const char *n, char **ret) {
137 const char *p;
138 char *s;
139
140 assert(n);
141 assert(ret);
142
143 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
144 return -EINVAL;
145
146 p = strchr(n, '@');
147 if (!p)
148 p = strrchr(n, '.');
149
150 assert_se(p);
151
152 s = strndup(n, p - n);
153 if (!s)
154 return -ENOMEM;
155
156 *ret = s;
157 return 0;
9e2f7c11
LP
158}
159
160int unit_name_to_instance(const char *n, char **instance) {
161 const char *p, *d;
162 char *i;
163
164 assert(n);
165 assert(instance);
166
7410616c
LP
167 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
168 return -EINVAL;
169
9e2f7c11 170 /* Everything past the first @ and before the last . is the instance */
35eb6b12
LP
171 p = strchr(n, '@');
172 if (!p) {
9e2f7c11
LP
173 *instance = NULL;
174 return 0;
175 }
176
7410616c
LP
177 p++;
178
179 d = strrchr(p, '.');
b9a33026
LP
180 if (!d)
181 return -EINVAL;
9e2f7c11 182
7410616c 183 i = strndup(p, d-p);
35eb6b12 184 if (!i)
9e2f7c11
LP
185 return -ENOMEM;
186
187 *instance = i;
b9a33026 188 return 1;
9e2f7c11
LP
189}
190
7410616c 191int unit_name_to_prefix_and_instance(const char *n, char **ret) {
9e2f7c11 192 const char *d;
7410616c 193 char *s;
9e2f7c11
LP
194
195 assert(n);
7410616c
LP
196 assert(ret);
197
198 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
199 return -EINVAL;
9e2f7c11 200
7410616c
LP
201 d = strrchr(n, '.');
202 if (!d)
203 return -EINVAL;
204
205 s = strndup(n, d - n);
206 if (!s)
207 return -ENOMEM;
208
209 *ret = s;
210 return 0;
9e2f7c11
LP
211}
212
7410616c
LP
213UnitType unit_name_to_type(const char *n) {
214 const char *e;
9e2f7c11 215
b9a33026
LP
216 assert(n);
217
7410616c
LP
218 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
219 return _UNIT_TYPE_INVALID;
9e2f7c11 220
7410616c
LP
221 assert_se(e = strrchr(n, '.'));
222
223 return unit_type_from_string(e + 1);
9e2f7c11
LP
224}
225
7410616c
LP
226int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
227 char *e, *s;
9e2f7c11
LP
228 size_t a, b;
229
230 assert(n);
9e2f7c11 231 assert(suffix);
7410616c
LP
232 assert(ret);
233
234 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
235 return -EINVAL;
236
237 if (!unit_suffix_is_valid(suffix))
238 return -EINVAL;
9e2f7c11
LP
239
240 assert_se(e = strrchr(n, '.'));
7410616c 241
9e2f7c11
LP
242 a = e - n;
243 b = strlen(suffix);
244
7410616c
LP
245 s = new(char, a + b + 1);
246 if (!s)
247 return -ENOMEM;
9e2f7c11 248
7410616c
LP
249 strcpy(mempcpy(s, n, a), suffix);
250 *ret = s;
251
252 return 0;
9e2f7c11
LP
253}
254
7410616c
LP
255int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
256 char *s;
257
9e2f7c11 258 assert(prefix);
9e2f7c11 259 assert(suffix);
7410616c
LP
260 assert(ret);
261
262 if (!unit_prefix_is_valid(prefix))
263 return -EINVAL;
264
265 if (instance && !unit_instance_is_valid(instance))
266 return -EINVAL;
267
268 if (!unit_suffix_is_valid(suffix))
269 return -EINVAL;
9e2f7c11
LP
270
271 if (!instance)
7410616c
LP
272 s = strappend(prefix, suffix);
273 else
605405c6 274 s = strjoin(prefix, "@", instance, suffix);
7410616c
LP
275 if (!s)
276 return -ENOMEM;
9e2f7c11 277
7410616c
LP
278 *ret = s;
279 return 0;
9e2f7c11
LP
280}
281
4b712653 282static char *do_escape_char(char c, char *t) {
b9a33026
LP
283 assert(t);
284
4b712653
KS
285 *(t++) = '\\';
286 *(t++) = 'x';
287 *(t++) = hexchar(c >> 4);
288 *(t++) = hexchar(c);
b9a33026 289
4b712653
KS
290 return t;
291}
292
293static char *do_escape(const char *f, char *t) {
9e2f7c11
LP
294 assert(f);
295 assert(t);
296
4b712653
KS
297 /* do not create units with a leading '.', like for "/.dotdir" mount points */
298 if (*f == '.') {
299 t = do_escape_char(*f, t);
300 f++;
301 }
302
9e2f7c11
LP
303 for (; *f; f++) {
304 if (*f == '/')
8d567588 305 *(t++) = '-';
4c701096 306 else if (IN_SET(*f, '-', '\\') || !strchr(VALID_CHARS, *f))
4b712653
KS
307 t = do_escape_char(*f, t);
308 else
9e2f7c11
LP
309 *(t++) = *f;
310 }
311
312 return t;
313}
314
9e2f7c11
LP
315char *unit_name_escape(const char *f) {
316 char *r, *t;
317
b9a33026
LP
318 assert(f);
319
b0193f1c
LP
320 r = new(char, strlen(f)*4+1);
321 if (!r)
9e2f7c11
LP
322 return NULL;
323
324 t = do_escape(f, r);
325 *t = 0;
326
327 return r;
9e2f7c11
LP
328}
329
7410616c
LP
330int unit_name_unescape(const char *f, char **ret) {
331 _cleanup_free_ char *r = NULL;
332 char *t;
9e2f7c11
LP
333
334 assert(f);
335
b0193f1c
LP
336 r = strdup(f);
337 if (!r)
7410616c 338 return -ENOMEM;
9e2f7c11
LP
339
340 for (t = r; *f; f++) {
8d567588 341 if (*f == '-')
9e2f7c11
LP
342 *(t++) = '/';
343 else if (*f == '\\') {
344 int a, b;
345
7410616c
LP
346 if (f[1] != 'x')
347 return -EINVAL;
348
349 a = unhexchar(f[2]);
350 if (a < 0)
351 return -EINVAL;
352
353 b = unhexchar(f[3]);
354 if (b < 0)
355 return -EINVAL;
356
93c47472 357 *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
7410616c 358 f += 3;
9e2f7c11
LP
359 } else
360 *(t++) = *f;
361 }
362
363 *t = 0;
364
7410616c
LP
365 *ret = r;
366 r = NULL;
367
368 return 0;
9e2f7c11
LP
369}
370
7410616c
LP
371int unit_name_path_escape(const char *f, char **ret) {
372 char *p, *s;
35eb6b12
LP
373
374 assert(f);
7410616c 375 assert(ret);
35eb6b12 376
7410616c 377 p = strdupa(f);
35eb6b12 378 if (!p)
7410616c 379 return -ENOMEM;
35eb6b12
LP
380
381 path_kill_slashes(p);
382
b9a33026 383 if (STR_IN_SET(p, "/", ""))
7410616c
LP
384 s = strdup("-");
385 else {
7410616c
LP
386 if (!path_is_safe(p))
387 return -EINVAL;
35eb6b12 388
7410616c 389 /* Truncate trailing slashes */
7546145e 390 delete_trailing_chars(p, "/");
35eb6b12 391
7410616c 392 /* Truncate leading slashes */
7546145e 393 p = skip_leading_chars(p, "/");
35eb6b12 394
7410616c 395 s = unit_name_escape(p);
35eb6b12 396 }
7410616c
LP
397 if (!s)
398 return -ENOMEM;
35eb6b12 399
7410616c
LP
400 *ret = s;
401 return 0;
35eb6b12
LP
402}
403
7410616c 404int unit_name_path_unescape(const char *f, char **ret) {
93c47472 405 char *s;
7410616c 406 int r;
9e2f7c11 407
7410616c 408 assert(f);
9e2f7c11 409
93c47472
LP
410 if (isempty(f))
411 return -EINVAL;
412
7410616c
LP
413 if (streq(f, "-")) {
414 s = strdup("/");
415 if (!s)
416 return -ENOMEM;
93c47472
LP
417 } else {
418 char *w;
6ef9eeed 419
93c47472
LP
420 r = unit_name_unescape(f, &w);
421 if (r < 0)
422 return r;
29283ea4 423
93c47472
LP
424 /* Don't accept trailing or leading slashes */
425 if (startswith(w, "/") || endswith(w, "/")) {
426 free(w);
427 return -EINVAL;
428 }
29283ea4 429
93c47472
LP
430 /* Prefix a slash again */
431 s = strappend("/", w);
7410616c 432 free(w);
93c47472
LP
433 if (!s)
434 return -ENOMEM;
435
436 if (!path_is_safe(s)) {
437 free(s);
438 return -EINVAL;
439 }
7410616c 440 }
6ef9eeed 441
93c47472
LP
442 if (ret)
443 *ret = s;
444 else
445 free(s);
446
7410616c 447 return 0;
29283ea4
MS
448}
449
7410616c 450int unit_name_replace_instance(const char *f, const char *i, char **ret) {
9e2f7c11 451 const char *p, *e;
7410616c 452 char *s;
8556879e 453 size_t a, b;
9e2f7c11
LP
454
455 assert(f);
b9a33026 456 assert(i);
7410616c 457 assert(ret);
9e2f7c11 458
7410616c
LP
459 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
460 return -EINVAL;
461 if (!unit_instance_is_valid(i))
462 return -EINVAL;
9e2f7c11 463
7410616c
LP
464 assert_se(p = strchr(f, '@'));
465 assert_se(e = strrchr(f, '.'));
9e2f7c11 466
8556879e
LP
467 a = p - f;
468 b = strlen(i);
9e2f7c11 469
7410616c
LP
470 s = new(char, a + 1 + b + strlen(e) + 1);
471 if (!s)
472 return -ENOMEM;
9e2f7c11 473
7410616c
LP
474 strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
475
476 *ret = s;
477 return 0;
9e2f7c11
LP
478}
479
7410616c 480int unit_name_template(const char *f, char **ret) {
9e2f7c11 481 const char *p, *e;
7410616c 482 char *s;
9e2f7c11
LP
483 size_t a;
484
b9a33026 485 assert(f);
7410616c 486 assert(ret);
b9a33026 487
7410616c
LP
488 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
489 return -EINVAL;
9e2f7c11 490
7410616c
LP
491 assert_se(p = strchr(f, '@'));
492 assert_se(e = strrchr(f, '.'));
b9a33026
LP
493
494 a = p - f;
9e2f7c11 495
7410616c
LP
496 s = new(char, a + 1 + strlen(e) + 1);
497 if (!s)
498 return -ENOMEM;
9e2f7c11 499
7410616c
LP
500 strcpy(mempcpy(s, f, a + 1), e);
501
502 *ret = s;
503 return 0;
9e2f7c11 504}
a16e1123 505
7410616c 506int unit_name_from_path(const char *path, const char *suffix, char **ret) {
58d08142 507 _cleanup_free_ char *p = NULL;
7410616c
LP
508 char *s = NULL;
509 int r;
5ffceb2f 510
a16e1123
LP
511 assert(path);
512 assert(suffix);
7410616c 513 assert(ret);
a16e1123 514
7410616c
LP
515 if (!unit_suffix_is_valid(suffix))
516 return -EINVAL;
5ffceb2f 517
7410616c
LP
518 r = unit_name_path_escape(path, &p);
519 if (r < 0)
520 return r;
521
522 s = strappend(p, suffix);
523 if (!s)
524 return -ENOMEM;
525
526 *ret = s;
527 return 0;
a16e1123
LP
528}
529
7410616c 530int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
58d08142 531 _cleanup_free_ char *p = NULL;
7410616c
LP
532 char *s;
533 int r;
9fff8a1f 534
35eb6b12 535 assert(prefix);
9fff8a1f
LP
536 assert(path);
537 assert(suffix);
7410616c 538 assert(ret);
9fff8a1f 539
7410616c
LP
540 if (!unit_prefix_is_valid(prefix))
541 return -EINVAL;
542
543 if (!unit_suffix_is_valid(suffix))
544 return -EINVAL;
545
546 r = unit_name_path_escape(path, &p);
547 if (r < 0)
548 return r;
549
605405c6 550 s = strjoin(prefix, "@", p, suffix);
7410616c
LP
551 if (!s)
552 return -ENOMEM;
9fff8a1f 553
7410616c
LP
554 *ret = s;
555 return 0;
9fff8a1f
LP
556}
557
7410616c
LP
558int unit_name_to_path(const char *name, char **ret) {
559 _cleanup_free_ char *prefix = NULL;
560 int r;
a16e1123
LP
561
562 assert(name);
563
7410616c
LP
564 r = unit_name_to_prefix(name, &prefix);
565 if (r < 0)
566 return r;
a16e1123 567
7410616c 568 return unit_name_path_unescape(prefix, ret);
9fc50704 569}
48899192 570
7410616c
LP
571static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
572 const char *valid_chars;
573
574 assert(f);
575 assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
576 assert(t);
577
578 /* We'll only escape the obvious characters here, to play
579 * safe. */
580
2aaafcf5 581 valid_chars = allow_globs == UNIT_NAME_GLOB ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT;
7410616c
LP
582
583 for (; *f; f++) {
584 if (*f == '/')
585 *(t++) = '-';
586 else if (!strchr(valid_chars, *f))
587 t = do_escape_char(*f, t);
588 else
589 *(t++) = *f;
590 }
591
592 return t;
593}
594
e3e0314b 595/**
5e03c6e3
ZJS
596 * Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
597 * /blah/blah is converted to blah-blah.mount, anything else is left alone,
598 * except that @suffix is appended if a valid unit suffix is not present.
599 *
b938cb90 600 * If @allow_globs, globs characters are preserved. Otherwise, they are escaped.
e3e0314b 601 */
7410616c
LP
602int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
603 char *s, *t;
604 int r;
b0193f1c
LP
605
606 assert(name);
5e03c6e3 607 assert(suffix);
7410616c 608 assert(ret);
b0193f1c 609
7410616c
LP
610 if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
611 return -EINVAL;
b0193f1c 612
7410616c
LP
613 if (!unit_suffix_is_valid(suffix))
614 return -EINVAL;
b0193f1c 615
2aaafcf5
LP
616 /* Already a fully valid unit name? If so, no mangling is necessary... */
617 if (unit_name_is_valid(name, UNIT_NAME_ANY))
618 goto good;
1dcf6065 619
2aaafcf5
LP
620 /* Already a fully valid globbing expression? If so, no mangling is necessary either... */
621 if (allow_globs == UNIT_NAME_GLOB &&
622 string_is_glob(name) &&
623 in_charset(name, VALID_CHARS_GLOB))
624 goto good;
1dcf6065 625
7410616c
LP
626 if (is_device_path(name)) {
627 r = unit_name_from_path(name, ".device", ret);
628 if (r >= 0)
629 return 1;
630 if (r != -EINVAL)
631 return r;
632 }
1dcf6065 633
7410616c
LP
634 if (path_is_absolute(name)) {
635 r = unit_name_from_path(name, ".mount", ret);
636 if (r >= 0)
637 return 1;
638 if (r != -EINVAL)
639 return r;
640 }
1dcf6065 641
7410616c
LP
642 s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
643 if (!s)
644 return -ENOMEM;
5f739699 645
7410616c
LP
646 t = do_escape_mangle(name, allow_globs, s);
647 *t = 0;
5f739699 648
2aaafcf5
LP
649 /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a
650 * valid glob. */
651 if ((allow_globs != UNIT_NAME_GLOB || !string_is_glob(s)) && unit_name_to_type(s) < 0)
7410616c 652 strcpy(t, suffix);
5f739699 653
7410616c
LP
654 *ret = s;
655 return 1;
2aaafcf5
LP
656
657good:
658 s = strdup(name);
659 if (!s)
660 return -ENOMEM;
661
662 *ret = s;
663 return 0;
5f739699 664}
fb6becb4 665
93c47472
LP
666int slice_build_parent_slice(const char *slice, char **ret) {
667 char *s, *dash;
2fc09a9c 668 int r;
93c47472
LP
669
670 assert(slice);
671 assert(ret);
672
673 if (!slice_name_is_valid(slice))
674 return -EINVAL;
675
676 if (streq(slice, "-.slice")) {
677 *ret = NULL;
678 return 0;
679 }
680
681 s = strdup(slice);
682 if (!s)
683 return -ENOMEM;
684
685 dash = strrchr(s, '-');
686 if (dash)
687 strcpy(dash, ".slice");
688 else {
2fc09a9c 689 r = free_and_strdup(&s, "-.slice");
8e542fcd
DM
690 if (r < 0) {
691 free(s);
2fc09a9c 692 return r;
8e542fcd 693 }
93c47472
LP
694 }
695
696 *ret = s;
697 return 1;
698}
699
7410616c
LP
700int slice_build_subslice(const char *slice, const char*name, char **ret) {
701 char *subslice;
fb6becb4
LP
702
703 assert(slice);
704 assert(name);
7410616c
LP
705 assert(ret);
706
93c47472 707 if (!slice_name_is_valid(slice))
7410616c
LP
708 return -EINVAL;
709
710 if (!unit_prefix_is_valid(name))
711 return -EINVAL;
fb6becb4
LP
712
713 if (streq(slice, "-.slice"))
7410616c 714 subslice = strappend(name, ".slice");
fb6becb4
LP
715 else {
716 char *e;
717
93c47472 718 assert_se(e = endswith(slice, ".slice"));
fb6becb4 719
7410616c
LP
720 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
721 if (!subslice)
fb6becb4
LP
722 return -ENOMEM;
723
7410616c 724 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
fb6becb4
LP
725 }
726
7410616c 727 *ret = subslice;
fb6becb4
LP
728 return 0;
729}
cb87a73b 730
93c47472
LP
731bool slice_name_is_valid(const char *name) {
732 const char *p, *e;
733 bool dash = false;
734
735 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
736 return false;
737
738 if (streq(name, "-.slice"))
739 return true;
740
741 e = endswith(name, ".slice");
742 if (!e)
743 return false;
744
745 for (p = name; p < e; p++) {
746
747 if (*p == '-') {
748
749 /* Don't allow initial dash */
750 if (p == name)
751 return false;
752
753 /* Don't allow multiple dashes */
754 if (dash)
755 return false;
756
757 dash = true;
758 } else
759 dash = false;
760 }
761
762 /* Don't allow trailing hash */
763 if (dash)
764 return false;
765
766 return true;
767}