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