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