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