1/*
2 * Copyright (c) 2006 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <stdbool.h>
33#include <errno.h>
34#include <string.h>
35
36// add additional headers needed here.
37
38#include "../libmicro.h"
39#include <membership.h>
40#include <pwd.h>
41#include <uuid/uuid.h>
42
43#if DEBUG
44# define debug(fmt, args...)    (void) fprintf(stderr, fmt "\n" , ##args)
45#else
46# define debug(fmt, args...)
47#endif
48
49
50// Correct use case
51//
52//    mbr_check_membership -E  -L -S -W -B 200 -C 10 -g 1211-1213 -u 5000-5200
53//
54//      libMicro default benchmark run options are "-E -C 200 -L -S -W"
55//
56// -B is batch size: loop iteration per each benchmark run. (default: 100)
57// -C is min sample number: how many benchmark needs to run to get proper sample
58//                          1 is mimumum, but you get at least 3 benchmark run
59//                          samples. Do not set to zero. Default is 200 for most
60//                          runs in libMicro.
61// -u uid range in the form of "min-max". For example, -u 5000-5200
62// -g gid range or gid
63
64/*
65 *    Your state variables should live in the tsd_t struct below
66 */
67typedef struct {
68} tsd_t;
69
70#define INVALID_ID  -1
71
72static uid_t uid_min = INVALID_ID;
73static gid_t gid_min = INVALID_ID;;
74
75static int   uid_range = 0;  // uid_max = uid_min + uid_range
76static int   gid_range = 0; // gid_max = gid_min + gid_range
77
78static uuid_t *u_uuid_list = NULL;  // user uuid list
79static uuid_t *g_uuid_list = NULL;  // group uuid list
80
81int
82benchmark_init()
83{
84    debug("benchmark_init");
85    (void) sprintf(lm_optstr,  "g:u:");
86
87    lm_tsdsize = sizeof(tsd_t);
88    lm_defB = 100;
89
90    (void) sprintf(lm_usage,
91                "\n       ------- mbr_check_membership specific options\n"
92                "       [-u UID range (min-max)]\n"
93                "       [-g GID or GID range (gid or min-max)]\n"
94                "\n" );
95    return (0);
96}
97
98int
99parse_range(uint *min, int *offset, char *buf)
100{
101    char *value, *tmp_ptr = strdup(buf);
102    int range=0;
103    debug("parse_range");
104
105    value = strsep(&tmp_ptr, "-");
106    *min = atoi(value);
107    debug("min = %d", *min);
108    if (tmp_ptr) {
109        value = strsep(&tmp_ptr, "-");
110        range = atoi(value);
111        if (range < *min) {
112            printf("max id should be larger than min id\n");
113            return -1;
114        }
115        *offset = range - *min;
116        debug("range = %d", *offset);
117    }
118
119    return 0;
120
121}
122
123/*
124 * This is where you parse your lower-case arguments.
125 */
126int
127benchmark_optswitch(int opt, char *optarg)
128{
129    debug("benchmark_optswitch");
130
131    switch (opt) {
132    case 'g':    // GID or GID range
133        return parse_range( &gid_min, &gid_range, optarg);
134        break;
135
136    case 'u':    // UID range
137        return parse_range( &uid_min, &uid_range, optarg);
138        break;
139    default:
140        return -1;
141    }
142
143    return 0;
144}
145
146
147// Initialize all structures that will be used in benchmark()
148// 1. make local or network node for OD query
149// 2. create user key
150int
151benchmark_initrun(void *tsd)
152{
153    int i;
154    //tsd_t *ts = (tsd_t *)tsd;
155
156    debug("benchmark_initrun");
157
158    if (uid_min == INVALID_ID || gid_min == INVALID_ID) {
159        printf("Both -u and -g need to be specified\n");
160        return -1;
161    }
162
163    // create an array of usernames to use in benchmark before their use
164    // realtime generation in benchmark effects performance measurements
165
166    u_uuid_list = malloc( sizeof(*u_uuid_list) * (uid_range+1) );
167    g_uuid_list = malloc( sizeof(*g_uuid_list) * (gid_range+1) );
168
169    for (i = 0; i <= uid_range; i++) {
170
171        if (mbr_uid_to_uuid(uid_min+i, u_uuid_list[i])) {
172            printf("error converting uid %d to UUID\n", uid_min+i);
173            return -1;
174        }
175    }
176
177    for (i = 0; i <= gid_range; i++) {
178
179        if (mbr_gid_to_uuid(gid_min+i, g_uuid_list[i])) {
180            printf("error converting gid %d to UUID\n", gid_min+i);
181            return -1;
182        }
183    }
184
185    return (0);
186}
187
188int
189benchmark(void *tsd, result_t *res)
190{
191    int         i, index, gindex, err, isMember=0;
192    //tsd_t *ts = (tsd_t *)tsd;
193
194#ifdef DEBUG
195    uid_t       uid;
196    int         id_type;
197#endif
198
199    res->re_errors = 0;
200
201    // debug("in to benchmark - optB = %i", lm_optB);
202
203    for (i = 0; i < lm_optB; i++) {
204
205        index = random() % (uid_range+1);
206        gindex = random() % (gid_range+1);
207        err = mbr_check_membership(u_uuid_list[index], g_uuid_list[gindex], &isMember);
208
209#ifdef DEBUG
210        //mbr_uuid_to_id(u_uuid_list[index], &uid, &id_type);
211        //debug ("loop %d: uid %d is %s (gindex %d)", i, uid, (isMember)?"member":"not a member", gindex);
212#endif
213
214        if (err) {
215            if (err == EIO) {
216                debug("mbr_check_membership returned EIO. Unable to communicate with DS daemon");
217            }
218            else if (err == ENOENT) {
219                debug("mbr_check_membership returned ENOENT. User not found");
220            }
221            else {
222                debug("error: %s", strerror(err));
223            }
224            res->re_errors++;
225        }
226    }
227    res->re_count = i;
228
229    return (0);
230}
231
232
233// We need to release all the structures we allocated in benchmark_initrun()
234int
235benchmark_finirun(void *tsd)
236{
237    //tsd_t    *ts = (tsd_t *)tsd;
238
239    debug("benchmark_result: deallocating structures");
240
241    free(u_uuid_list);
242    free(g_uuid_list);
243
244    return (0);
245}
246
247char *
248benchmark_result()
249{
250    static char    result = '\0';
251    debug("benchmark_result");
252    return (&result);
253}
254
255