diff options
Diffstat (limited to 'do/ipcctl')
-rw-r--r-- | do/ipcctl | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/do/ipcctl b/do/ipcctl new file mode 100644 index 0000000000..fb3e2430c6 --- /dev/null +++ b/do/ipcctl @@ -0,0 +1,103 @@ +int +do_ipcctl(optype, arglast) +int optype; +int *arglast; +{ + register STR **st = stack->ary_array; + register int sp = arglast[0]; + STR *astr; + char *a; + int id, n, cmd, infosize, getinfo, ret; + + id = (int)str_gnum(st[++sp]); + n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0; + cmd = (int)str_gnum(st[++sp]); + astr = st[++sp]; + + infosize = 0; + getinfo = (cmd == IPC_STAT); + + switch (optype) + { +#ifdef HAS_MSG + case O_MSGCTL: + if (cmd == IPC_STAT || cmd == IPC_SET) + infosize = sizeof(struct msqid_ds); + break; +#endif +#ifdef HAS_SHM + case O_SHMCTL: + if (cmd == IPC_STAT || cmd == IPC_SET) + infosize = sizeof(struct shmid_ds); + break; +#endif +#ifdef HAS_SEM + case O_SEMCTL: + if (cmd == IPC_STAT || cmd == IPC_SET) + infosize = sizeof(struct semid_ds); + else if (cmd == GETALL || cmd == SETALL) + { + struct semid_ds semds; + if (semctl(id, 0, IPC_STAT, &semds) == -1) + return -1; + getinfo = (cmd == GETALL); + infosize = semds.sem_nsems * sizeof(short); + /* "short" is technically wrong but much more portable + than guessing about u_?short(_t)? */ + } + break; +#endif +#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM) + default: + fatal("%s not implemented", opname[optype]); +#endif + } + + if (infosize) + { + if (getinfo) + { + STR_GROW(astr, infosize+1); + a = str_get(astr); + } + else + { + a = str_get(astr); + if (astr->str_cur != infosize) + { + errno = EINVAL; + return -1; + } + } + } + else + { + int i = (int)str_gnum(astr); + a = (char *)i; /* ouch */ + } + errno = 0; + switch (optype) + { +#ifdef HAS_MSG + case O_MSGCTL: + ret = msgctl(id, cmd, (struct msqid_ds *)a); + break; +#endif +#ifdef HAS_SEM + case O_SEMCTL: + ret = semctl(id, n, cmd, a); + break; +#endif +#ifdef HAS_SHM + case O_SHMCTL: + ret = shmctl(id, cmd, (struct shmid_ds *)a); + break; +#endif + } + if (getinfo && ret >= 0) { + astr->str_cur = infosize; + astr->str_ptr[infosize] = '\0'; + } + return ret; +} + |