1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
21 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * The split of ipcs.c into ipcs.c and ipc.c to accommodate the
30 * changes in ipcrm.c was done by Edwin Groothuis <edwin@FreeBSD.org>
31 */
32
33#include <sys/types.h>
34#include <sys/sysctl.h>
35#define	_WANT_SYSVMSG_INTERNALS
36#include <sys/msg.h>
37#define	_WANT_SYSVSEM_INTERNALS
38#include <sys/sem.h>
39#define	_WANT_SYSVSHM_INTERNALS
40#include <sys/shm.h>
41
42#include <assert.h>
43#include <err.h>
44#include <kvm.h>
45#include <nlist.h>
46#include <stddef.h>
47
48#include "ipc.h"
49
50int	use_sysctl = 1;
51struct semid_kernel	*sema;
52struct seminfo		seminfo;
53struct msginfo		msginfo;
54struct msqid_kernel	*msqids;
55struct shminfo		shminfo;
56struct shmid_kernel	*shmsegs;
57
58struct nlist symbols[] = {
59	{ .n_name = "sema" },
60	{ .n_name = "seminfo" },
61	{ .n_name = "msginfo" },
62	{ .n_name = "msqids" },
63	{ .n_name = "shminfo" },
64	{ .n_name = "shmsegs" },
65	{ .n_name = NULL }
66};
67
68#define	SHMINFO_XVEC	X(shmmax, sizeof(u_long))			\
69			X(shmmin, sizeof(u_long))			\
70			X(shmmni, sizeof(u_long))			\
71			X(shmseg, sizeof(u_long))			\
72			X(shmall, sizeof(u_long))
73
74#define	SEMINFO_XVEC	X(semmni, sizeof(int))				\
75			X(semmns, sizeof(int))				\
76			X(semmnu, sizeof(int))				\
77			X(semmsl, sizeof(int))				\
78			X(semopm, sizeof(int))				\
79			X(semume, sizeof(int))				\
80			X(semusz, sizeof(int))				\
81			X(semvmx, sizeof(int))				\
82			X(semaem, sizeof(int))
83
84#define	MSGINFO_XVEC	X(msgmax, sizeof(int))				\
85			X(msgmni, sizeof(int))				\
86			X(msgmnb, sizeof(int))				\
87			X(msgtql, sizeof(int))				\
88			X(msgssz, sizeof(int))				\
89			X(msgseg, sizeof(int))
90
91#define	X(a, b)	{ "kern.ipc." #a, offsetof(TYPEC, a), (b) },
92#define	TYPEC	struct shminfo
93static struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { .sysctl=NULL } };
94#undef	TYPEC
95#define	TYPEC	struct seminfo
96static struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { .sysctl=NULL } };
97#undef	TYPEC
98#define	TYPEC	struct msginfo
99static struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { .sysctl=NULL } };
100#undef	TYPEC
101#undef	X
102
103kvm_t *kd;
104
105void
106sysctlgatherstruct(void *addr, size_t size, struct scgs_vector *vecarr)
107{
108	struct scgs_vector *xp;
109	size_t tsiz;
110	int rv;
111
112	for (xp = vecarr; xp->sysctl != NULL; xp++) {
113		assert(xp->offset <= size);
114		tsiz = xp->size;
115		rv = sysctlbyname(xp->sysctl, (char *)addr + xp->offset,
116		    &tsiz, NULL, 0);
117		if (rv == -1)
118			err(1, "sysctlbyname: %s", xp->sysctl);
119		if (tsiz != xp->size)
120			errx(1, "%s size mismatch (expected %zu, got %zu)",
121			    xp->sysctl, xp->size, tsiz);
122	}
123}
124
125void
126kget(int idx, void *addr, size_t size)
127{
128	const char *symn;		/* symbol name */
129	size_t tsiz;
130	int rv;
131	unsigned long kaddr;
132	const char *sym2sysctl[] = {	/* symbol to sysctl name table */
133		"kern.ipc.sema",
134		"kern.ipc.seminfo",
135		"kern.ipc.msginfo",
136		"kern.ipc.msqids",
137		"kern.ipc.shminfo",
138		"kern.ipc.shmsegs" };
139
140	assert((unsigned)idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl));
141	if (!use_sysctl) {
142		symn = symbols[idx].n_name;
143		if (*symn == '_')
144			symn++;
145		if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0)
146			errx(1, "symbol %s undefined", symn);
147		/*
148		 * For some symbols, the value we retrieve is
149		 * actually a pointer; since we want the actual value,
150		 * we have to manually dereference it.
151		 */
152		switch (idx) {
153		case X_MSQIDS:
154			tsiz = sizeof(msqids);
155			rv = kvm_read(kd, symbols[idx].n_value,
156			    &msqids, tsiz);
157			kaddr = (u_long)msqids;
158			break;
159		case X_SHMSEGS:
160			tsiz = sizeof(shmsegs);
161			rv = kvm_read(kd, symbols[idx].n_value,
162			    &shmsegs, tsiz);
163			kaddr = (u_long)shmsegs;
164			break;
165		case X_SEMA:
166			tsiz = sizeof(sema);
167			rv = kvm_read(kd, symbols[idx].n_value,
168			    &sema, tsiz);
169			kaddr = (u_long)sema;
170			break;
171		default:
172			rv = tsiz = 0;
173			kaddr = symbols[idx].n_value;
174			break;
175		}
176		if ((unsigned)rv != tsiz)
177			errx(1, "%s: %s", symn, kvm_geterr(kd));
178		if ((unsigned)kvm_read(kd, kaddr, addr, size) != size)
179			errx(1, "%s: %s", symn, kvm_geterr(kd));
180	} else {
181		switch (idx) {
182		case X_SHMINFO:
183			sysctlgatherstruct(addr, size, shminfo_scgsv);
184			break;
185		case X_SEMINFO:
186			sysctlgatherstruct(addr, size, seminfo_scgsv);
187			break;
188		case X_MSGINFO:
189			sysctlgatherstruct(addr, size, msginfo_scgsv);
190			break;
191		default:
192			tsiz = size;
193			rv = sysctlbyname(sym2sysctl[idx], addr, &tsiz,
194			    NULL, 0);
195			if (rv == -1)
196				err(1, "sysctlbyname: %s", sym2sysctl[idx]);
197			if (tsiz != size)
198				errx(1, "%s size mismatch "
199				    "(expected %zu, got %zu)",
200				    sym2sysctl[idx], size, tsiz);
201			break;
202		}
203	}
204}
205