rjk@mrstve.UUCP (Richard Kuhns) (10/11/87)
I realize that this isn't a source group, but shsem isn't very big and I can't seem to contact a moderator (my mail bounces around Purdue for while, then comes home to roost). Enough people have asked for it that I think it's worth posting, so here goes... Do whatever you want with it, but please let me know of any bugs/fixes (preferably fixes :-) # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by rjk on Sun Oct 11 13:21:21 EST 1987 # Contents: shsem.1l shsem.c echo x - shsem.1l sed 's/^@//' > "shsem.1l" <<'@//E*O*F shsem.1l//' @.TH SHSEM 1 @.tr ~ @.SH NAME shsem \- Utilize System V semaphores from the shell @.SH SYNOPSIS @.B shsem [ -Vclruvw ] [ -d debug_level ] file_name @.SH DESCRIPTION @.I Shsem is a program to allow shell scripts to specify `critical' sections of code, using semaphores. @.P @.I Shsem attempts to lock a semaphore whose id (see stdipc(3)) is determined by the file name supplied. It's an error if the file doesn't exist. By default, the semaphore is created if it doesn't already exist. @.P The options are @.TP @.B \-l lock semaphore, fail if semaphore is already locked. @.TP @.B \-w lock semaphore, waiting if semaphore is already locked. @.TP @.B \-c fail if the semaphore doesn't already exist (don't create it). @.TP @.B \-u unlock semaphore. Remove the semaphore if no one is waiting on it. @.TP @.B \-r don't remove the semaphore on last unlock. @.TP @.B \-V talk about what we're doing. @.TP @.B \-v print the version. @.TP @.B \-d # turn on debugging output, with a larger # ==> more output. @.SH EXAMPLE Since @.I shsem returns a succeeded/failed value when run, it could be used in a shell script as follows: @.nf #!/bin/sh if shsem -w /dev/lp then echo We now have exclusive access to /dev/lp else # Since we said to wait for the lock, failure implies # that /dev/lp doesn't exist, we've got too many # semaphores, or something else on the system level is wrong. echo Shsem failed, something is seriously wrong fi @.fi @.SH BUGS Shsem sometimes thinks there's no one waiting to lock a semaphore when there really is. However, since shsem tries to relock the semaphore before removing it, we don't remove semaphores that are in use. Look at the source code. @.SH SEE ALSO Various Semaphore System Calls @.br semctl(2), semget(2), semop(2) @.SH VERSION It varies... @//E*O*F shsem.1l// chmod u=rw,g=rw,o=rw shsem.1l echo x - shsem.c sed 's/^@//' > "shsem.c" <<'@//E*O*F shsem.c//' static char *RCSid = "$Header: shsem.c,v 1.4 87/10/10 12:26:52 rjk Exp $\n"; /* * $Log: shsem.c,v $ * Revision 1.4 87/10/10 12:26:52 rjk * Added the 3 lines of code necessary for no_create... (oops) * * Revision 1.3 87/08/14 17:43:54 rjk * Fooled with semctl stuff, fixed a bad error message * * Revision 1.2 87/08/10 20:58:05 buhrt * newest version.... * need to checkin to install old version * * Revision 1.1 87/08/06 17:17:56 rjk * Initial revision * */ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> typedef int FLAG; #define USAGE() fprintf(stderr, \ "usage:%s -Vcdulrvw file_name_to_lock\n", \ progname) #define BADOPTS() fprintf(stderr, \ "%s:bad options: -l, -u and -w are mutually exclusive\n", \ progname); #define FTOKID ('s') #define LOCKIT (-1) #define UNLOCKIT (1) #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* exit statuses (for shell tests) */ #define ERRORRET 1 #define OKRET 0 extern char *optarg; extern int optind, opterr; char *progname; FLAG debug_flag, /* obvious */ no_create, /* don't create it if it doesn't exist */ wlockit, /* lock it, waiting if necessary */ nwlockit, /* lock it, don't wait */ unlockit, /* unlock it */ errflag, /* was there an error? */ verbose, /* talk about it */ no_remove_sem; /* don't remove when we're the last unlock */ int SemId; /* returned by semget */ int debug_level; key_t SemKey; /* our identifier */ main(argc, argv) int argc; char *argv[]; { int c; progname = argv[0]; /* who i am */ no_create = wlockit = nwlockit = unlockit = FALSE; while ((c = getopt(argc, argv, "Vcd:lruvw")) != -1) { switch (c) { case 'V': verbose = TRUE; break; case 'c': no_create = TRUE; break; case 'd': /* turn on debugging */ debug_flag++; debug_level = atoi(optarg); break; case 'l': /* lock it, no waiting */ if (wlockit || unlockit) { BADOPTS(); errflag = TRUE; } else { nwlockit = TRUE; } break; case 'r': /* don't remove sem if noone's waiting */ no_remove_sem = TRUE; break; case 'u': /* unlock it */ if (wlockit || nwlockit) { BADOPTS(); errflag = TRUE; } else { unlockit = TRUE; } break; case 'v': /* version */ puts(RCSid); break; case 'w': if (unlockit || nwlockit) { BADOPTS(); errflag = TRUE; } else { wlockit = TRUE; } break; case '?': /* bad argument */ errflag = TRUE; break; default: /* this can't happen! */ fprintf(stderr, "%s: BAD RETURN FROM GETOPT (%d)!\n", c); exit(ERRORRET); } if (errflag) { USAGE(); exit(ERRORRET); } } if ((argc - optind) != 1) { fprintf(stderr, "%s: bad arg count (filename required)\n", progname); USAGE(); exit(ERRORRET); } if (!wlockit && !nwlockit && !unlockit) { fprintf(stderr, "%s: one of -l, -u or -w is required\n", progname); USAGE(); exit(ERRORRET); } if (no_remove_sem && !unlockit) { fprintf(stderr, "%s: -r only useful with -u, ignored\n", progname); } if (debug_flag) { fprintf(stderr, "+++attempting to get key for %s\n", argv[optind]); } if ((SemKey = ftok(argv[optind], FTOKID)) == (key_t) -1) { fprintf(stderr, "%s: %s does not exist or is not accessible\n", progname, argv[optind]); exit(ERRORRET); } /* we have a real key -- let's see if we can attach the semaphore... */ if ((SemId = semget(SemKey, 0, 0)) == -1) { if (no_create) { /* Don't even try to create it */ exit(ERRORRET); } if (debug_flag) { fprintf(stderr,"+++creating semaphore\n"); } /* Couldn't get it because... */ if (errno == ENOENT) { /* it doesn't exist */ /* so let's create it! */ if ((SemId = semget(SemKey, 1, IPC_CREAT | IPC_EXCL | 0666)) == -1) { fprintf(stderr, "%s: can't create semaphore (errno = %d)\n", progname, errno); exit(ERRORRET); } /* Make sure the first time thru, it's unlocked */ if (!semcall(SemId, UNLOCKIT, (short)0)) { fprintf(stderr, "%s: can't initialize semaphore\n", progname); exit(ERRORRET); } } else { /* for now, any other reason is fatal */ fprintf(stderr, "%s: can't get/create semaphore (errno = %d)\n", progname, errno); exit(ERRORRET); } } if (unlockit) { if (!semcall(SemId, UNLOCKIT, (short)0)) { fprintf(stderr, "%s: can't unlock semaphore\n", progname); exit(ERRORRET); } if (!no_remove_sem) { /* let's see if anyone is waiting on it */ int waiting; if (debug_flag && debug_level > 5) { fprintf(stderr, "+++current value of semaphore: %d\n", semctl(SemId, 0, GETVAL, (unsigned *)NULL)); } if ((waiting = semctl(SemId, 0, GETNCNT, (unsigned *)NULL)) == 0) { /* Nope */ /* first, try to lock it again WITHOUT waiting (just in case */ /* someone else snuck in while we weren't looking) */ if (semcall(SemId, LOCKIT, IPC_NOWAIT)) { if (debug_flag) { fprintf(stderr, "+++Locked, ready to delete\n"); } if (semctl(SemId, 0, IPC_RMID, (unsigned *)NULL) == -1) { if (debug_flag) { fprintf(stderr, "+++Couldn't remove semaphore\n"); } } } else { if (debug_flag) { fprintf(stderr, "+++Couldn't sneak a lock in\n"); } } } } } else { if (wlockit) { if (!semcall(SemId, LOCKIT, 0)) { /* couldn't lock it or wait */ fprintf(stderr, "%s: can't lock semaphore or wait on it\n", progname); exit(ERRORRET); } } else { if (nwlockit) { if (!semcall(SemId, LOCKIT, IPC_NOWAIT)) { exit(ERRORRET); } } } } if (verbose) { printf("0x%x %s\n", SemId, unlockit ? "unlocked" : "locked"); } exit(OKRET); } static int semcall(sid, op, sflags) int sid, op; short sflags; { struct sembuf sb; sb.sem_num = 0; sb.sem_op = op; sb.sem_flg = sflags; if (semop(sid, &sb, 1) == -1) { if (errno == EAGAIN) { return(FALSE); } else { fprintf(stderr, "%s: semop error (errno = %d)\n", progname, errno); } } return(TRUE); } @//E*O*F shsem.c// chmod u=r,g=r,o=r shsem.c exit 0 -- !pur-ee!pur-phy!mrstve!rjk Rich Kuhns {ihnp4, decvax, etc...} !itivax!mrstve!rjk