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> 11SM_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 28static void 29delay(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 57static int 58seminter(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 121static int semid_c = -1; 122void 123sem_cleanup(sig) 124 int sig; 125{ 126 if (semid_c >= 0) 127 (void) sm_sem_stop(semid_c); 128 exit(EX_UNAVAILABLE); 129} 130 131static int 132drop_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 158static int 159semtest(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 319int 320main(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 */ 393int 394main(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