1 /*
2 ** OSSP uuid - Universally Unique Identifier
3 ** Copyright (c) 2004-2008 Ralf S. Engelschall <rse@engelschall.com>
4 ** Copyright (c) 2004-2008 The OSSP Project <http://www.ossp.org/>
5 **
6 ** This file is part of OSSP uuid, a library for the generation
7 ** of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
8 **
9 ** Permission to use, copy, modify, and distribute this software for
10 ** any purpose with or without fee is hereby granted, provided that
11 ** the above copyright notice and this permission notice appear in all
12 ** copies.
13 **
14 ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
15 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
18 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
21 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 **
27 ** uuid_cli.c: command line tool
28 */
29
30 /* own headers */
31 #include "uuid.h"
32 #include "uuid_ac.h"
33
34 /* system headers */
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <errno.h>
41
42 /* error handler */
43 static void
error(int ec,const char * str,...)44 error(int ec, const char *str, ...)
45 {
46 va_list ap;
47
48 va_start(ap, str);
49 fprintf(stderr, "uuid:ERROR: ");
50 vfprintf(stderr, str, ap);
51 fprintf(stderr, "\n");
52 va_end(ap);
53 exit(ec);
54 }
55
56 /* usage handler */
57 static void
usage(const char * str,...)58 usage(const char *str, ...)
59 {
60 va_list ap;
61
62 va_start(ap, str);
63 if (str != NULL) {
64 fprintf(stderr, "uuid:ERROR: ");
65 vfprintf(stderr, str, ap);
66 fprintf(stderr, "\n");
67 }
68 fprintf(stderr, "usage: uuid [-v version] [-m] [-n count] [-1] [-F format] [-o filename] [namespace name]\n");
69 fprintf(stderr, "usage: uuid -d [-F format] [-o filename] [uuid]\n");
70 va_end(ap);
71 exit(1);
72 }
73
74 /* main procedure */
main(int argc,char * argv[])75 int main(int argc, char *argv[])
76 {
77 char uuid_buf_bin[UUID_LEN_BIN];
78 char uuid_buf_str[UUID_LEN_STR+1];
79 char uuid_buf_siv[UUID_LEN_SIV+1];
80 uuid_t *uuid;
81 uuid_t *uuid_ns;
82 uuid_rc_t rc;
83 FILE *fp;
84 char *p;
85 int ch;
86 int count;
87 int i;
88 int iterate;
89 uuid_fmt_t fmt;
90 int decode;
91 void *vp;
92 size_t n;
93 unsigned int version;
94
95 /* command line parsing */
96 count = -1; /* no count yet */
97 fp = stdout; /* default output file */
98 iterate = 0; /* not one at a time */
99 fmt = UUID_FMT_STR; /* default is ASCII output */
100 decode = 0; /* default is to encode */
101 version = UUID_MAKE_V1;
102 while ((ch = getopt(argc, argv, "1n:rF:dmo:v:h")) != -1) {
103 switch (ch) {
104 case '1':
105 iterate = 1;
106 break;
107 case 'n':
108 if (count > 0)
109 usage("option 'n' specified multiple times");
110 count = strtol(optarg, &p, 10);
111 if (*p != '\0' || count < 1)
112 usage("invalid argument to option 'n'");
113 break;
114 case 'r':
115 fmt = UUID_FMT_BIN;
116 break;
117 case 'F':
118 if (strcasecmp(optarg, "bin") == 0)
119 fmt = UUID_FMT_BIN;
120 else if (strcasecmp(optarg, "str") == 0)
121 fmt = UUID_FMT_STR;
122 else if (strcasecmp(optarg, "siv") == 0)
123 fmt = UUID_FMT_SIV;
124 else
125 error(1, "invalid format \"%s\" (has to be \"bin\", \"str\" or \"siv\")", optarg);
126 break;
127 case 'd':
128 decode = 1;
129 break;
130 case 'o':
131 if (fp != stdout)
132 error(1, "multiple output files are not allowed");
133 if ((fp = fopen(optarg, "w")) == NULL)
134 error(1, "fopen: %s", strerror(errno));
135 break;
136 case 'm':
137 version |= UUID_MAKE_MC;
138 break;
139 case 'v':
140 i = strtol(optarg, &p, 10);
141 if (*p != '\0')
142 usage("invalid argument to option 'v'");
143 switch (i) {
144 case 1: version = UUID_MAKE_V1; break;
145 case 3: version = UUID_MAKE_V3; break;
146 case 4: version = UUID_MAKE_V4; break;
147 case 5: version = UUID_MAKE_V5; break;
148 default:
149 usage("invalid version on option 'v'");
150 break;
151 }
152 break;
153 case 'h':
154 usage(NULL);
155 break;
156 default:
157 usage("invalid option '%c'", optopt);
158 }
159 }
160 argv += optind;
161 argc -= optind;
162 if (count == -1)
163 count = 1;
164
165 if (decode) {
166 /* decoding */
167 if ((rc = uuid_create(&uuid)) != UUID_RC_OK)
168 error(1, "uuid_create: %s", uuid_error(rc));
169 if (argc != 1)
170 usage("invalid number of arguments");
171 if (strcmp(argv[0], "-") == 0) {
172 if (fmt == UUID_FMT_BIN) {
173 if (fread(uuid_buf_bin, UUID_LEN_BIN, 1, stdin) != 1)
174 error(1, "fread: failed to read %d (UUID_LEN_BIN) bytes from stdin", UUID_LEN_BIN);
175 if ((rc = uuid_import(uuid, UUID_FMT_BIN, uuid_buf_bin, UUID_LEN_BIN)) != UUID_RC_OK)
176 error(1, "uuid_import: %s", uuid_error(rc));
177 }
178 else if (fmt == UUID_FMT_STR) {
179 if (fread(uuid_buf_str, UUID_LEN_STR, 1, stdin) != 1)
180 error(1, "fread: failed to read %d (UUID_LEN_STR) bytes from stdin", UUID_LEN_STR);
181 uuid_buf_str[UUID_LEN_STR] = '\0';
182 if ((rc = uuid_import(uuid, UUID_FMT_STR, uuid_buf_str, UUID_LEN_STR)) != UUID_RC_OK)
183 error(1, "uuid_import: %s", uuid_error(rc));
184 }
185 else if (fmt == UUID_FMT_SIV) {
186 if (fread(uuid_buf_siv, UUID_LEN_SIV, 1, stdin) != 1)
187 error(1, "fread: failed to read %d (UUID_LEN_SIV) bytes from stdin", UUID_LEN_SIV);
188 uuid_buf_siv[UUID_LEN_SIV] = '\0';
189 if ((rc = uuid_import(uuid, UUID_FMT_SIV, uuid_buf_siv, UUID_LEN_SIV)) != UUID_RC_OK)
190 error(1, "uuid_import: %s", uuid_error(rc));
191 }
192 }
193 else {
194 if (fmt == UUID_FMT_BIN) {
195 error(1, "binary input mode only possible if reading from stdin");
196 }
197 else if (fmt == UUID_FMT_STR) {
198 if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK)
199 error(1, "uuid_import: %s", uuid_error(rc));
200 }
201 else if (fmt == UUID_FMT_SIV) {
202 if ((rc = uuid_import(uuid, UUID_FMT_SIV, argv[0], strlen(argv[0]))) != UUID_RC_OK)
203 error(1, "uuid_import: %s", uuid_error(rc));
204 }
205 }
206 vp = NULL;
207 if ((rc = uuid_export(uuid, UUID_FMT_TXT, &vp, NULL)) != UUID_RC_OK)
208 error(1, "uuid_export: %s", uuid_error(rc));
209 fprintf(stdout, "%s", (char *)vp);
210 free(vp);
211 if ((rc = uuid_destroy(uuid)) != UUID_RC_OK)
212 error(1, "uuid_destroy: %s", uuid_error(rc));
213 }
214 else {
215 /* encoding */
216 if ( (version == UUID_MAKE_V1 && argc != 0)
217 || (version == UUID_MAKE_V3 && argc != 2)
218 || (version == UUID_MAKE_V4 && argc != 0)
219 || (version == UUID_MAKE_V5 && argc != 2))
220 usage("invalid number of arguments");
221 if ((rc = uuid_create(&uuid)) != UUID_RC_OK)
222 error(1, "uuid_create: %s", uuid_error(rc));
223 if (argc == 1) {
224 /* load initial UUID for setting old generator state */
225 if (strlen(argv[0]) != UUID_LEN_STR)
226 error(1, "invalid length of UUID string representation");
227 if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK)
228 error(1, "uuid_import: %s", uuid_error(rc));
229 }
230 for (i = 0; i < count; i++) {
231 if (iterate) {
232 if ((rc = uuid_load(uuid, "nil")) != UUID_RC_OK)
233 error(1, "uuid_load: %s", uuid_error(rc));
234 }
235 if (version == UUID_MAKE_V3 || version == UUID_MAKE_V5) {
236 if ((rc = uuid_create(&uuid_ns)) != UUID_RC_OK)
237 error(1, "uuid_create: %s", uuid_error(rc));
238 if ((rc = uuid_load(uuid_ns, argv[0])) != UUID_RC_OK) {
239 if ((rc = uuid_import(uuid_ns, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK)
240 error(1, "uuid_import: %s", uuid_error(rc));
241 }
242 if ((rc = uuid_make(uuid, version, uuid_ns, argv[1])) != UUID_RC_OK)
243 error(1, "uuid_make: %s", uuid_error(rc));
244 if ((rc = uuid_destroy(uuid_ns)) != UUID_RC_OK)
245 error(1, "uuid_destroy: %s", uuid_error(rc));
246 }
247 else {
248 if ((rc = uuid_make(uuid, version)) != UUID_RC_OK)
249 error(1, "uuid_make: %s", uuid_error(rc));
250 }
251 if (fmt == UUID_FMT_BIN) {
252 vp = NULL;
253 if ((rc = uuid_export(uuid, UUID_FMT_BIN, &vp, &n)) != UUID_RC_OK)
254 error(1, "uuid_export: %s", uuid_error(rc));
255 fwrite(vp, n, 1, fp);
256 free(vp);
257 }
258 else if (fmt == UUID_FMT_STR) {
259 vp = NULL;
260 if ((rc = uuid_export(uuid, UUID_FMT_STR, &vp, &n)) != UUID_RC_OK)
261 error(1, "uuid_export: %s", uuid_error(rc));
262 fprintf(fp, "%s\n", (char *)vp);
263 free(vp);
264 }
265 else if (fmt == UUID_FMT_SIV) {
266 vp = NULL;
267 if ((rc = uuid_export(uuid, UUID_FMT_SIV, &vp, &n)) != UUID_RC_OK)
268 error(1, "uuid_export: %s", uuid_error(rc));
269 fprintf(fp, "%s\n", (char *)vp);
270 free(vp);
271 }
272 }
273 if ((rc = uuid_destroy(uuid)) != UUID_RC_OK)
274 error(1, "uuid_destroy: %s", uuid_error(rc));
275 }
276
277 /* close output channel */
278 if (fp != stdout)
279 fclose(fp);
280
281 return 0;
282 }
283
284