IPC server: restyle

Closer to KNF, better coding practices, more similar to other
services, no more global variables, a few more comments, that
kind of stuff.  No major functional changes.

Change-Id: I6e8f53bfafd6f41e92031fba76c40a31d2107a8e
This commit is contained in:
David van Moolenbroek 2015-11-25 22:37:19 +00:00 committed by Lionel Sambuc
parent 4d272e5a97
commit 0baafa0ef4
5 changed files with 348 additions and 375 deletions

View File

@ -11,6 +11,7 @@
#include <minix/syslib.h> #include <minix/syslib.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h>
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/shm.h> #include <sys/shm.h>
#include <sys/sem.h> #include <sys/sem.h>
@ -38,17 +39,20 @@
#define IPCID_TO_IX(id) ((id) & 0xffff) #define IPCID_TO_IX(id) ((id) & 0xffff)
#define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff) #define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff)
/* shm.c */
int do_shmget(message *); int do_shmget(message *);
int do_shmat(message *); int do_shmat(message *);
int do_shmdt(message *); int do_shmdt(message *);
int do_shmctl(message *); int do_shmctl(message *);
int check_perm(struct ipc_perm *, endpoint_t, int); int is_shm_nil(void);
void update_refcount_and_destroy(void); void update_refcount_and_destroy(void);
/* sem.c */
int do_semget(message *); int do_semget(message *);
int do_semctl(message *); int do_semctl(message *);
int do_semop(message *); int do_semop(message *);
int is_sem_nil(void); int is_sem_nil(void);
int is_shm_nil(void);
void sem_process_vm_notify(void); void sem_process_vm_notify(void);
EXTERN endpoint_t who_e; /* utility.c */
int check_perm(struct ipc_perm *, endpoint_t, int);

View File

@ -1,8 +1,8 @@
#include "inc.h" #include "inc.h"
endpoint_t who_e; /*
static unsigned int call_type; * The call table for this service.
*/
#define CALL(n) [((n) - IPC_BASE)] #define CALL(n) [((n) - IPC_BASE)]
static int (* const call_vec[])(message *) = { static int (* const call_vec[])(message *) = {
CALL(IPC_SHMGET) = do_shmget, CALL(IPC_SHMGET) = do_shmget,
@ -16,90 +16,37 @@ static int (* const call_vec[])(message *) = {
static int verbose = 0; static int verbose = 0;
/* SEF functions and variables. */ /*
static void sef_local_startup(void); * Initialize the IPC server.
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
static void sef_cb_signal_handler(int signo);
int main(int argc, char *argv[])
{
message m;
unsigned int ipc_number;
int r;
/* SEF local startup. */
env_setargs(argc, argv);
sef_local_startup();
while (TRUE) {
if ((r = sef_receive(ANY, &m)) != OK)
printf("sef_receive failed %d.\n", r);
who_e = m.m_source;
call_type = m.m_type;
if(verbose)
printf("IPC: get %d from %d\n", call_type, who_e);
if (call_type & NOTIFY_MESSAGE) {
switch (who_e) {
case VM_PROC_NR:
/* currently, only semaphore needs such information. */
sem_process_vm_notify();
break;
default:
printf("IPC: ignoring notify() from %d\n",
who_e);
break;
}
continue;
}
ipc_number = (unsigned int)(call_type - IPC_BASE);
/* dispatch message */
if (ipc_number < __arraycount(call_vec) &&
call_vec[ipc_number] != NULL) {
/* If any process does an IPC call,
* we have to know about it exiting.
* Tell VM to watch it for us.
*/ */
if(vm_watch_exit(m.m_source) != OK) { static int
printf("IPC: watch failed on %d\n", m.m_source); sef_cb_init_fresh(int type __unused, sef_init_info_t * info __unused)
{
return OK;
} }
r = call_vec[ipc_number](&m); static void
sef_cb_signal_handler(int signo)
{
/* Only check for termination signal, ignore anything else. */
if (signo != SIGTERM) return;
/* /*
* The handler of the IPC call did not * Check if there are still IPC keys around. If not, we can safely
* post a reply. * exit immediately. Otherwise, warn the system administrator.
*/ */
if (r != SUSPEND) { if (is_sem_nil() && is_shm_nil())
m.m_type = r; sef_exit(0);
if(verbose && r != OK) printf("IPC: exit with unclean state\n");
printf("IPC: error for %d: %d\n",
call_type, r);
if ((r = ipc_sendnb(who_e, &m)) != OK)
printf("IPC send error %d.\n", r);
}
} else {
/* warn and then ignore */
printf("IPC unknown call type: %d from %d.\n",
call_type, who_e);
}
update_refcount_and_destroy();
} }
/* no way to get here */ static void
return -1; sef_local_startup(void)
}
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
static void sef_local_startup(void)
{ {
/* Register init callbacks. */ /* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh); sef_setcb_init_fresh(sef_cb_init_fresh);
sef_setcb_init_restart(sef_cb_init_fresh); sef_setcb_init_restart(sef_cb_init_fresh);
@ -111,30 +58,80 @@ static void sef_local_startup(void)
sef_startup(); sef_startup();
} }
/*===========================================================================* int
* sef_cb_init_fresh * main(int argc, char ** argv)
*===========================================================================*/
static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
{ {
/* Initialize the ipc server. */ message m;
unsigned int call_index;
int r, ipc_status;
/* SEF local startup. */
env_setargs(argc, argv);
sef_local_startup();
/* The main message loop. */
for (;;) {
if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK)
panic("IPC: sef_receive_status failed: %d", r);
if (verbose) if (verbose)
printf("IPC: self: %d\n", sef_self()); printf("IPC: got %d from %d\n", m.m_type, m.m_source);
return(OK); if (is_ipc_notify(ipc_status)) {
switch (m.m_source) {
case VM_PROC_NR:
/*
* Currently, only semaphore handling needs
* to know about processes exiting.
*/
sem_process_vm_notify();
break;
default:
printf("IPC: ignoring notification from %d\n",
m.m_source);
break;
}
continue;
} }
/*===========================================================================* /* Dispatch the request. */
* sef_cb_signal_handler * call_index = (unsigned int)(m.m_type - IPC_BASE);
*===========================================================================*/
static void sef_cb_signal_handler(int signo)
{
/* Only check for termination signal, ignore anything else. */
if (signo != SIGTERM) return;
/* Checkout if there are still IPC keys. Inform the user in that case. */ if (call_index < __arraycount(call_vec) &&
if (is_sem_nil() && is_shm_nil()) call_vec[call_index] != NULL) {
sef_exit(0); /*
* If any process does an IPC call, we have to know
printf("IPC: exit with un-clean states.\n"); * about it exiting. Tell VM to watch it for us.
* TODO: this is not true; limit to affected processes.
*/
if (vm_watch_exit(m.m_source) != OK) {
printf("IPC: watch failed on %d\n",
m.m_source);
}
r = call_vec[call_index](&m);
} else
r = ENOSYS;
/* Send a reply, if needed. */
if (r != SUSPEND) {
if (verbose)
printf("IPC: call result %d\n", r);
m.m_type = r;
/*
* Other fields may have been set by the handler
* function already.
*/
if ((r = ipc_sendnb(m.m_source, &m)) != OK)
printf("IPC: send error %d\n", r);
}
/* XXX there must be a better way to do this! */
update_refcount_and_destroy();
}
/* NOTREACHED */
return 0;
} }

View File

@ -22,22 +22,26 @@ struct sem_struct {
static struct sem_struct sem_list[SEMMNI]; static struct sem_struct sem_list[SEMMNI];
static unsigned int sem_list_nr = 0; /* highest in-use slot number plus one */ static unsigned int sem_list_nr = 0; /* highest in-use slot number plus one */
static struct sem_struct *sem_find_key(key_t key) static struct sem_struct *
sem_find_key(key_t key)
{ {
unsigned int i; unsigned int i;
if (key == IPC_PRIVATE) if (key == IPC_PRIVATE)
return NULL; return NULL;
for (i = 0; i < sem_list_nr; i++) { for (i = 0; i < sem_list_nr; i++) {
if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC)) if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
continue; continue;
if (sem_list[i].semid_ds.sem_perm._key == key) if (sem_list[i].semid_ds.sem_perm._key == key)
return &sem_list[i]; return &sem_list[i];
} }
return NULL; return NULL;
} }
static struct sem_struct *sem_find_id(int id) static struct sem_struct *
sem_find_id(int id)
{ {
struct sem_struct *sem; struct sem_struct *sem;
unsigned int i; unsigned int i;
@ -54,10 +58,8 @@ static struct sem_struct *sem_find_id(int id)
return sem; return sem;
} }
/*===========================================================================* int
* do_semget * do_semget(message * m)
*===========================================================================*/
int do_semget(message *m)
{ {
struct sem_struct *sem; struct sem_struct *sem;
unsigned int i, seq; unsigned int i, seq;
@ -68,10 +70,10 @@ int do_semget(message *m)
nsems = m->m_lc_ipc_semget.nr; nsems = m->m_lc_ipc_semget.nr;
flag = m->m_lc_ipc_semget.flag; flag = m->m_lc_ipc_semget.flag;
if ((sem = sem_find_key(key))) { if ((sem = sem_find_key(key)) != NULL) {
if ((flag & IPC_CREAT) && (flag & IPC_EXCL)) if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
return EEXIST; return EEXIST;
if (!check_perm(&sem->semid_ds.sem_perm, who_e, flag)) if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, flag))
return EACCES; return EACCES;
if (nsems > sem->semid_ds.sem_nsems) if (nsems > sem->semid_ds.sem_nsems)
return EINVAL; return EINVAL;
@ -92,12 +94,12 @@ int do_semget(message *m)
/* Initialize the entry. */ /* Initialize the entry. */
sem = &sem_list[i]; sem = &sem_list[i];
seq = sem->semid_ds.sem_perm._seq; seq = sem->semid_ds.sem_perm._seq;
memset(sem, 0, sizeof(struct sem_struct)); memset(sem, 0, sizeof(*sem));
sem->semid_ds.sem_perm._key = key; sem->semid_ds.sem_perm._key = key;
sem->semid_ds.sem_perm.cuid = sem->semid_ds.sem_perm.cuid =
sem->semid_ds.sem_perm.uid = getnuid(who_e); sem->semid_ds.sem_perm.uid = getnuid(m->m_source);
sem->semid_ds.sem_perm.cgid = sem->semid_ds.sem_perm.cgid =
sem->semid_ds.sem_perm.gid = getngid(who_e); sem->semid_ds.sem_perm.gid = getngid(m->m_source);
sem->semid_ds.sem_perm.mode = SEM_ALLOC | (flag & ACCESSPERMS); sem->semid_ds.sem_perm.mode = SEM_ALLOC | (flag & ACCESSPERMS);
sem->semid_ds.sem_perm._seq = (seq + 1) & 0x7fff; sem->semid_ds.sem_perm._seq = (seq + 1) & 0x7fff;
sem->semid_ds.sem_nsems = nsems; sem->semid_ds.sem_nsems = nsems;
@ -113,25 +115,42 @@ int do_semget(message *m)
return OK; return OK;
} }
static void send_message_to_process(endpoint_t who, int ret, int ignore) static void
send_reply(endpoint_t who, int ret)
{ {
message m; message m;
memset(&m, 0, sizeof(m));
m.m_type = ret; m.m_type = ret;
ipc_sendnb(who, &m); ipc_sendnb(who, &m);
} }
static void remove_semaphore(struct sem_struct *sem) static void
remove_semaphore(struct sem_struct * sem)
{ {
int i, nr; int i, j, nr;
struct semaphore *semaphore;
nr = sem->semid_ds.sem_nsems; nr = sem->semid_ds.sem_nsems;
/* Deal with processes waiting for this semaphore set. */
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
if (sem->sems[i].zlist) semaphore = &sem->sems[i];
free(sem->sems[i].zlist);
if (sem->sems[i].nlist) for (j = 0; j < semaphore->semzcnt; j++)
free(sem->sems[i].nlist); send_reply(semaphore->zlist[j].who, EIDRM);
for (j = 0; j < semaphore->semncnt; j++)
send_reply(semaphore->nlist[j].who, EIDRM);
if (semaphore->zlist != NULL) {
free(semaphore->zlist);
semaphore->zlist = NULL;
}
if (semaphore->nlist != NULL) {
free(semaphore->nlist);
semaphore->nlist = NULL;
}
} }
/* Mark the entry as free. */ /* Mark the entry as free. */
@ -147,7 +166,8 @@ static void remove_semaphore(struct sem_struct *sem)
} }
#if 0 #if 0
static void show_semaphore(void) static void
show_semaphore(void)
{ {
unsigned int i; unsigned int i;
int j, k, nr; int j, k, nr;
@ -176,7 +196,8 @@ static void show_semaphore(void)
printf("incr("); printf("incr(");
for (k = 0; k < semaphore->semncnt; k++) for (k = 0; k < semaphore->semncnt; k++)
printf("%d-%d,", printf("%d-%d,",
semaphore->nlist[k].who, semaphore->nlist[k].val); semaphore->nlist[k].who,
semaphore->nlist[k].val);
printf(")"); printf(")");
} }
printf("\n"); printf("\n");
@ -186,11 +207,14 @@ static void show_semaphore(void)
} }
#endif #endif
static void remove_process(endpoint_t pt) static void
remove_process(endpoint_t endpt)
{ {
struct sem_struct *sem; struct sem_struct *sem;
struct semaphore *semaphore;
endpoint_t who_waiting;
unsigned int i; unsigned int i;
int j, nr; int j, k, nr;
for (i = 0; i < sem_list_nr; i++) { for (i = 0; i < sem_list_nr; i++) {
sem = &sem_list[i]; sem = &sem_list[i];
@ -199,34 +223,39 @@ static void remove_process(endpoint_t pt)
nr = sem->semid_ds.sem_nsems; nr = sem->semid_ds.sem_nsems;
for (j = 0; j < nr; j++) { for (j = 0; j < nr; j++) {
struct semaphore *semaphore = &sem->sems[j]; semaphore = &sem->sems[j];
int k;
for (k = 0; k < semaphore->semzcnt; k++) { for (k = 0; k < semaphore->semzcnt; k++) {
endpoint_t who_waiting = semaphore->zlist[k].who; who_waiting = semaphore->zlist[k].who;
if (who_waiting == pt) { if (who_waiting == endpt) {
/* remove this slot first */ /* Remove this slot first. */
memmove(semaphore->zlist+k, semaphore->zlist+k+1, memmove(semaphore->zlist + k,
sizeof(struct waiting) * (semaphore->semzcnt-k-1)); semaphore->zlist + k + 1,
--semaphore->semzcnt; sizeof(struct waiting) *
/* then send message to the process */ (semaphore->semzcnt - k - 1));
send_message_to_process(who_waiting, EINTR, 1); semaphore->semzcnt--;
/* Then send message to the process. */
send_reply(who_waiting, EINTR);
break; break;
} }
} }
for (k = 0; k < semaphore->semncnt; k++) { for (k = 0; k < semaphore->semncnt; k++) {
endpoint_t who_waiting = semaphore->nlist[k].who; who_waiting = semaphore->nlist[k].who;
if (who_waiting == pt) { if (who_waiting == endpt) {
/* remove it first */ /* Remove it first. */
memmove(semaphore->nlist+k, semaphore->nlist+k+1, memmove(semaphore->nlist + k,
sizeof(struct waiting) * (semaphore->semncnt-k-1)); semaphore->nlist + k + 1,
--semaphore->semncnt; sizeof(struct waiting) *
/* send the message to the process */ (semaphore->semncnt-k-1));
send_message_to_process(who_waiting, EINTR, 1); semaphore->semncnt--;
/* Send the message to the process. */
send_reply(who_waiting, EINTR);
break; break;
} }
@ -235,7 +264,8 @@ static void remove_process(endpoint_t pt)
} }
} }
static void update_one_semaphore(struct sem_struct *sem, int is_remove) static void
check_semaphore(struct sem_struct * sem)
{ {
int i, j, nr; int i, j, nr;
struct semaphore *semaphore; struct semaphore *semaphore;
@ -243,47 +273,35 @@ static void update_one_semaphore(struct sem_struct *sem, int is_remove)
nr = sem->semid_ds.sem_nsems; nr = sem->semid_ds.sem_nsems;
if (is_remove) {
for (i = 0; i < nr; i++) {
semaphore = &sem->sems[i];
for (j = 0; j < semaphore->semzcnt; j++)
send_message_to_process(semaphore->zlist[j].who, EIDRM, 0);
for (j = 0; j < semaphore->semncnt; j++)
send_message_to_process(semaphore->nlist[j].who, EIDRM, 0);
}
remove_semaphore(sem);
return;
}
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
semaphore = &sem->sems[i]; semaphore = &sem->sems[i];
if (semaphore->zlist && !semaphore->semval) { if (semaphore->zlist && !semaphore->semval) {
/* choose one process, policy: FIFO. */ /* Choose one process, policy: FIFO. */
who = semaphore->zlist[0].who; who = semaphore->zlist[0].who;
memmove(semaphore->zlist, semaphore->zlist + 1, memmove(semaphore->zlist, semaphore->zlist + 1,
sizeof(struct waiting) * (semaphore->semzcnt - 1)); sizeof(struct waiting) * (semaphore->semzcnt - 1));
--semaphore->semzcnt; semaphore->semzcnt--;
send_message_to_process(who, OK, 0); send_reply(who, OK);
} }
if (semaphore->nlist) { if (semaphore->nlist) {
for (j = 0; j < semaphore->semncnt; j++) { for (j = 0; j < semaphore->semncnt; j++) {
if (semaphore->nlist[j].val <= semaphore->semval) { if (semaphore->nlist[j].val <=
semaphore->semval -= semaphore->nlist[j].val; semaphore->semval) {
semaphore->semval -=
semaphore->nlist[j].val;
who = semaphore->nlist[j].who; who = semaphore->nlist[j].who;
memmove(semaphore->nlist+j, semaphore->nlist+j+1, memmove(semaphore->nlist + j,
sizeof(struct waiting) * (semaphore->semncnt-j-1)); semaphore->nlist + j + 1,
--semaphore->semncnt; sizeof(struct waiting) *
(semaphore->semncnt-j-1));
semaphore->semncnt--;
send_message_to_process(who, OK, 0); send_reply(who, OK);
/* choose only one process */
break; break;
} }
} }
@ -291,28 +309,15 @@ static void update_one_semaphore(struct sem_struct *sem, int is_remove)
} }
} }
static void update_semaphores(void) int
{ do_semctl(message * m)
unsigned int i;
for (i = 0; i < sem_list_nr; i++) {
if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
continue;
update_one_semaphore(&sem_list[i], FALSE /*is_remove*/);
}
}
/*===========================================================================*
* do_semctl *
*===========================================================================*/
int do_semctl(message *m)
{ {
unsigned int i; unsigned int i;
vir_bytes opt; vir_bytes opt;
uid_t uid; uid_t uid;
int r, id, num, cmd, val; int r, id, num, cmd, val;
unsigned short *buf; unsigned short *buf;
struct semid_ds *ds, tmp_ds; struct semid_ds tmp_ds;
struct sem_struct *sem; struct sem_struct *sem;
struct seminfo sinfo; struct seminfo sinfo;
@ -334,37 +339,38 @@ int do_semctl(message *m)
return EINVAL; return EINVAL;
break; break;
default: default:
if (!(sem = sem_find_id(id))) if ((sem = sem_find_id(id)) == NULL)
return EINVAL; return EINVAL;
break; break;
} }
/* IPC_SET and IPC_RMID as its own permission check */ /*
* IPC_SET and IPC_RMID have their own permission checks. IPC_INFO and
* SEM_INFO are free for general use.
*/
if (sem != NULL && cmd != IPC_SET && cmd != IPC_RMID) { if (sem != NULL && cmd != IPC_SET && cmd != IPC_RMID) {
/* check read permission */ /* Check read permission. */
if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444)) if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, 0444))
return EACCES; return EACCES;
} }
switch (cmd) { switch (cmd) {
case IPC_STAT: case IPC_STAT:
case SEM_STAT: case SEM_STAT:
if ((r = sys_datacopy(SELF, (vir_bytes)&sem->semid_ds, who_e, if ((r = sys_datacopy(SELF, (vir_bytes)&sem->semid_ds,
(vir_bytes)opt, sizeof(sem->semid_ds))) != OK) m->m_source, opt, sizeof(sem->semid_ds))) != OK)
return r; return r;
if (cmd == SEM_STAT) if (cmd == SEM_STAT)
m->m_lc_ipc_semctl.ret = m->m_lc_ipc_semctl.ret =
IXSEQ_TO_IPCID(id, sem->semid_ds.sem_perm); IXSEQ_TO_IPCID(id, sem->semid_ds.sem_perm);
break; break;
case IPC_SET: case IPC_SET:
uid = getnuid(who_e); uid = getnuid(m->m_source);
if (uid != sem->semid_ds.sem_perm.cuid && if (uid != sem->semid_ds.sem_perm.cuid &&
uid != sem->semid_ds.sem_perm.uid && uid != sem->semid_ds.sem_perm.uid && uid != 0)
uid != 0)
return EPERM; return EPERM;
ds = (struct semid_ds *) opt; if ((r = sys_datacopy(m->m_source, opt, SELF,
if ((r = sys_datacopy(who_e, (vir_bytes)ds, SELF, (vir_bytes)&tmp_ds, sizeof(tmp_ds))) != OK)
(vir_bytes)&tmp_ds, sizeof(struct semid_ds))) != OK)
return r; return r;
sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid; sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid;
sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid; sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid;
@ -374,15 +380,15 @@ int do_semctl(message *m)
sem->semid_ds.sem_ctime = clock_time(NULL); sem->semid_ds.sem_ctime = clock_time(NULL);
break; break;
case IPC_RMID: case IPC_RMID:
uid = getnuid(who_e); uid = getnuid(m->m_source);
if (uid != sem->semid_ds.sem_perm.cuid && if (uid != sem->semid_ds.sem_perm.cuid &&
uid != sem->semid_ds.sem_perm.uid && uid != sem->semid_ds.sem_perm.uid && uid != 0)
uid != 0)
return EPERM; return EPERM;
/* awaken all processes block in semop /*
* and remove the semaphore set. * Awaken all processes blocked in semop(2) on any semaphore in
* this set, and remove the semaphore set itself.
*/ */
update_one_semaphore(sem, TRUE /*is_remove*/); remove_semaphore(sem);
break; break;
case IPC_INFO: case IPC_INFO:
case SEM_INFO: case SEM_INFO:
@ -413,8 +419,8 @@ int do_semctl(message *m)
} else } else
sinfo.semaem = 0; /* TODO: support for SEM_UNDO */ sinfo.semaem = 0; /* TODO: support for SEM_UNDO */
if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, who_e, if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, m->m_source,
(vir_bytes)opt, sizeof(sinfo))) != OK) opt, sizeof(sinfo))) != OK)
return r; return r;
/* Return the highest in-use slot number if any, or zero. */ /* Return the highest in-use slot number if any, or zero. */
if (sem_list_nr > 0) if (sem_list_nr > 0)
@ -428,8 +434,8 @@ int do_semctl(message *m)
return ENOMEM; return ENOMEM;
for (i = 0; i < sem->semid_ds.sem_nsems; i++) for (i = 0; i < sem->semid_ds.sem_nsems; i++)
buf[i] = sem->sems[i].semval; buf[i] = sem->sems[i].semval;
r = sys_datacopy(SELF, (vir_bytes)buf, who_e, (vir_bytes)opt, r = sys_datacopy(SELF, (vir_bytes)buf, m->m_source,
sizeof(unsigned short) * sem->semid_ds.sem_nsems); opt, sizeof(unsigned short) * sem->semid_ds.sem_nsems);
free(buf); free(buf);
if (r != OK) if (r != OK)
return EINVAL; return EINVAL;
@ -458,33 +464,32 @@ int do_semctl(message *m)
buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems); buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
if (buf == NULL) if (buf == NULL)
return ENOMEM; return ENOMEM;
r = sys_datacopy(who_e, (vir_bytes)opt, SELF, (vir_bytes)buf, r = sys_datacopy(m->m_source, opt, SELF, (vir_bytes)buf,
sizeof(unsigned short) * sem->semid_ds.sem_nsems); sizeof(unsigned short) * sem->semid_ds.sem_nsems);
if (r != OK) { if (r != OK) {
free(buf); free(buf);
return EINVAL; return EINVAL;
} }
#ifdef DEBUG_SEM
printf("SEMCTL: SETALL: opt: %lu\n", (vir_bytes) opt);
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]);
#endif
for (i = 0; i < sem->semid_ds.sem_nsems; i++) { for (i = 0; i < sem->semid_ds.sem_nsems; i++) {
if (buf[i] > SEMVMX) { if (buf[i] > SEMVMX) {
free(buf); free(buf);
update_semaphores();
return ERANGE; return ERANGE;
} }
sem->sems[i].semval = buf[i];
} }
#ifdef DEBUG_SEM
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]);
#endif
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
sem->sems[i].semval = buf[i];
free(buf); free(buf);
/* awaken if possible */ /* Awaken any waiting parties if now possible. */
update_semaphores(); check_semaphore(sem);
break; break;
case SETVAL: case SETVAL:
val = (int)opt; val = (int)opt;
/* check write permission */ /* Check write permission. */
if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222)) if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, 0222))
return EACCES; return EACCES;
if (num < 0 || num >= sem->semid_ds.sem_nsems) if (num < 0 || num >= sem->semid_ds.sem_nsems)
return EINVAL; return EINVAL;
@ -495,8 +500,8 @@ int do_semctl(message *m)
printf("SEMCTL: SETVAL: %d %d\n", num, val); printf("SEMCTL: SETVAL: %d %d\n", num, val);
#endif #endif
sem->semid_ds.sem_ctime = clock_time(NULL); sem->semid_ds.sem_ctime = clock_time(NULL);
/* awaken if possible */ /* Awaken any waiting parties if now possible. */
update_semaphores(); check_semaphore(sem);
break; break;
default: default:
return EINVAL; return EINVAL;
@ -505,22 +510,21 @@ int do_semctl(message *m)
return OK; return OK;
} }
/*===========================================================================* int
* do_semop * do_semop(message * m)
*===========================================================================*/
int do_semop(message *m)
{ {
unsigned int i, j, mask; unsigned int i, mask;
int id, r; int id, r;
struct sembuf *sops; struct sembuf *sops;
unsigned int nsops; unsigned int nsops;
struct sem_struct *sem; struct sem_struct *sem;
int no_reply = 0; struct semaphore *s;
int op_n, val, no_reply;
id = m->m_lc_ipc_semop.id; id = m->m_lc_ipc_semop.id;
nsops = m->m_lc_ipc_semop.size; nsops = m->m_lc_ipc_semop.size;
if (!(sem = sem_find_id(id))) if ((sem = sem_find_id(id)) == NULL)
return EINVAL; return EINVAL;
if (nsops <= 0) if (nsops <= 0)
@ -528,13 +532,12 @@ int do_semop(message *m)
if (nsops > SEMOPM) if (nsops > SEMOPM)
return E2BIG; return E2BIG;
/* get the array from user application */ /* Get the array from the user process. */
sops = malloc(sizeof(struct sembuf) * nsops); sops = malloc(sizeof(sops[0]) * nsops);
if (!sops) if (!sops)
return ENOMEM; return ENOMEM;
r = sys_datacopy(who_e, (vir_bytes) m->m_lc_ipc_semop.ops, r = sys_datacopy(m->m_source, (vir_bytes)m->m_lc_ipc_semop.ops, SELF,
SELF, (vir_bytes) sops, (vir_bytes)sops, sizeof(sops[0]) * nsops);
sizeof(struct sembuf) * nsops);
if (r != OK) if (r != OK)
goto out_free; goto out_free;
@ -543,13 +546,13 @@ int do_semop(message *m)
printf("SEMOP: num:%d op:%d flg:%d\n", printf("SEMOP: num:%d op:%d flg:%d\n",
sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg); sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg);
#endif #endif
/* check for value range */ /* Check that all given semaphore numbers are within range. */
r = EFBIG; r = EFBIG;
for (i = 0; i < nsops; i++) for (i = 0; i < nsops; i++)
if (sops[i].sem_num >= sem->semid_ds.sem_nsems) if (sops[i].sem_num >= sem->semid_ds.sem_nsems)
goto out_free; goto out_free;
/* check for permissions */ /* Check for permissions. */
r = EACCES; r = EACCES;
mask = 0; mask = 0;
for (i = 0; i < nsops; i++) { for (i = 0; i < nsops; i++) {
@ -558,72 +561,57 @@ int do_semop(message *m)
else else
mask |= 0444; /* check for read permission */ mask |= 0444; /* check for read permission */
} }
if (mask && !check_perm(&sem->semid_ds.sem_perm, who_e, mask)) if (mask && !check_perm(&sem->semid_ds.sem_perm, m->m_source, mask))
goto out_free; goto out_free;
/* check for duplicate number */ /* Check for nonblocking operations. */
r = EINVAL;
for (i = 0; i < nsops; i++)
for (j = i + 1; j < nsops; j++)
if (sops[i].sem_num == sops[j].sem_num)
goto out_free;
/* check for nonblocking operations */
r = EAGAIN; r = EAGAIN;
for (i = 0; i < nsops; i++) { for (i = 0; i < nsops; i++) {
int op_n, val;
op_n = sops[i].sem_op; op_n = sops[i].sem_op;
val = sem->sems[sops[i].sem_num].semval; val = sem->sems[sops[i].sem_num].semval;
if ((sops[i].sem_flg & IPC_NOWAIT) && if ((sops[i].sem_flg & IPC_NOWAIT) &&
((!op_n && val) || ((op_n == 0 && val != 0) || (op_n < 0 && -op_n > val)))
(op_n < 0 &&
-op_n > val)))
goto out_free; goto out_free;
} }
/* there will be no errors left, so we can go ahead */ /* There will be no errors left, so we can go ahead. */
no_reply = 0;
for (i = 0; i < nsops; i++) { for (i = 0; i < nsops; i++) {
struct semaphore *s;
int op_n;
s = &sem->sems[sops[i].sem_num]; s = &sem->sems[sops[i].sem_num];
op_n = sops[i].sem_op; op_n = sops[i].sem_op;
s->sempid = getnpid(who_e); s->sempid = getnpid(m->m_source);
if (op_n > 0) { if (op_n > 0) {
/* XXX missing ERANGE check */
s->semval += sops[i].sem_op; s->semval += sops[i].sem_op;
} else if (!op_n) { } else if (op_n == 0) {
if (s->semval) { if (s->semval) {
/* put the process asleep */ /* Put the process to sleep. */
s->semzcnt++; s->semzcnt++;
s->zlist = realloc(s->zlist, s->zlist = realloc(s->zlist,
sizeof(struct waiting) * s->semzcnt); sizeof(struct waiting) * s->semzcnt);
/* continuing if NULL would lead to disaster */ /* continuing if NULL would lead to disaster */
if (s->zlist == NULL) if (s->zlist == NULL)
panic("out of memory"); panic("out of memory");
s->zlist[s->semzcnt-1].who = who_e; s->zlist[s->semzcnt - 1].who = m->m_source;
s->zlist[s->semzcnt - 1].val = op_n; s->zlist[s->semzcnt - 1].val = op_n;
#ifdef DEBUG_SEM
printf("SEMOP: Put into sleep... %d\n", who_e);
#endif
no_reply++; no_reply++;
} }
} else { } else /* (op_n < 0) */ {
if (s->semval >= -op_n) if (s->semval >= -op_n)
s->semval += op_n; s->semval += op_n;
else { else {
/* put the process asleep */ /* Put the process to sleep. */
s->semncnt++; s->semncnt++;
s->nlist = realloc(s->nlist, s->nlist = realloc(s->nlist,
sizeof(struct waiting) * s->semncnt); sizeof(struct waiting) * s->semncnt);
/* continuing if NULL would lead to disaster */ /* continuing if NULL would lead to disaster */
if (s->nlist == NULL) if (s->nlist == NULL)
panic("out of memory"); panic("out of memory");
s->nlist[s->semncnt-1].who = who_e; s->nlist[s->semncnt - 1].who = m->m_source;
s->nlist[s->semncnt - 1].val = -op_n; s->nlist[s->semncnt - 1].val = -op_n;
no_reply++; no_reply++;
@ -632,39 +620,36 @@ int do_semop(message *m)
} }
r = no_reply ? SUSPEND : OK; r = no_reply ? SUSPEND : OK;
/* Awaken any other waiting parties if now possible. */
check_semaphore(sem);
out_free: out_free:
free(sops); free(sops);
/* awaken process if possible */
update_semaphores();
return r; return r;
} }
/*===========================================================================* int
* is_sem_nil * is_sem_nil(void)
*===========================================================================*/
int is_sem_nil(void)
{ {
return (sem_list_nr == 0); return (sem_list_nr == 0);
} }
/*===========================================================================* void
* sem_process_vm_notify * sem_process_vm_notify(void)
*===========================================================================*/
void sem_process_vm_notify(void)
{ {
endpoint_t pt; endpoint_t endpt;
int r; int r;
while ((r = vm_query_exit(&pt)) >= 0) { /* For each endpoint, check whether it is waiting. */
/* for each enpoint 'pt', check whether it's waiting... */ while ((r = vm_query_exit(&endpt)) >= 0) {
remove_process(pt); remove_process(endpt);
if (r == 0) if (r == 0)
break; break;
} }
if (r < 0) if (r < 0)
printf("IPC: query exit error!\n"); printf("IPC: query exit error (%d)\n", r);
} }

View File

@ -11,22 +11,26 @@ struct shm_struct {
static struct shm_struct shm_list[SHMMNI]; static struct shm_struct shm_list[SHMMNI];
static unsigned int shm_list_nr = 0; /* highest in-use slot number plus one */ static unsigned int shm_list_nr = 0; /* highest in-use slot number plus one */
static struct shm_struct *shm_find_key(key_t key) static struct shm_struct *
shm_find_key(key_t key)
{ {
unsigned int i; unsigned int i;
if (key == IPC_PRIVATE) if (key == IPC_PRIVATE)
return NULL; return NULL;
for (i = 0; i < shm_list_nr; i++) { for (i = 0; i < shm_list_nr; i++) {
if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC)) if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
continue; continue;
if (shm_list[i].shmid_ds.shm_perm._key == key) if (shm_list[i].shmid_ds.shm_perm._key == key)
return &shm_list[i]; return &shm_list[i];
} }
return NULL; return NULL;
} }
static struct shm_struct *shm_find_id(int id) static struct shm_struct *
shm_find_id(int id)
{ {
struct shm_struct *shm; struct shm_struct *shm;
unsigned int i; unsigned int i;
@ -43,10 +47,8 @@ static struct shm_struct *shm_find_id(int id)
return shm; return shm;
} }
/*===========================================================================* int
* do_shmget * do_shmget(message * m)
*===========================================================================*/
int do_shmget(message *m)
{ {
struct shm_struct *shm; struct shm_struct *shm;
unsigned int i, seq; unsigned int i, seq;
@ -59,8 +61,8 @@ int do_shmget(message *m)
old_size = size = m->m_lc_ipc_shmget.size; old_size = size = m->m_lc_ipc_shmget.size;
flag = m->m_lc_ipc_shmget.flag; flag = m->m_lc_ipc_shmget.flag;
if ((shm = shm_find_key(key))) { if ((shm = shm_find_key(key)) != NULL) {
if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, flag))
return EACCES; return EACCES;
if ((flag & IPC_CREAT) && (flag & IPC_EXCL)) if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
return EEXIST; return EEXIST;
@ -72,9 +74,7 @@ int do_shmget(message *m)
return ENOENT; return ENOENT;
if (size <= 0) if (size <= 0)
return EINVAL; return EINVAL;
/* round up to a multiple of PAGE_SIZE */ size = roundup(size, PAGE_SIZE);
if (size % PAGE_SIZE)
size += PAGE_SIZE - size % PAGE_SIZE;
if (size <= 0) if (size <= 0)
return EINVAL; return EINVAL;
@ -98,20 +98,20 @@ int do_shmget(message *m)
/* Initialize the entry. */ /* Initialize the entry. */
shm = &shm_list[i]; shm = &shm_list[i];
seq = shm->shmid_ds.shm_perm._seq; seq = shm->shmid_ds.shm_perm._seq;
memset(shm, 0, sizeof(struct shm_struct)); memset(shm, 0, sizeof(*shm));
shm->shmid_ds.shm_perm._key = key; shm->shmid_ds.shm_perm._key = key;
shm->shmid_ds.shm_perm.cuid = shm->shmid_ds.shm_perm.cuid =
shm->shmid_ds.shm_perm.uid = getnuid(who_e); shm->shmid_ds.shm_perm.uid = getnuid(m->m_source);
shm->shmid_ds.shm_perm.cgid = shm->shmid_ds.shm_perm.cgid =
shm->shmid_ds.shm_perm.gid = getngid(who_e); shm->shmid_ds.shm_perm.gid = getngid(m->m_source);
shm->shmid_ds.shm_perm.mode = SHM_ALLOC | (flag & ACCESSPERMS); shm->shmid_ds.shm_perm.mode = SHM_ALLOC | (flag & ACCESSPERMS);
shm->shmid_ds.shm_perm._seq = (seq + 1) & 0x7fff; shm->shmid_ds.shm_perm._seq = (seq + 1) & 0x7fff;
shm->shmid_ds.shm_segsz = old_size; shm->shmid_ds.shm_segsz = old_size;
shm->shmid_ds.shm_atime = 0; shm->shmid_ds.shm_atime = 0;
shm->shmid_ds.shm_dtime = 0; shm->shmid_ds.shm_dtime = 0;
shm->shmid_ds.shm_ctime = clock_time(NULL); shm->shmid_ds.shm_ctime = clock_time(NULL);
shm->shmid_ds.shm_cpid = getnpid(who_e); shm->shmid_ds.shm_cpid = getnpid(m->m_source);
shm->shmid_ds.shm_lpid = 0; shm->shmid_ds.shm_lpid = 0;
shm->shmid_ds.shm_nattch = 0; shm->shmid_ds.shm_nattch = 0;
shm->page = (vir_bytes)page; shm->page = (vir_bytes)page;
@ -126,10 +126,8 @@ int do_shmget(message *m)
return OK; return OK;
} }
/*===========================================================================* int
* do_shmat * do_shmat(message * m)
*===========================================================================*/
int do_shmat(message *m)
{ {
int id, flag; int id, flag;
vir_bytes addr; vir_bytes addr;
@ -140,42 +138,39 @@ int do_shmat(message *m)
addr = (vir_bytes)m->m_lc_ipc_shmat.addr; addr = (vir_bytes)m->m_lc_ipc_shmat.addr;
flag = m->m_lc_ipc_shmat.flag; flag = m->m_lc_ipc_shmat.flag;
if (addr && (addr % PAGE_SIZE)) { if (addr % PAGE_SIZE) {
if (flag & SHM_RND) if (flag & SHM_RND)
addr -= (addr % PAGE_SIZE); addr -= addr % PAGE_SIZE;
else else
return EINVAL; return EINVAL;
} }
if (!(shm = shm_find_id(id))) if ((shm = shm_find_id(id)) == NULL)
return EINVAL; return EINVAL;
if (flag & SHM_RDONLY) if (flag & SHM_RDONLY)
flag = 0444; flag = 0444;
else else
flag = 0666; flag = 0666;
if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, flag))
return EACCES; return EACCES;
ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page, ret = vm_remap(m->m_source, sef_self(), (void *)addr,
shm->shmid_ds.shm_segsz); (void *)shm->page, shm->shmid_ds.shm_segsz);
if (ret == MAP_FAILED) if (ret == MAP_FAILED)
return ENOMEM; return ENOMEM;
shm->shmid_ds.shm_atime = clock_time(NULL); shm->shmid_ds.shm_atime = clock_time(NULL);
shm->shmid_ds.shm_lpid = getnpid(who_e); shm->shmid_ds.shm_lpid = getnpid(m->m_source);
/* nattach is updated lazily */ /* nattch is updated lazily */
m->m_lc_ipc_shmat.retaddr = ret; m->m_lc_ipc_shmat.retaddr = ret;
return OK; return OK;
} }
/*===========================================================================* void
* update_refcount_and_destroy * update_refcount_and_destroy(void)
*===========================================================================*/
void update_refcount_and_destroy(void)
{ {
size_t size;
u8_t rc; u8_t rc;
unsigned int i; unsigned int i;
@ -192,10 +187,9 @@ void update_refcount_and_destroy(void)
if (shm_list[i].shmid_ds.shm_nattch == 0 && if (shm_list[i].shmid_ds.shm_nattch == 0 &&
(shm_list[i].shmid_ds.shm_perm.mode & SHM_DEST)) { (shm_list[i].shmid_ds.shm_perm.mode & SHM_DEST)) {
size = shm_list[i].shmid_ds.shm_segsz; munmap((void *)shm_list[i].page,
if (size % PAGE_SIZE) roundup(shm_list[i].shmid_ds.shm_segsz,
size += PAGE_SIZE - size % PAGE_SIZE; PAGE_SIZE));
munmap((void *)shm_list[i].page, size);
/* Mark the entry as free. */ /* Mark the entry as free. */
shm_list[i].shmid_ds.shm_perm.mode &= ~SHM_ALLOC; shm_list[i].shmid_ds.shm_perm.mode &= ~SHM_ALLOC;
} }
@ -210,10 +204,8 @@ void update_refcount_and_destroy(void)
shm_list_nr--; shm_list_nr--;
} }
/*===========================================================================* int
* do_shmdt * do_shmdt(message * m)
*===========================================================================*/
int do_shmdt(message *m)
{ {
struct shm_struct *shm; struct shm_struct *shm;
vir_bytes addr; vir_bytes addr;
@ -222,7 +214,7 @@ int do_shmdt(message *m)
addr = (vir_bytes)m->m_lc_ipc_shmdt.addr; addr = (vir_bytes)m->m_lc_ipc_shmdt.addr;
if ((vm_id = vm_getphys(who_e, (void *) addr)) == 0) if ((vm_id = vm_getphys(m->m_source, (void *)addr)) == 0)
return EINVAL; return EINVAL;
for (i = 0; i < shm_list_nr; i++) { for (i = 0; i < shm_list_nr; i++) {
@ -233,39 +225,36 @@ int do_shmdt(message *m)
if (shm->vm_id == vm_id) { if (shm->vm_id == vm_id) {
shm->shmid_ds.shm_atime = clock_time(NULL); shm->shmid_ds.shm_atime = clock_time(NULL);
shm->shmid_ds.shm_lpid = getnpid(who_e); shm->shmid_ds.shm_lpid = getnpid(m->m_source);
/* nattch is updated lazily */ /* nattch is updated lazily */
vm_unmap(who_e, (void *) addr); vm_unmap(m->m_source, (void *)addr);
break; break;
} }
} }
if (i == shm_list_nr) if (i == shm_list_nr)
printf("IPC: do_shmdt impossible error! could not find id %lu to unmap\n", printf("IPC: do_shmdt: ID %lu not found\n", vm_id);
vm_id);
update_refcount_and_destroy(); update_refcount_and_destroy();
return OK; return OK;
} }
/*===========================================================================* int
* do_shmctl * do_shmctl(message * m)
*===========================================================================*/
int do_shmctl(message *m)
{ {
struct shmid_ds *ds;
struct shmid_ds tmp_ds; struct shmid_ds tmp_ds;
struct shm_struct *shm; struct shm_struct *shm;
struct shminfo sinfo; struct shminfo sinfo;
struct shm_info s_info; struct shm_info s_info;
vir_bytes buf;
unsigned int i; unsigned int i;
uid_t uid; uid_t uid;
int r, id, cmd; int r, id, cmd;
id = m->m_lc_ipc_shmctl.id; id = m->m_lc_ipc_shmctl.id;
cmd = m->m_lc_ipc_shmctl.cmd; cmd = m->m_lc_ipc_shmctl.cmd;
ds = (struct shmid_ds *)m->m_lc_ipc_shmctl.buf; buf = (vir_bytes)m->m_lc_ipc_shmctl.buf;
/* /*
* For stat calls, sure that all information is up-to-date. Since this * For stat calls, sure that all information is up-to-date. Since this
@ -287,7 +276,7 @@ int do_shmctl(message *m)
return EINVAL; return EINVAL;
break; break;
default: default:
if (!(shm = shm_find_id(id))) if ((shm = shm_find_id(id)) == NULL)
return EINVAL; return EINVAL;
break; break;
} }
@ -296,23 +285,22 @@ int do_shmctl(message *m)
case IPC_STAT: case IPC_STAT:
case SHM_STAT: case SHM_STAT:
/* Check whether the caller has read permission. */ /* Check whether the caller has read permission. */
if (!check_perm(&shm->shmid_ds.shm_perm, who_e, 0444)) if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, 0444))
return EACCES; return EACCES;
if ((r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds, who_e, if ((r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds,
(vir_bytes)ds, sizeof(struct shmid_ds))) != OK) m->m_source, buf, sizeof(shm->shmid_ds))) != OK)
return r; return r;
if (cmd == SHM_STAT) if (cmd == SHM_STAT)
m->m_lc_ipc_shmctl.ret = m->m_lc_ipc_shmctl.ret =
IXSEQ_TO_IPCID(id, shm->shmid_ds.shm_perm); IXSEQ_TO_IPCID(id, shm->shmid_ds.shm_perm);
break; break;
case IPC_SET: case IPC_SET:
uid = getnuid(who_e); uid = getnuid(m->m_source);
if (uid != shm->shmid_ds.shm_perm.cuid && if (uid != shm->shmid_ds.shm_perm.cuid &&
uid != shm->shmid_ds.shm_perm.uid && uid != shm->shmid_ds.shm_perm.uid && uid != 0)
uid != 0)
return EPERM; return EPERM;
if ((r = sys_datacopy(who_e, (vir_bytes)ds, SELF, if ((r = sys_datacopy(m->m_source, buf, SELF,
(vir_bytes)&tmp_ds, sizeof(struct shmid_ds))) != OK) (vir_bytes)&tmp_ds, sizeof(tmp_ds))) != OK)
return r; return r;
shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid; shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid;
shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid; shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid;
@ -322,13 +310,12 @@ int do_shmctl(message *m)
shm->shmid_ds.shm_ctime = clock_time(NULL); shm->shmid_ds.shm_ctime = clock_time(NULL);
break; break;
case IPC_RMID: case IPC_RMID:
uid = getnuid(who_e); uid = getnuid(m->m_source);
if (uid != shm->shmid_ds.shm_perm.cuid && if (uid != shm->shmid_ds.shm_perm.cuid &&
uid != shm->shmid_ds.shm_perm.uid && uid != shm->shmid_ds.shm_perm.uid && uid != 0)
uid != 0)
return EPERM; return EPERM;
shm->shmid_ds.shm_perm.mode |= SHM_DEST; shm->shmid_ds.shm_perm.mode |= SHM_DEST;
/* destroy if possible */ /* Destroy if possible. */
update_refcount_and_destroy(); update_refcount_and_destroy();
break; break;
case IPC_INFO: case IPC_INFO:
@ -338,8 +325,8 @@ int do_shmctl(message *m)
sinfo.shmmni = __arraycount(shm_list); sinfo.shmmni = __arraycount(shm_list);
sinfo.shmseg = (unsigned long) -1; sinfo.shmseg = (unsigned long) -1;
sinfo.shmall = (unsigned long) -1; sinfo.shmall = (unsigned long) -1;
if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, who_e, if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, m->m_source,
(vir_bytes)ds, sizeof(sinfo))) != OK) buf, sizeof(sinfo))) != OK)
return r; return r;
if (shm_list_nr > 0) if (shm_list_nr > 0)
m->m_lc_ipc_shmctl.ret = shm_list_nr - 1; m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
@ -357,8 +344,8 @@ int do_shmctl(message *m)
s_info.shm_swp = 0; s_info.shm_swp = 0;
s_info.swap_attempts = 0; s_info.swap_attempts = 0;
s_info.swap_successes = 0; s_info.swap_successes = 0;
if ((r = sys_datacopy(SELF, (vir_bytes)&s_info, who_e, if ((r = sys_datacopy(SELF, (vir_bytes)&s_info, m->m_source,
(vir_bytes)ds, sizeof(s_info))) != OK) buf, sizeof(s_info))) != OK)
return r; return r;
if (shm_list_nr > 0) if (shm_list_nr > 0)
m->m_lc_ipc_shmctl.ret = shm_list_nr - 1; m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
@ -372,9 +359,11 @@ int do_shmctl(message *m)
} }
#if 0 #if 0
static void list_shm_ds(void) static void
list_shm_ds(void)
{ {
unsigned int i; unsigned int i;
printf("key\tid\tpage\n"); printf("key\tid\tpage\n");
for (i = 0; i < shm_list_nr; i++) { for (i = 0; i < shm_list_nr; i++) {
if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC)) if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
@ -387,10 +376,9 @@ static void list_shm_ds(void)
} }
#endif #endif
/*===========================================================================* int
* is_shm_nil * is_shm_nil(void)
*===========================================================================*/
int is_shm_nil(void)
{ {
return (shm_list_nr == 0); return (shm_list_nr == 0);
} }

View File

@ -1,35 +1,34 @@
#include "inc.h" #include "inc.h"
int check_perm(struct ipc_perm *req, endpoint_t who, int mode) int
check_perm(struct ipc_perm * req, endpoint_t who, int mode)
{ {
int req_mode; int req_mode;
int cur_mode; int cur_mode;
uid_t uid = getnuid(who); uid_t uid;
gid_t gid = getngid(who); gid_t gid;
uid = getnuid(who);
gid = getngid(who);
mode &= 0666; mode &= 0666;
/* is root? */ /* Root is allowed to do anything. */
if (uid == 0) if (uid == 0)
return 1; return 1;
if (uid == req->uid || uid == req->cuid) { if (uid == req->uid || uid == req->cuid) {
/* same user */ /* Same user. */
req_mode = (req->mode >> 6) & 0x7; req_mode = (req->mode >> 6) & 0x7;
cur_mode = (mode >> 6) & 0x7; cur_mode = (mode >> 6) & 0x7;
} else if (gid == req->gid || gid == req->cgid) { } else if (gid == req->gid || gid == req->cgid) {
/* same group */ /* Same group. */
req_mode = (req->mode >> 3) & 0x7; req_mode = (req->mode >> 3) & 0x7;
cur_mode = (mode >> 3) & 0x7; cur_mode = (mode >> 3) & 0x7;
} else { } else {
/* other group */ /* Other user and group. */
req_mode = req->mode & 0x7; req_mode = req->mode & 0x7;
cur_mode = mode & 0x7; cur_mode = mode & 0x7;
} }
if (cur_mode && ((cur_mode & req_mode) == cur_mode)) return (cur_mode && ((cur_mode & req_mode) == cur_mode));
return 1;
else
return 0;
} }