summaryrefslogtreecommitdiff
path: root/do/ipcctl
blob: fb3e2430c6fdad800e8468eae8be32c4e33f65ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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;
}