chiark / gitweb /
sd-id128: split UUID file read/write code into new id128-util.[ch]
[elogind.git] / src / libelogind / sd-id128 / id128-util.c
1 /***
2   This file is part of elogind.
3
4   Copyright 2016 Lennart Poettering
5
6   elogind is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   elogind is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with elogind; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <fcntl.h>
21
22 #include "fd-util.h"
23 #include "hexdecoct.h"
24 #include "id128-util.h"
25 #include "io-util.h"
26 #include "stdio-util.h"
27
28 char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
29         unsigned n, k = 0;
30
31         assert(s);
32
33         /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
34
35         for (n = 0; n < 16; n++) {
36
37                 if (IN_SET(n, 4, 6, 8, 10))
38                         s[k++] = '-';
39
40                 s[k++] = hexchar(id.bytes[n] >> 4);
41                 s[k++] = hexchar(id.bytes[n] & 0xF);
42         }
43
44         assert(k == 36);
45
46         s[k] = 0;
47
48         return s;
49 }
50
51 bool id128_is_valid(const char *s) {
52         size_t i, l;
53
54         assert(s);
55
56         l = strlen(s);
57         if (l == 32) {
58
59                 /* Plain formatted 128bit hex string */
60
61                 for (i = 0; i < l; i++) {
62                         char c = s[i];
63
64                         if (!(c >= '0' && c <= '9') &&
65                             !(c >= 'a' && c <= 'z') &&
66                             !(c >= 'A' && c <= 'Z'))
67                                 return false;
68                 }
69
70         } else if (l == 36) {
71
72                 /* Formatted UUID */
73
74                 for (i = 0; i < l; i++) {
75                         char c = s[i];
76
77                         if ((i == 8 || i == 13 || i == 18 || i == 23)) {
78                                 if (c != '-')
79                                         return false;
80                         } else {
81                                 if (!(c >= '0' && c <= '9') &&
82                                     !(c >= 'a' && c <= 'z') &&
83                                     !(c >= 'A' && c <= 'Z'))
84                                         return false;
85                         }
86                 }
87
88         } else
89                 return false;
90
91         return true;
92 }
93
94 int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
95         char buffer[36 + 2];
96         ssize_t l;
97
98         assert(fd >= 0);
99         assert(f < _ID128_FORMAT_MAX);
100
101         /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
102          * followed by a newline and nothing else. */
103
104         l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 33 or 37 chars */
105         if (l < 0)
106                 return (int) l;
107         if (l == 0) /* empty? */
108                 return -ENOMEDIUM;
109
110         if (l == 33) {
111                 if (f == ID128_UUID)
112                         return -EINVAL;
113
114                 if (buffer[32] != '\n')
115                         return -EINVAL;
116
117                 buffer[32] = 0;
118
119         } else if (l == 37) {
120                 if (f == ID128_PLAIN)
121                         return -EINVAL;
122
123                 if (buffer[36] != '\n')
124                         return -EINVAL;
125
126                 buffer[36] = 0;
127         } else
128                 return -EINVAL;
129
130         return sd_id128_from_string(buffer, ret);
131 }
132
133 int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
134         _cleanup_close_ int fd = -1;
135
136         fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
137         if (fd < 0)
138                 return -errno;
139
140         return id128_read_fd(fd, f, ret);
141 }
142
143 int id128_write_fd(int fd, Id128Format f, sd_id128_t id) {
144         char buffer[36 + 2];
145         size_t sz;
146
147         assert(fd >= 0);
148         assert(f < _ID128_FORMAT_MAX);
149
150         if (f != ID128_UUID) {
151                 sd_id128_to_string(id, buffer);
152                 buffer[32] = '\n';
153                 sz = 33;
154         } else {
155                 id128_to_uuid_string(id, buffer);
156                 buffer[36] = '\n';
157                 sz = 37;
158         }
159
160         return loop_write(fd, buffer, sz, false);
161 }
162
163 int id128_write(const char *p, Id128Format f, sd_id128_t id) {
164         _cleanup_close_ int fd = -1;
165
166         fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
167         if (fd < 0)
168                 return -errno;
169
170         return id128_write_fd(fd, f, id);
171 }