]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/test_uuidd.c
Use --help suggestion on invalid option
[thirdparty/util-linux.git] / misc-utils / test_uuidd.c
CommitLineData
0f2b00ce
KZ
1/*
2 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
3 * Huschaam Hussain <Huschaam.Hussain@hp.com>
4 * TSG Solution Alliances Engineering
5 * SAP Technology Group
6 *
7 * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
28f47fd2
KZ
8 *
9 *
10 * The test heavily uses shared memory, to enlarge maximal size of shared
11 * segment use:
12 *
13 * echo "4294967295" > /proc/sys/kernel/shmm
14 *
15 * The test is compiled against in-tree libuuid, if you want to test uuidd
16 * installed to the system then make sure that libuuid uses the same socket
17 * like the running uuidd. You can start the uuidd manually, for example:
18 *
19 * uuidd --debug --no-fork --no-pid --socket /run/uuidd/request
20 *
21 * if the $localstatedir (as defined by build-system) is /run. If you want
22 * to overwrite the built-in default then use:
23 *
24 * make uuidd uuidgen localstatedir=/var
0f2b00ce
KZ
25 */
26#include <error.h>
963f128c
HH
27#include <pthread.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include <sys/shm.h>
33#include <sys/types.h>
34#include <sys/wait.h>
35
adbc73eb 36#include "uuid.h"
0f2b00ce
KZ
37#include "c.h"
38#include "xalloc.h"
39#include "strutils.h"
677ec86c 40#include "nls.h"
0f2b00ce 41
17930612 42#define LOG(level,args) if (loglev >= level) { fprintf args; }
963f128c 43
17930612
KZ
44size_t nprocesses = 4;
45size_t nthreads = 4;
46size_t nobjects = 4096;
47size_t loglev = 1;
f4be1406
KZ
48
49struct processentry {
50 pid_t pid;
51 int status;
52};
53typedef struct processentry process_t;
963f128c
HH
54
55struct threadentry {
f4be1406
KZ
56 process_t *proc;
57 pthread_t tid; /* pthread_self() / phtread_create() */
58 pthread_attr_t thread_attr;
59 size_t index; /* index in object[] */
60 int retval; /* pthread exit() */
963f128c
HH
61};
62typedef struct threadentry thread_t;
63
4d524158 64/* this is in shared memory, keep it as small as possible */
963f128c 65struct objectentry {
f4be1406 66 uuid_t uuid;
a539def5
KZ
67 pthread_t tid;
68 pid_t pid;
69 size_t idx;
963f128c
HH
70};
71typedef struct objectentry object_t;
72
f4be1406 73static int shmem_id;
1d27cd11 74static object_t *objects;
963f128c 75
963f128c 76
0f2b00ce 77static void __attribute__((__noreturn__)) usage(FILE *out)
963f128c 78{
0f2b00ce 79 fprintf(out, "\n %s [options]\n", program_invocation_short_name);
963f128c 80
17930612
KZ
81 fprintf(out, " -p <num> number of of nprocesses (default:%zu)\n", nprocesses);
82 fprintf(out, " -t <num> number of nthreads (default:%zu)\n", nthreads);
83 fprintf(out, " -o <num> number of nobjects (default:%zu)\n", nobjects);
84 fprintf(out, " -l <level> log level (default:%zu)\n", loglev);
0f2b00ce 85 fprintf(out, " -h display help\n");
963f128c 86
0f2b00ce
KZ
87 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
88}
963f128c 89
0f2b00ce 90static void allocate_segment(int *id, void **address, size_t number, size_t size)
963f128c
HH
91{
92 *id = shmget(IPC_PRIVATE, number * size, IPC_CREAT | 0600);
93 if (*id == -1)
1d27cd11 94 err(EXIT_FAILURE, "shmget failed to create %zu bytes shared memory", number * size);
0f2b00ce 95
963f128c
HH
96 *address = shmat(*id, NULL, 0);
97 if (*address == (void *)-1)
0f2b00ce
KZ
98 err(EXIT_FAILURE, "shmat failed");
99
100 LOG(2, (stderr,
7eeb7e1d
KZ
101 "allocate shared memory segment [id=%d,address=0x%p]\n",
102 *id, *address));
4d524158
KZ
103
104 memset(*address, 0, number * size);
0f2b00ce 105}
963f128c 106
0f2b00ce 107static void remove_segment(int id, void *address)
963f128c
HH
108{
109 if (shmdt(address) == -1)
0f2b00ce 110 err(EXIT_FAILURE, "shmdt failed");
963f128c 111 if (shmctl(id, IPC_RMID, NULL) == -1)
0f2b00ce 112 err(EXIT_FAILURE, "shmctl failed");
963f128c
HH
113 LOG(2,
114 (stderr,
7eeb7e1d
KZ
115 "remove shared memory segment [id=%d,address=0x%p]\n",
116 id, address));
0f2b00ce 117}
963f128c 118
0f2b00ce 119static void object_uuid_create(object_t * object)
963f128c
HH
120{
121 uuid_generate_time(object->uuid);
0f2b00ce 122}
963f128c 123
f4be1406 124static void object_uuid_to_string(object_t * object, char **string_uuid)
963f128c
HH
125{
126 uuid_unparse(object->uuid, *string_uuid);
0f2b00ce 127}
963f128c 128
0f2b00ce 129static int object_uuid_compare(const void *object1, const void *object2)
963f128c 130{
f4be1406
KZ
131 uuid_t *uuid1 = &((object_t *) object1)->uuid,
132 *uuid2 = &((object_t *) object2)->uuid;
963f128c 133
f4be1406 134 return uuid_compare(*uuid1, *uuid2);
0f2b00ce 135}
963f128c 136
f4be1406 137static void *create_uuids(thread_t *th)
963f128c 138{
f4be1406 139 size_t i;
963f128c 140
17930612 141 for (i = th->index; i < th->index + nobjects; i++) {
1d27cd11
KZ
142 object_t *obj = &objects[i];
143
144 object_uuid_create(obj);
a539def5
KZ
145 obj->tid = th->tid;
146 obj->pid = th->proc->pid;
147 obj->idx = th->index + i;;
0f2b00ce 148 }
f4be1406 149 return 0;
0f2b00ce 150}
963f128c 151
f4be1406
KZ
152static void *thread_body(void *arg)
153{
154 thread_t *th = (thread_t *) arg;
155
156 return create_uuids(th);
157}
158
17930612 159static void create_nthreads(process_t *proc, size_t index)
963f128c 160{
1d27cd11 161 thread_t *threads;
4d524158 162 size_t i, ncreated = 0;
1d27cd11
KZ
163 int rc;
164
fea1cbf7 165 threads = xcalloc(nthreads, sizeof(thread_t));
963f128c 166
17930612 167 for (i = 0; i < nthreads; i++) {
1d27cd11 168 thread_t *th = &threads[i];
0f2b00ce 169
1d27cd11 170 rc = pthread_attr_init(&th->thread_attr);
4d524158
KZ
171 if (rc) {
172 error(0, rc, "%d: pthread_attr_init failed", proc->pid);
173 break;
174 }
1d27cd11
KZ
175
176 th->index = index;
177 th->proc = proc;
178 rc = pthread_create(&th->tid, &th->thread_attr, &thread_body, th);
179
4d524158
KZ
180 if (rc) {
181 error(0, rc, "%d: pthread_create failed", proc->pid);
182 break;
183 }
1d27cd11
KZ
184
185 LOG(2, (stderr, "%d: started thread [tid=%d,index=%zu]\n",
186 proc->pid, (int) th->tid, th->index));
17930612 187 index += nobjects;
4d524158 188 ncreated++;
0f2b00ce
KZ
189 }
190
4d524158 191 if (ncreated != nthreads)
9e930041 192 fprintf(stderr, "%d: %zu threads not created and ~%zu objects will be ignored\n",
4d524158
KZ
193 proc->pid, nthreads - ncreated,
194 (nthreads - ncreated) * nobjects);
195
196 for (i = 0; i < ncreated; i++) {
1d27cd11
KZ
197 thread_t *th = &threads[i];
198
199 rc = pthread_join(th->tid, (void *) &th->retval);
200 if (rc)
201 error(EXIT_FAILURE, rc, "pthread_join failed");
202
203 LOG(2, (stderr, "%d: thread exited [tid=%d,return=%d]\n",
204 proc->pid, (int) th->tid, th->retval));
0f2b00ce 205 }
0f2b00ce 206}
963f128c 207
17930612 208static void create_nprocesses(void)
963f128c
HH
209{
210 process_t *process;
f4be1406 211 size_t i;
963f128c 212
fea1cbf7 213 process = xcalloc(nprocesses, sizeof(process_t));
1d27cd11 214
17930612 215 for (i = 0; i < nprocesses; i++) {
1d27cd11
KZ
216 process_t *proc = &process[i];
217
218 proc->pid = fork();
219 switch (proc->pid) {
7eeb7e1d 220 case -1: /* error */
0f2b00ce 221 err(EXIT_FAILURE, "fork failed");
963f128c 222 break;
7eeb7e1d 223 case 0: /* child */
1d27cd11
KZ
224 proc->pid = getpid();
225 create_nthreads(proc, i * nthreads * nobjects);
0f2b00ce 226 exit(EXIT_SUCCESS);
963f128c 227 break;
7eeb7e1d 228 default: /* parent */
1d27cd11 229 LOG(2, (stderr, "started process [pid=%d]\n", proc->pid));
963f128c 230 break;
0f2b00ce
KZ
231 }
232 }
233
17930612 234 for (i = 0; i < nprocesses; i++) {
1d27cd11 235 process_t *proc = &process[i];
0f2b00ce 236
1d27cd11
KZ
237 if (waitpid(proc->pid, &proc->status, 0) == (pid_t) - 1)
238 err(EXIT_FAILURE, "waitpid failed");
963f128c 239 LOG(2,
7eeb7e1d 240 (stderr, "process exited [pid=%d,status=%d]\n",
1d27cd11 241 proc->pid, proc->status));
0f2b00ce 242 }
0f2b00ce 243}
963f128c 244
1d27cd11 245static void object_dump(size_t idx, object_t *obj)
963f128c 246{
f4be1406 247 char uuid_string[37], *p;
963f128c
HH
248
249 p = uuid_string;
1d27cd11
KZ
250 object_uuid_to_string(obj, &p);
251
032776e8
KZ
252 fprintf(stderr, "object[%zu]: {\n", idx);
253 fprintf(stderr, " uuid: <%s>\n", p);
a539def5
KZ
254 fprintf(stderr, " idx: %zu\n", obj->idx);
255 fprintf(stderr, " process: %d\n", (int) obj->pid);
256 fprintf(stderr, " thread: %d\n", (int) obj->tid);
032776e8 257 fprintf(stderr, "}\n");
0f2b00ce 258}
963f128c 259
0f2b00ce 260int main(int argc, char *argv[])
963f128c 261{
1d27cd11 262 size_t i, nfailed = 0, nignored = 0;
0f2b00ce
KZ
263 int c;
264
265 while (((c = getopt(argc, argv, "p:t:o:l:h")) != -1)) {
266 switch (c) {
267 case 'p':
17930612 268 nprocesses = strtou32_or_err(optarg, "invalid nprocesses number argument");
0f2b00ce
KZ
269 break;
270 case 't':
17930612 271 nthreads = strtou32_or_err(optarg, "invalid nthreads number argument");
0f2b00ce
KZ
272 break;
273 case 'o':
17930612 274 nobjects = strtou32_or_err(optarg, "invalid nobjects number argument");
0f2b00ce
KZ
275 break;
276 case 'l':
17930612 277 loglev = strtou32_or_err(optarg, "invalid log level argument");
0f2b00ce
KZ
278 break;
279 case 'h':
280 usage(stdout);
281 break;
282 default:
677ec86c 283 errtryh(EXIT_FAILURE);
0f2b00ce
KZ
284 }
285 }
286
287 if (optind != argc)
288 usage(stderr);
289
17930612 290 if (loglev == 1)
1d27cd11
KZ
291 fprintf(stderr, "requested: %zu processes, %zu threads, %zu objects per thread (%zu objects = %zu bytes)\n",
292 nprocesses, nthreads, nobjects,
293 nprocesses * nthreads * nobjects,
294 nprocesses * nthreads * nobjects * sizeof(object_t));
0f2b00ce 295
1d27cd11 296 allocate_segment(&shmem_id, (void **)&objects,
17930612 297 nprocesses * nthreads * nobjects, sizeof(object_t));
1d27cd11 298
17930612 299 create_nprocesses();
1d27cd11 300
17930612
KZ
301 if (loglev >= 3) {
302 for (i = 0; i < nprocesses * nthreads * nobjects; i++)
1d27cd11 303 object_dump(i, &objects[i]);
0f2b00ce 304 }
7eeb7e1d 305
1d27cd11 306 qsort(objects, nprocesses * nthreads * nobjects, sizeof(object_t),
963f128c 307 object_uuid_compare);
1d27cd11 308
17930612 309 for (i = 0; i < nprocesses * nthreads * nobjects - 1; i++) {
1d27cd11
KZ
310 object_t *obj1 = &objects[i],
311 *obj2 = &objects[i + 1];
312
a539def5 313 if (!obj1->tid) {
1d27cd11
KZ
314 LOG(3, (stderr, "ignore unused object #%zu\n", i));
315 nignored++;
316 continue;
317 }
318
319 if (object_uuid_compare(obj1, obj2) == 0) {
17930612
KZ
320 if (loglev >= 1)
321 fprintf(stderr, "nobjects #%zu and #%zu have duplicate UUIDs\n",
7eeb7e1d 322 i, i + 1);
1d27cd11
KZ
323 object_dump(i, obj1),
324 object_dump(i + 1, obj2);
325 nfailed++;
0f2b00ce
KZ
326 }
327 }
1d27cd11
KZ
328
329 remove_segment(shmem_id, objects);
330 if (nignored)
cfa4171a 331 printf("%zu objects ignored\n", nignored);
1d27cd11 332 if (!nfailed)
f4be1406
KZ
333 printf("test successful (no duplicate UUIDs found)\n");
334 else
1d27cd11 335 printf("test failed (found %zu duplicate UUIDs)\n", nfailed);
4d524158
KZ
336
337 return nfailed ? EXIT_FAILURE : EXIT_SUCCESS;
0f2b00ce 338}