home *** CD-ROM | disk | FTP | other *** search
- From: eric@snark.UUCP (Eric S. Raymond)
- Newsgroups: comp.sources.misc
- Subject: Semaphore facilities exerciser for System V
- Message-ID: <4193@ncoast.UUCP>
- Date: 17 Aug 87 00:57:59 GMT
- Sender: allbery@ncoast.UUCP
- Lines: 546
- Approved: allbery@ncoast.UUCP
- X-Archive: comp.sources.misc/8708/16
-
- [I'm testing the new version of my submitter; send me mail if this is screwed
- up somehow. ++bsa]
-
- /*****************************************************************************
-
- NAME
- semex -- interactive exerciser for System V semaphore operations
-
- SYNOPSIS
- semex
-
- DESCRIPTION
- This is an interactive exerciser for the semctl(2), semget(2) and
- semop(2) system calls of System V UNIX. You can use it to experiment with
- the semaphore features in order to understand them better. It includes
- on-line help.
-
- Calls that might cause semex to block (semop(2) with negative operation
- values) are handed to a forked copy of semex. Semex's children emit reports
- just before they block and when they unblock, to enable the user to track
- what's going on.
-
- Semex can also be used as a semaphores interface for scripts. Command
- prompting is suppressed if stdin isn't a tty; so are the verbose
- descriptions of actions performed that it normally emits, and the
- process-forking described above.
-
- COMMANDS
- All arguments of every command are optional; the code tries to give
- reasonable defaults to any you leave off. Anytime a `semid' or `semnum'
- argument is given, the default semid or semnum for future commands is set
- to it.
-
- c(reate) key nsems -[ce] perms -- create a semaphore group
-
- This calls semget(2). The `key' argument should be a long, the `nsems'
- argument an int. The third (flags) argument of the semget(2) call is
- created from the third and fourth arguments of this command; flags
- `c' and `e' stand for IPC_CREAT and IPC_EXCL respectively and `perms'
- should be at least three digits of octal permission mask.
- The `current semaphore group id' (semid) is set to the return value
- of this command.
- The default arguments are `0L 1 - 0660' (note that 0L = IPC_PRIVATE).
-
- f(ind) semid -- select a semaphore group by id
-
- This changes semex's notion of the current semaphore group id. If the
- argument is omitted, the current value is simply printed out.
-
- i(ndex) semnum -- select a semaphore index
-
- This changes semex's notion of the current semaphore index. If the
- argument is omitted, the current value is simply printed out.
-
- d(o) op -[un] -- do a semaphore operation
-
- This command does a semop(2) call. The first argument of the call will
- be the currently selected semaphore id. The third argument (number of
- operations) will be 1. The (struct sembuf *) second argument will point
- to a single operation structure.
- The sem_num field of this structure is set to the `current semaphore
- index' value set by the `n' command (normally 1). The sem_op field is set
- to the value of the `op' command argument (which should be an integer). The
- sem_flg field is set according to the flags in the third command argument;
- `u' stands for SEM_UNDO, `n' for IPC_NOWAIT.
- The argument defaults are `0 -'.
-
- v(alue) semid semnum -- query a semaphore's semval
-
- This command displays the return of a semctl(semid, semnum, GETVAL). If
- semnum is omitted it defaults to the currently selected semaphore index. If
- semid is omitted it defaults to the currently selected semaphore id.
-
- p(id) semid semnum -- query a semaphore's sempid
-
- This command displays the return of a semctl(semid, semnum, GETPID). If
- semnum is omitted it defaults to the currently selected semaphore index. If
- semid is omitted it defaults to the currently selected semaphore id.
-
- n(cnt) semid semnum -- query a semaphore's semncnt
-
- This command displays the return of a semctl(semid, semnum, GETNCNT). If
- semnum is omitted it defaults to the currently selected semaphore index. If
- semid is omitted it defaults to the currently selected semaphore id.
-
- z(cnt) semid semnum -- query a semaphore's semzcnt
-
- This command displays the return of a semctl(semid, semnum, GETZCNT). If
- semnum is omitted it defaults to the currently selected semaphore index. If
- semid is omitted it defaults to the currently selected semaphore id.
-
- s(et) semval -- set the value of a semaphore
-
- This command does a semop(2) call using the SETVAL command to set
- the value of the currently selected semaphore. The first argument of the call
- will be the currently selected semaphore id. The second argument of the call
- will be the currently selected semaphore index. The fourth (value) argument
- will be the semval argument of the command (which defaults to 0 if omitted).
-
- m(mask) semid uid gid mode -- query/set a semaphore's mode
-
- The m command with no arguments displays the uid, gid and mode
- of the currently selected semaphore group. With one argument, it displays
- this information for the given semaphore group. With two or more arguments
- it sets whatever portions of the mode and ownership data are given; uid and
- gid should be decimal integers and mode at least three digits of octal.
-
- r(emove) semid -- remove a semaphore group
-
- Do a semctl(2) to remove a semaphore group. If the semid argument is
- omitted, the currently selected semaphore group will be removed.
-
- l(ist) -- run ipcs -sbopt
-
- This is just a convenience. It displays data on active semaphores.
-
- x(it) -- exit
-
- Exit semex. Child semex processes created by 'd' commands will get SIGHUP
- and die gracefully.
-
- ! cmd -- execute a shell command
-
- Escape to a shell.
-
- ? -- print this help message
-
- In addition, typing a newline will simply display the value of the
- currently selected semaphore (newline is a synonym for the `v' command).
-
- NOTE
- The AT&T documentation entries for semop(2) tell lies about the type of
- the second argument. System V Release 1 claims the type is
-
- struct sembuf (*)[]
-
- and its lint library entry is correspondingly broken. Release 2 claims
- that it's
-
- struct sembuf **
-
- but its lint library checks for the correct type, which is
-
- struct sembuf *
-
- as one can actually deduce from the description text for both entries.
-
- BUGS
- The 'p' and 'v' commands are not Dyskstra's P and V operations.
- There is no way for semex to specify more than one semaphore op at once
- in semop(2).
- There is no support for exercising the GETALL or SETALL modes of semctl(2).
-
- AUTHOR
- Eric S. Raymond {{ihnp4,seismo}!cbmvax,hplabs!sdcrdcf!burdvax}!snark!eric
-
- *****************************************************************************/
- /* LINTLIBRARY */
-
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
-
- extern int errno;
- extern void exit();
- extern char *strchr(), *strcat();
- extern unsigned sleep();
-
- /*
- * This will need to change if any future version changes the define values
- * of any UNIX error types. The highest value currently recognized is
- * EIDRM; the code that uses it in errmsg() will issue a generic error type
- * for higher values.
- */
- static char *errtypes[] =
- {
- "?",
- "EPERM", /* Not super-user */
- "ENOENT", /* No such file or directory */
- "ESRCH", /* No such process */
- "EINTR", /* interrupted system call */
- "EIO", /* I/O error */
- "ENXIO", /* No such device or address */
- "E2BIG", /* Arg list too long */
- "ENOEXEC", /* Exec format error */
- "EBADF", /* Bad file number */
- "ECHILD", /* No children */
- "EAGAIN", /* No more processes */
- "ENOMEM", /* Not enough core */
- "EACCES", /* Permission denied */
- "EFAULT", /* Bad address */
- "ENOTBLK", /* Block device required */
- "EBUSY", /* Mount device busy */
- "EEXIST", /* File exists */
- "EXDEV", /* Cross-device link */
- "ENODEV", /* No such device */
- "ENOTDIR", /* Not a directory */
- "EISDIR", /* Is a directory */
- "EINVAL", /* Invalid argument */
- "ENFILE", /* File table overflow */
- "EMFILE", /* Too many open files */
- "ENOTTY", /* Not a typewriter */
- "ETXTBSY", /* Text file busy */
- "EFBIG", /* File too large */
- "ENOSPC", /* No space left on device */
- "ESPIPE", /* Illegal seek */
- "EROFS", /* Read only file system */
- "EMLINK", /* Too many links */
- "EPIPE", /* Broken pipe */
- "EDOM", /* Math arg out of domain of func */
- "ERANGE", /* Math result not representable */
- "ENOMSG", /* No message of desired type */
- "EIDRM", /* Identifier removed */
- };
-
- static ushort parent;
- static int tty;
-
- static void sigabort(sig)
- /* log the occurrence of a signal, die gracefully if it's SIGHUP */
- int sig; /* the signal number */
- {
- (void) fprintf("Received signal %d\n", sig);
- if (sig == SIGHUP)
- exit(0);
- }
-
- static char *errmsg(code)
- /* return the UNIX error message for a given errno code */
- int code;
- {
- extern int sys_nerr;
- extern char *sys_errlist[];
- static char ebuf[BUFSIZ];
-
- (void) sprintf(ebuf, "error %d", code);
-
- if (code < sizeof(errtypes) / sizeof(char *))
- {
- (void) strcat(ebuf, " (");
- (void) strcat(ebuf, errtypes[code]);
- (void) strcat(ebuf, ")");
- }
-
- if (code <= sys_nerr)
- {
- (void) strcat(ebuf, ", ");
- (void) strcat(ebuf, sys_errlist[code]);
- }
-
- return(ebuf);
- }
-
- void shsemop(semid, sops, nops)
- /* perform a semaphore op, announcing the specifics of the operation */
- int semid;
- struct sembuf *sops;
- int nops;
- {
- if (tty)
- (void) fprintf(stdout,
- "semop(%d, {%hd, %hd, %hd}, %d) in process %d\n",
- semid, sops->sem_num, sops->sem_op, sops->sem_flg,
- nops, getpid());
-
- nops = semop(semid, sops, nops);
-
- if (tty)
- {
- /* if we're in the parent, give child processes time to report */
- if (getpid() == parent)
- (void) sleep(2);
-
- if (nops == -1)
- (void) fprintf(stdout,"semop in process %d failed: %s\n",
- getpid(), errmsg(errno));
- else
- (void) fprintf(stdout,
- "semop in process %d succeeded, returning %d\n",
- getpid(), nops);
- }
- }
-
- main(argc, argv)
- /* excercise the semaphore functions */
- int argc;
- char *argv[];
- {
- key_t key = IPC_PRIVATE;
- int sc, rv, nsems, perms, semflg, semid, semnum = 0;
- struct sembuf sop;
- char cmdline[BUFSIZ], strbuf[BUFSIZ];
-
- parent = getpid();
- tty = isatty(fileno(stdin));
-
- for (rv = SIGHUP; rv <= SIGTERM; rv++)
- (void) signal(rv, sigabort);
-
- if (tty)
- {
- (void) puts("This is the semaphore exerciser, type ? for help");
- (void) fprintf(stdout, "The exerciser process pid is %d\n", parent);
- }
- while ((!tty || fputs("> ", stdout) != EOF) && gets(cmdline))
- {
- errno = 0;
-
- switch(cmdline[0])
- {
- case 'c': /* create and select a new semaphore */
- key = IPC_PRIVATE;
- nsems = 1;
- perms = 0660; /* read & alter by owning user & group */
- semflg = 0;
-
- sc = sscanf(cmdline, "c %ld %d %s %o", &key,&nsems,strbuf,&perms);
-
- if (sc >= 3)
- {
- if (strchr(strbuf, 'c') != (char *)NULL)
- semflg |= IPC_CREAT;
-
- if (strchr(strbuf, 'e') != (char *)NULL)
- semflg |= IPC_EXCL;
- }
- semflg |= perms;
-
- semid = semget(key, nsems, semflg);
- if (tty)
- {
- (void) printf("semget(%ld, %d, %04o) ", key, nsems, semflg);
- if (semid == -1)
- (void) printf("failed: %s\n", errmsg(errno));
- else
- (void) printf("succeeded, semid = %d\n", semid);
- }
- break;
-
- case 'f': /* select a given semaphore group */
- (void) sscanf("f %d", &semid);
- (void) printf("Semaphore id %d selected\n", semid);
- break;
-
- case 'i': /* set current semaphore number */
- (void) sscanf("i %d", &semnum);
- (void) printf("Semaphore index %d selected\n", semnum);
- break;
-
- case 'd': /* perform a semaphore operation */
- sc = sscanf(cmdline, "d %hd %s", &sop.sem_op, strbuf);
- sop.sem_num = semnum;
-
- if (sc == 0)
- sop.sem_op = 0;
-
- if (sc <= 1)
- sop.sem_flg = 0;
-
- if (sc == 2)
- {
- if (strchr(strbuf, 'u') != (char *)NULL)
- sop.sem_flg |= SEM_UNDO;
-
- if (strchr(strbuf, 'n') != (char *)NULL)
- sop.sem_flg |= IPC_NOWAIT;
- }
-
- if (tty && sop.sem_op < 0)
- {
- if (rv = fork()) /* parent side */
- {
- (void)fprintf(stdout,"Spawning child with pid = %d\n",rv);
- (void) sleep(1);
- }
- else /* child side */
- {
- (void) sleep(1);
- shsemop(semid, &sop, 1);
- exit(0);
- }
- }
- else
- shsemop(semid, &sop, 1);
- break;
-
- case 'v':
- case '\0':
- (void) sscanf(cmdline, "v %d %d\n", &semid, &semnum);
- if (tty)
- (void) printf("semctl(%d, %d, GETVAL) returns %d\n",
- semid, semnum, semctl(semid, semnum, GETVAL));
- break;
-
- case 'p':
- (void) sscanf(cmdline, "p %d %d\n", &semid, &semnum);
- if (tty)
- (void) printf("semctl(%d, %d, GETPID) returns %d\n",
- semid, semnum, semctl(semid, semnum, GETPID));
- break;
-
- case 'n':
- (void) sscanf(cmdline, "n %d %d\n", &semid, &semnum);
- if (tty)
- (void) printf("semctl(%d, %d, GETNCNT) returns %d\n",
- semid, semnum, semctl(semid, semnum, GETNCNT));
- break;
-
- case 'z':
- (void) sscanf(cmdline, "z %d %d\n", &semid, &semnum);
- if (tty)
- (void) printf("semctl(%d, %d, GETZCNT) returns %d\n",
- semid, semnum, semctl(semid, semnum, GETZCNT));
- break;
-
- case 's': /* set the value of a semaphore */
- {
- int semval = 0;
-
- (void) sscanf(cmdline, "s %d", &semval);
-
- rv = semctl(semid, semnum, SETVAL, semval);
- if (tty)
- {
- (void) printf("semctl(%d, %d, SETVAL, %d) ",
- semid, semnum, semval);
- if (rv == -1)
- (void) printf("failed: %s\n", errmsg(errno));
- else
- (void) printf("succeeded, returning %d\n", rv);
- }
- }
- break;
-
- case 'm': /* query-set mode information */
- {
- int uid, gid, mode;
- struct semid_ds ds;
-
- sc = sscanf(cmdline, "m %d %d %d %o", &semid,&uid,&gid,&mode);
-
- rv = semctl(semid, semnum, IPC_STAT, &ds);
-
- /* retrieve and show the existing modes */
- (void) printf("semctl(%d, %d, IPC_STAT, &ds) ", semnum,semid);
- if (rv == -1)
- (void) printf("failed: %s\n", errmsg(errno));
- else
- {
- (void) printf("succeeded, returning %d\n", rv);
- (void) printf("Here is the semaphore group data:\nds = {\n");
- (void) printf(" sem_perm.uid = %d\n", ds.sem_perm.uid);
- (void) printf(" sem_perm.gid = %d\n", ds.sem_perm.gid);
- (void) printf(" sem_perm.mode = %04o\n", ds.sem_perm.mode);
- (void) printf(" sem_nsems = %d\n", ds.sem_nsems);
- (void) printf(" sem_otime = (%ld) %s",
- ds.sem_otime, ctime(&ds.sem_otime));
- (void) printf(" sem_ctime = (%ld) %s}\n",
- ds.sem_ctime, ctime(&ds.sem_ctime));
- }
-
- /* if two or more arguments were given, set new modes */
- if (sc >= 2)
- {
- ds.sem_perm.uid = uid;
- if (sc >= 3)
- ds.sem_perm.gid = gid;
- if (sc >= 4)
- ds.sem_perm.mode = mode;
-
- rv = semctl(semid, semnum, IPC_SET, &ds);
- if (tty)
- {
- (void) printf("semctl(%d, %d, IPC_SET, &ds) ",
- semnum, semid);
- if (rv == -1)
- (void) printf("failed: %s\n", errmsg(errno));
- else
- (void) printf("succeeded, returning %d\n", rv);
- }
- }
- }
- break;
-
- case 'r': /* delete an existing semaphore */
- (void) sscanf(cmdline, "r %d", &semid);
-
- rv = semctl(semid, 0, IPC_RMID);
-
- if (tty)
- {
- (void) printf("semctl(%d, 0, IPC_RMID) ", semid);
- if (rv == -1)
- (void) printf("failed: %s\n", errmsg(errno));
- else
- (void) printf("succeeded\n");
- }
- break;
-
- case 'l': /* list status of semaphore groups */
- (void) system("exec ipcs -sbopt");
- break;
-
- case 'x': /* leave */
- return;
-
- case '!': /* escape to a shell */
- (void) system(cmdline + 1);
- break;
-
- case '?': /* print on-line help */
- printf("c(reate) key nsems [ce] perms -- create a semaphore group\n");
- printf("f(ind) semid -- select a semaphore group by id\n");
- printf("i(ndex) semnum -- select a semaphore index\n");
- printf("d(o) op [un] -- do a semaphore operation\n");
- printf("v(alue) semid semnum -- query a semaphore's semval\n");
- printf("p(id) semid semnum -- query a semaphore's sempid\n");
- printf("n(cnt) semid semnum -- query a semaphore's semncnt\n");
- printf("z(cnt) semid semnum -- query a semaphore's semzcnt\n");
- printf("m(mask) semid uid gid mode -- query/set a semaphore's mode\n");
- printf("r(emove) semid -- remove a semaphore group\n");
- printf("s(et) semval -- set the value of a semaphore\n");
- printf("l(ist) -- run ipcs -sbopt\n");
- printf("x(it) -- exit\n\n");
-
- printf("! cmd -- execute a shell command\n");
- printf("? -- print this help message\n\n");
- break;
-
- default:
- (void)printf("Illegal command -- type ? for help\n");
- break;
- }
-
- (void) sleep(1);
- }
- }
-
- /* semex.c ends here */
- --
- Eric S. Raymond
- UUCP: {{seismo,ihnp4,rutgers}!cbmvax,sdcrdcf!burdvax}!snark!eric
- Post: 22 South Warren Avenue, Malvern, PA 19355
- Phone: (215)-296-5718
-