1 /* 2 * Copyright (c) 2000-2001, 2005-2008 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 SM_RCSID("@(#)$Id: t-sem.c,v 1.18 2013-11-22 20:51:43 ca Exp $") 12 13 #include <stdio.h> 14 15 #if SM_CONF_SEM 16 # include <stdlib.h> 17 # include <unistd.h> 18 # include <sysexits.h> 19 # include <sm/heap.h> 20 # include <sm/string.h> 21 # include <sm/signal.h> 22 # include <sm/test.h> 23 # include <sm/conf.h> 24 # include <sm/sem.h> 25 26 # define T_SM_SEM_KEY (4321L) 27 28 static void 29 delay(t, s) 30 int t; 31 char *s; 32 { 33 if (t > 0) 34 { 35 # if DEBUG 36 fprintf(stderr, "sleep(%d) before %s\n", t, s); 37 # endif 38 sleep(t); 39 } 40 # if DEBUG 41 fprintf(stderr, "%s\n", s); 42 # endif 43 } 44 45 46 /* 47 ** SEMINTER -- interactive testing of semaphores. 48 ** 49 ** Parameters: 50 ** owner -- create semaphores. 51 ** 52 ** Returns: 53 ** 0 on success 54 ** < 0 on failure. 55 */ 56 57 static int 58 seminter(owner) 59 bool owner; 60 { 61 int semid; 62 int t; 63 64 semid = sm_sem_start(T_SM_SEM_KEY, SM_NSEM, 0, owner); 65 if (semid < 0) 66 { 67 perror("sm_sem_start failed"); 68 return 1; 69 } 70 71 while ((t = getchar()) != EOF) 72 { 73 switch (t) 74 { 75 case 'a': 76 delay(0, "try to acq"); 77 if (sm_sem_acq(semid, 0, 2) < 0) 78 { 79 perror("sm_sem_acq failed"); 80 return 1; 81 } 82 delay(0, "acquired"); 83 break; 84 85 case 'r': 86 delay(0, "try to rel"); 87 if (sm_sem_rel(semid, 0, 2) < 0) 88 { 89 perror("sm_sem_rel failed"); 90 return 1; 91 } 92 delay(0, "released"); 93 break; 94 95 case 'v': 96 if ((t = sm_sem_get(semid, 0)) < 0) 97 { 98 perror("get_sem failed"); 99 return 1; 100 } 101 printf("semval: %d\n", t); 102 break; 103 104 } 105 } 106 if (owner) 107 return sm_sem_stop(semid); 108 return 0; 109 } 110 111 /* 112 ** SEM_CLEANUP -- cleanup if something breaks 113 ** 114 ** Parameters: 115 ** sig -- signal. 116 ** 117 ** Returns: 118 ** none. 119 */ 120 121 static int semid_c = -1; 122 void 123 sem_cleanup(sig) 124 int sig; 125 { 126 if (semid_c >= 0) 127 (void) sm_sem_stop(semid_c); 128 exit(EX_UNAVAILABLE); 129 } 130 131 static int 132 drop_priv(uid, gid) 133 uid_t uid; 134 gid_t gid; 135 { 136 int r; 137 138 r = setgid(gid); 139 if (r != 0) 140 return r; 141 r = setuid(uid); 142 return r; 143 } 144 145 /* 146 ** SEMTEST -- test of semaphores 147 ** 148 ** Parameters: 149 ** owner -- create semaphores. 150 ** 151 ** Returns: 152 ** 0 on success 153 ** < 0 on failure. 154 */ 155 156 # define MAX_CNT 10 157 158 static int 159 semtest(owner, uid, gid) 160 int owner; 161 uid_t uid; 162 gid_t gid; 163 { 164 int semid, r; 165 int cnt = 0; 166 167 if (!owner && uid != 0) 168 { 169 r = drop_priv(uid, gid); 170 if (r < 0) 171 { 172 perror("drop_priv child failed"); 173 return -1; 174 } 175 } 176 semid = sm_sem_start(T_SM_SEM_KEY, 1, 0, owner); 177 if (semid < 0) 178 { 179 perror("sm_sem_start failed"); 180 return -1; 181 } 182 183 if (owner) 184 { 185 if (uid != 0) 186 { 187 r = sm_semsetowner(semid, uid, gid, 0660); 188 if (r < 0) 189 { 190 perror("sm_semsetowner failed"); 191 return -1; 192 } 193 r = drop_priv(uid, gid); 194 if (r < 0) 195 { 196 perror("drop_priv owner failed"); 197 return -1; 198 } 199 } 200 201 /* just in case someone kills the program... */ 202 semid_c = semid; 203 (void) sm_signal(SIGHUP, sem_cleanup); 204 (void) sm_signal(SIGINT, sem_cleanup); 205 (void) sm_signal(SIGTERM, sem_cleanup); 206 207 delay(1, "parent: acquire 1"); 208 cnt = 0; 209 do 210 { 211 r = sm_sem_acq(semid, 0, 0); 212 if (r < 0) 213 { 214 sleep(1); 215 ++cnt; 216 } 217 } while (r < 0 && cnt <= MAX_CNT); 218 SM_TEST(r >= 0); 219 if (r < 0) 220 return r; 221 222 delay(3, "parent: release 1"); 223 cnt = 0; 224 do 225 { 226 r = sm_sem_rel(semid, 0, 0); 227 if (r < 0) 228 { 229 sleep(1); 230 ++cnt; 231 } 232 } while (r < 0 && cnt <= MAX_CNT); 233 SM_TEST(r >= 0); 234 if (r < 0) 235 return r; 236 237 delay(1, "parent: getval"); 238 cnt = 0; 239 do 240 { 241 r = sm_sem_get(semid, 0); 242 if (r <= 0) 243 { 244 sleep(1); 245 ++cnt; 246 } 247 } while (r <= 0 && cnt <= MAX_CNT); 248 SM_TEST(r > 0); 249 if (r <= 0) 250 return r; 251 252 delay(1, "parent: acquire 2"); 253 cnt = 0; 254 do 255 { 256 r = sm_sem_acq(semid, 0, 0); 257 if (r < 0) 258 { 259 sleep(1); 260 ++cnt; 261 } 262 } while (r < 0 && cnt <= MAX_CNT); 263 SM_TEST(r >= 0); 264 if (r < 0) 265 return r; 266 267 cnt = 0; 268 do 269 { 270 r = sm_sem_rel(semid, 0, 0); 271 if (r < 0) 272 { 273 sleep(1); 274 ++cnt; 275 } 276 } while (r < 0 && cnt <= MAX_CNT); 277 SM_TEST(r >= 0); 278 if (r < 0) 279 return r; 280 } 281 else 282 { 283 delay(1, "child: acquire 1"); 284 cnt = 0; 285 do 286 { 287 r = sm_sem_acq(semid, 0, 0); 288 if (r < 0) 289 { 290 sleep(1); 291 ++cnt; 292 } 293 } while (r < 0 && cnt <= MAX_CNT); 294 SM_TEST(r >= 0); 295 if (r < 0) 296 return r; 297 298 delay(1, "child: release 1"); 299 cnt = 0; 300 do 301 { 302 r = sm_sem_rel(semid, 0, 0); 303 if (r < 0) 304 { 305 sleep(1); 306 ++cnt; 307 } 308 } while (r < 0 && cnt <= MAX_CNT); 309 SM_TEST(r >= 0); 310 if (r < 0) 311 return r; 312 313 } 314 if (owner) 315 return sm_sem_stop(semid); 316 return 0; 317 } 318 319 int 320 main(argc, argv) 321 int argc; 322 char *argv[]; 323 { 324 bool interactive = false; 325 bool owner = false; 326 int ch, r; 327 uid_t uid; 328 gid_t gid; 329 330 uid = 0; 331 gid = 0; 332 r = 0; 333 334 # define OPTIONS "iog:u:" 335 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 336 { 337 switch ((char) ch) 338 { 339 case 'g': 340 gid = (gid_t)strtoul(optarg, 0, 0); 341 break; 342 343 case 'i': 344 interactive = true; 345 break; 346 347 case 'u': 348 uid = (uid_t)strtoul(optarg, 0, 0); 349 break; 350 351 case 'o': 352 owner = true; 353 break; 354 355 default: 356 break; 357 } 358 } 359 360 if (interactive) 361 r = seminter(owner); 362 else 363 { 364 pid_t pid; 365 366 printf("This test takes about 8 seconds.\n"); 367 printf("If it takes longer than 30 seconds, please interrupt it\n"); 368 printf("and compile again without semaphore support, i.e.,"); 369 printf("-DSM_CONF_SEM=0\n"); 370 if ((pid = fork()) < 0) 371 { 372 perror("fork failed\n"); 373 return -1; 374 } 375 376 sm_test_begin(argc, argv, "test semaphores"); 377 if (pid == 0) 378 { 379 /* give the parent the chance to setup data */ 380 sleep(1); 381 r = semtest(false, uid, gid); 382 } 383 else 384 { 385 r = semtest(true, uid, gid); 386 } 387 SM_TEST(r == 0); 388 return sm_test_end(); 389 } 390 return r; 391 } 392 #else /* SM_CONF_SEM */ 393 int 394 main(argc, argv) 395 int argc; 396 char *argv[]; 397 { 398 printf("No support for semaphores configured on this machine\n"); 399 return 0; 400 } 401 #endif /* SM_CONF_SEM */ 402