]> thyrsus.com Git - semex.git/commitdiff
Initial revision
authorEric S. Raymond <esr@thyrsus.com>
Mon, 24 Oct 1994 06:15:51 +0000 (06:15 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Mon, 24 Oct 1994 06:15:51 +0000 (06:15 +0000)
semex.c [new file with mode: 0644]

diff --git a/semex.c b/semex.c
new file mode 100644 (file)
index 0000000..dc7a6fe
--- /dev/null
+++ b/semex.c
@@ -0,0 +1,395 @@
+/*
+ * semex.c --- System V semaphore exerciser
+ *
+ * by Eric S. Raymond <esr@snark.thyrsus.com>
+ */
+#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(), *ctime();
+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) printf("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) printf(
+               "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) printf("semop in process %d failed: %s\n",
+                           getpid(), errmsg(errno));
+       else
+           (void) printf(
+                           "semop in process %d succeeded, returning %d\n",
+                           getpid(), nops);
+    }
+}
+
+main(argc, argv)
+/* exercise the active file 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) printf( "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(cmdline, "f %d", &semid);
+           (void) printf("Semaphore id %d selected\n", semid);
+           break;
+
+       case 'i':       /* set current semaphore number */
+           (void) sscanf(cmdline, "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) printf("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 */
+           {
+               union {
+                   int val;
+                   struct semid_ds *buf;
+                   unsigned short *array;
+               } semval;
+
+               semval.val = 0;
+
+               (void) sscanf(cmdline, "s %d", &semval.val);
+
+               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(0);
+
+       case '!':       /* escape to a shell */
+           (void) system(cmdline + 1);
+           break;
+
+       case '?':       /* print on-line help */
+(void)printf("c(reate) key nsems [ce] perms -- create a semaphore group\n");
+(void)printf("f(ind) semid                  -- selectsemaphore group by id\n");
+(void)printf("i(ndex) semnum                -- select a semaphore index\n");
+(void)printf("d(o) op [un]                  -- do a semaphore operation\n");
+(void)printf("v(alue) semid semnum          -- query a semaphore's semval\n");
+(void)printf("p(id) semid semnum            -- query a semaphore's sempid\n");
+(void)printf("n(cnt) semid semnum           -- query a semaphore's semncnt\n");
+(void)printf("z(cnt) semid semnum           -- query a semaphore's semzcnt\n");
+(void)printf("m(mask) semid uid gid mode    -- query/set semaphore's mode\n");
+(void)printf("r(emove) semid                -- remove a semaphore group\n");
+(void)printf("s(et) semval                  -- set given semaphore's value\n");
+(void)printf("l(ist)                        -- run ipcs -sbopt\n");
+(void)printf("x(it)                         -- exit\n\n");
+
+(void)printf("! cmd                         -- execute a shell command\n");
+(void)printf("?                             -- print this help message\n\n");
+           break;
+
+       default:
+           (void)printf("Illegal command -- type ? for help\n");
+           break;
+       }
+
+       (void) sleep(1);
+    }
+    return(0);
+}
+
+/* semex.c ends here */