Print this page
OS-1571 Placate gcc -Wparentheses
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/lxproc/lxpr_vnops.c
+++ new/usr/src/uts/common/fs/lxproc/lxpr_vnops.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
28 28 */
29 29
30 30 /*
31 31 * lxproc -- a loosely Linux-compatible /proc
32 32 *
33 33 * The aspiration here is to provide something that sufficiently approximates
34 34 * the Linux /proc implementation for purposes of offering some compatibility
35 35 * for simple Linux /proc readers (e.g., ps/top/htop). However, it is not
36 36 * intended to exactly mimic Linux semantics; when choosing between offering
37 37 * compatibility and telling the truth, we emphatically pick the truth. A
38 38 * particular glaring example of this is the Linux notion of "tasks" (that is,
39 39 * threads), which -- due to historical misadventures on Linux -- allocate their
40 40 * identifiers from the process identifier space. (That is, each thread has in
41 41 * effect a pid.) Some Linux /proc readers have come to depend on this
42 42 * attribute, and become confused when threads appear with proper identifiers,
43 43 * so we simply opt for the pre-2.6 behavior, and do not present the tasks
44 44 * directory at all. Similarly, when choosing between offering compatibility
45 45 * and remaining consistent with our broader security model, we (obviously)
46 46 * choose security over compatibility. In short, this is meant to be a best
47 47 * effort -- no more.
48 48 */
49 49
50 50 #include <sys/cpupart.h>
51 51 #include <sys/cpuvar.h>
52 52 #include <sys/session.h>
53 53 #include <sys/vmparam.h>
54 54 #include <sys/mman.h>
55 55 #include <vm/rm.h>
56 56 #include <vm/seg_vn.h>
57 57 #include <sys/sdt.h>
58 58 #include <sys/strlog.h>
59 59 #include <sys/stropts.h>
60 60 #include <sys/cmn_err.h>
61 61 #include <sys/x86_archext.h>
62 62 #include <sys/archsystm.h>
63 63 #include <sys/fp.h>
64 64 #include <sys/pool_pset.h>
65 65 #include <sys/pset.h>
66 66 #include <sys/zone.h>
67 67 #include <sys/pghw.h>
68 68 #include <sys/vfs_opreg.h>
69 69
70 70 /* Dependent on procfs */
71 71 extern kthread_t *prchoose(proc_t *);
72 72
73 73 #include "lxproc.h"
74 74
75 75 extern pgcnt_t swapfs_minfree;
76 76 extern time_t boot_time;
77 77
78 78 /*
79 79 * Pointer to the vnode ops vector for this fs.
80 80 * This is instantiated in lxprinit() in lxpr_vfsops.c
81 81 */
82 82 vnodeops_t *lxpr_vnodeops;
83 83
84 84 static int lxpr_open(vnode_t **, int, cred_t *, caller_context_t *);
85 85 static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *,
86 86 caller_context_t *);
87 87 static int lxpr_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
88 88 static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *,
89 89 caller_context_t *);
90 90 static int lxpr_access(vnode_t *, int, int, cred_t *, caller_context_t *);
91 91 static int lxpr_lookup(vnode_t *, char *, vnode_t **,
92 92 pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
93 93 pathname_t *);
94 94 static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *,
95 95 caller_context_t *, int);
96 96 static int lxpr_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
97 97 static int lxpr_cmp(vnode_t *, vnode_t *, caller_context_t *);
98 98 static int lxpr_realvp(vnode_t *, vnode_t **, caller_context_t *);
99 99 static int lxpr_sync(void);
100 100 static void lxpr_inactive(vnode_t *, cred_t *, caller_context_t *);
101 101
102 102 static vnode_t *lxpr_lookup_procdir(vnode_t *, char *);
103 103 static vnode_t *lxpr_lookup_piddir(vnode_t *, char *);
104 104 static vnode_t *lxpr_lookup_not_a_dir(vnode_t *, char *);
105 105 static vnode_t *lxpr_lookup_fddir(vnode_t *, char *);
106 106 static vnode_t *lxpr_lookup_netdir(vnode_t *, char *);
107 107
108 108 static int lxpr_readdir_procdir(lxpr_node_t *, uio_t *, int *);
109 109 static int lxpr_readdir_piddir(lxpr_node_t *, uio_t *, int *);
110 110 static int lxpr_readdir_not_a_dir(lxpr_node_t *, uio_t *, int *);
111 111 static int lxpr_readdir_fddir(lxpr_node_t *, uio_t *, int *);
112 112 static int lxpr_readdir_netdir(lxpr_node_t *, uio_t *, int *);
113 113
114 114 static void lxpr_read_invalid(lxpr_node_t *, lxpr_uiobuf_t *);
115 115 static void lxpr_read_empty(lxpr_node_t *, lxpr_uiobuf_t *);
116 116 static void lxpr_read_cpuinfo(lxpr_node_t *, lxpr_uiobuf_t *);
117 117 static void lxpr_read_isdir(lxpr_node_t *, lxpr_uiobuf_t *);
118 118 static void lxpr_read_fd(lxpr_node_t *, lxpr_uiobuf_t *);
119 119 static void lxpr_read_kmsg(lxpr_node_t *, lxpr_uiobuf_t *);
120 120 static void lxpr_read_loadavg(lxpr_node_t *, lxpr_uiobuf_t *);
121 121 static void lxpr_read_meminfo(lxpr_node_t *, lxpr_uiobuf_t *);
122 122 static void lxpr_read_mounts(lxpr_node_t *, lxpr_uiobuf_t *);
123 123 static void lxpr_read_partitions(lxpr_node_t *, lxpr_uiobuf_t *);
124 124 static void lxpr_read_stat(lxpr_node_t *, lxpr_uiobuf_t *);
125 125 static void lxpr_read_uptime(lxpr_node_t *, lxpr_uiobuf_t *);
126 126 static void lxpr_read_version(lxpr_node_t *, lxpr_uiobuf_t *);
127 127
128 128 static void lxpr_read_pid_cmdline(lxpr_node_t *, lxpr_uiobuf_t *);
129 129 static void lxpr_read_pid_maps(lxpr_node_t *, lxpr_uiobuf_t *);
130 130 static void lxpr_read_pid_stat(lxpr_node_t *, lxpr_uiobuf_t *);
131 131 static void lxpr_read_pid_statm(lxpr_node_t *, lxpr_uiobuf_t *);
132 132 static void lxpr_read_pid_status(lxpr_node_t *, lxpr_uiobuf_t *);
133 133
134 134 static void lxpr_read_net_arp(lxpr_node_t *, lxpr_uiobuf_t *);
135 135 static void lxpr_read_net_dev(lxpr_node_t *, lxpr_uiobuf_t *);
136 136 static void lxpr_read_net_dev_mcast(lxpr_node_t *, lxpr_uiobuf_t *);
137 137 static void lxpr_read_net_igmp(lxpr_node_t *, lxpr_uiobuf_t *);
138 138 static void lxpr_read_net_ip_mr_cache(lxpr_node_t *, lxpr_uiobuf_t *);
139 139 static void lxpr_read_net_ip_mr_vif(lxpr_node_t *, lxpr_uiobuf_t *);
140 140 static void lxpr_read_net_mcfilter(lxpr_node_t *, lxpr_uiobuf_t *);
141 141 static void lxpr_read_net_netstat(lxpr_node_t *, lxpr_uiobuf_t *);
142 142 static void lxpr_read_net_raw(lxpr_node_t *, lxpr_uiobuf_t *);
143 143 static void lxpr_read_net_route(lxpr_node_t *, lxpr_uiobuf_t *);
144 144 static void lxpr_read_net_rpc(lxpr_node_t *, lxpr_uiobuf_t *);
145 145 static void lxpr_read_net_rt_cache(lxpr_node_t *, lxpr_uiobuf_t *);
146 146 static void lxpr_read_net_sockstat(lxpr_node_t *, lxpr_uiobuf_t *);
147 147 static void lxpr_read_net_snmp(lxpr_node_t *, lxpr_uiobuf_t *);
148 148 static void lxpr_read_net_stat(lxpr_node_t *, lxpr_uiobuf_t *);
149 149 static void lxpr_read_net_tcp(lxpr_node_t *, lxpr_uiobuf_t *);
150 150 static void lxpr_read_net_udp(lxpr_node_t *, lxpr_uiobuf_t *);
151 151 static void lxpr_read_net_unix(lxpr_node_t *, lxpr_uiobuf_t *);
152 152
153 153 /*
154 154 * Simple conversion
155 155 */
156 156 #define btok(x) ((x) >> 10) /* bytes to kbytes */
157 157 #define ptok(x) ((x) << (PAGESHIFT - 10)) /* pages to kbytes */
158 158
159 159 /*
160 160 * The lxproc vnode operations vector
161 161 */
162 162 const fs_operation_def_t lxpr_vnodeops_template[] = {
163 163 VOPNAME_OPEN, { .vop_open = lxpr_open },
164 164 VOPNAME_CLOSE, { .vop_close = lxpr_close },
165 165 VOPNAME_READ, { .vop_read = lxpr_read },
166 166 VOPNAME_GETATTR, { .vop_getattr = lxpr_getattr },
167 167 VOPNAME_ACCESS, { .vop_access = lxpr_access },
168 168 VOPNAME_LOOKUP, { .vop_lookup = lxpr_lookup },
169 169 VOPNAME_READDIR, { .vop_readdir = lxpr_readdir },
170 170 VOPNAME_READLINK, { .vop_readlink = lxpr_readlink },
171 171 VOPNAME_FSYNC, { .error = lxpr_sync },
172 172 VOPNAME_SEEK, { .error = lxpr_sync },
173 173 VOPNAME_INACTIVE, { .vop_inactive = lxpr_inactive },
174 174 VOPNAME_CMP, { .vop_cmp = lxpr_cmp },
175 175 VOPNAME_REALVP, { .vop_realvp = lxpr_realvp },
176 176 NULL, NULL
177 177 };
178 178
179 179 /*
180 180 * file contents of an lxproc directory.
181 181 */
182 182 static lxpr_dirent_t lxpr_dir[] = {
183 183 { LXPR_CMDLINE, "cmdline" },
184 184 { LXPR_CPUINFO, "cpuinfo" },
185 185 { LXPR_DEVICES, "devices" },
186 186 { LXPR_DMA, "dma" },
187 187 { LXPR_FILESYSTEMS, "filesystems" },
188 188 { LXPR_INTERRUPTS, "interrupts" },
189 189 { LXPR_IOPORTS, "ioports" },
190 190 { LXPR_KCORE, "kcore" },
191 191 { LXPR_KMSG, "kmsg" },
192 192 { LXPR_LOADAVG, "loadavg" },
193 193 { LXPR_MEMINFO, "meminfo" },
194 194 { LXPR_MOUNTS, "mounts" },
195 195 { LXPR_NETDIR, "net" },
196 196 { LXPR_PARTITIONS, "partitions" },
197 197 { LXPR_SELF, "self" },
198 198 { LXPR_STAT, "stat" },
199 199 { LXPR_UPTIME, "uptime" },
200 200 { LXPR_VERSION, "version" }
201 201 };
202 202
203 203 #define PROCDIRFILES (sizeof (lxpr_dir) / sizeof (lxpr_dir[0]))
204 204
205 205 /*
206 206 * Contents of an /lxproc/<pid> directory.
207 207 */
208 208 static lxpr_dirent_t piddir[] = {
209 209 { LXPR_PID_CMDLINE, "cmdline" },
210 210 { LXPR_PID_CPU, "cpu" },
211 211 { LXPR_PID_CURDIR, "cwd" },
212 212 { LXPR_PID_ENV, "environ" },
213 213 { LXPR_PID_EXE, "exe" },
214 214 { LXPR_PID_MAPS, "maps" },
215 215 { LXPR_PID_MEM, "mem" },
216 216 { LXPR_PID_ROOTDIR, "root" },
217 217 { LXPR_PID_STAT, "stat" },
218 218 { LXPR_PID_STATM, "statm" },
219 219 { LXPR_PID_STATUS, "status" },
220 220 { LXPR_PID_FDDIR, "fd" }
221 221 };
222 222
223 223 #define PIDDIRFILES (sizeof (piddir) / sizeof (piddir[0]))
224 224
225 225 /*
226 226 * contents of /lxproc/net directory
227 227 */
228 228 static lxpr_dirent_t netdir[] = {
229 229 { LXPR_NET_ARP, "arp" },
230 230 { LXPR_NET_DEV, "dev" },
231 231 { LXPR_NET_DEV_MCAST, "dev_mcast" },
232 232 { LXPR_NET_IGMP, "igmp" },
233 233 { LXPR_NET_IP_MR_CACHE, "ip_mr_cache" },
234 234 { LXPR_NET_IP_MR_VIF, "ip_mr_vif" },
235 235 { LXPR_NET_MCFILTER, "mcfilter" },
236 236 { LXPR_NET_NETSTAT, "netstat" },
237 237 { LXPR_NET_RAW, "raw" },
238 238 { LXPR_NET_ROUTE, "route" },
239 239 { LXPR_NET_RPC, "rpc" },
240 240 { LXPR_NET_RT_CACHE, "rt_cache" },
241 241 { LXPR_NET_SOCKSTAT, "sockstat" },
242 242 { LXPR_NET_SNMP, "snmp" },
243 243 { LXPR_NET_STAT, "stat" },
244 244 { LXPR_NET_TCP, "tcp" },
245 245 { LXPR_NET_UDP, "udp" },
246 246 { LXPR_NET_UNIX, "unix" }
247 247 };
248 248
249 249 #define NETDIRFILES (sizeof (netdir) / sizeof (netdir[0]))
250 250
251 251 /*
252 252 * These are the major signal number differences between Linux and native:
253 253 *
254 254 * ====================================
255 255 * | Number | Linux | Native |
256 256 * | ====== | ========= | ========== |
257 257 * | 7 | SIGBUS | SIGEMT |
258 258 * | 10 | SIGUSR1 | SIGBUS |
259 259 * | 12 | SIGUSR2 | SIGSYS |
260 260 * | 16 | SIGSTKFLT | SIGUSR1 |
261 261 * | 17 | SIGCHLD | SIGUSR2 |
262 262 * | 18 | SIGCONT | SIGCHLD |
263 263 * | 19 | SIGSTOP | SIGPWR |
264 264 * | 20 | SIGTSTP | SIGWINCH |
265 265 * | 21 | SIGTTIN | SIGURG |
266 266 * | 22 | SIGTTOU | SIGPOLL |
267 267 * | 23 | SIGURG | SIGSTOP |
268 268 * | 24 | SIGXCPU | SIGTSTP |
269 269 * | 25 | SIGXFSZ | SIGCONT |
270 270 * | 26 | SIGVTALARM | SIGTTIN |
271 271 * | 27 | SIGPROF | SIGTTOU |
272 272 * | 28 | SIGWINCH | SIGVTALARM |
273 273 * | 29 | SIGPOLL | SIGPROF |
274 274 * | 30 | SIGPWR | SIGXCPU |
275 275 * | 31 | SIGSYS | SIGXFSZ |
276 276 * ====================================
277 277 *
278 278 * Not every Linux signal maps to a native signal, nor does every native
279 279 * signal map to a Linux counterpart. However, when signals do map, the
280 280 * mapping is unique.
281 281 */
282 282 static int
283 283 lxpr_sigmap[NSIG] = {
284 284 0,
285 285 LX_SIGHUP,
286 286 LX_SIGINT,
287 287 LX_SIGQUIT,
288 288 LX_SIGILL,
289 289 LX_SIGTRAP,
290 290 LX_SIGABRT,
291 291 LX_SIGSTKFLT,
292 292 LX_SIGFPE,
293 293 LX_SIGKILL,
294 294 LX_SIGBUS,
295 295 LX_SIGSEGV,
296 296 LX_SIGSYS,
297 297 LX_SIGPIPE,
298 298 LX_SIGALRM,
299 299 LX_SIGTERM,
300 300 LX_SIGUSR1,
301 301 LX_SIGUSR2,
302 302 LX_SIGCHLD,
303 303 LX_SIGPWR,
304 304 LX_SIGWINCH,
305 305 LX_SIGURG,
306 306 LX_SIGPOLL,
307 307 LX_SIGSTOP,
308 308 LX_SIGTSTP,
309 309 LX_SIGCONT,
310 310 LX_SIGTTIN,
311 311 LX_SIGTTOU,
312 312 LX_SIGVTALRM,
313 313 LX_SIGPROF,
314 314 LX_SIGXCPU,
315 315 LX_SIGXFSZ,
316 316 -1, /* 32: illumos SIGWAITING */
317 317 -1, /* 33: illumos SIGLWP */
318 318 -1, /* 34: illumos SIGFREEZE */
319 319 -1, /* 35: illumos SIGTHAW */
320 320 -1, /* 36: illumos SIGCANCEL */
321 321 -1, /* 37: illumos SIGLOST */
322 322 -1, /* 38: illumos SIGXRES */
323 323 -1, /* 39: illumos SIGJVM1 */
324 324 -1, /* 40: illumos SIGJVM2 */
325 325 LX_SIGRTMIN, /* 41: illumos _SIGRTMIN */
326 326 LX_SIGRTMIN + 1,
327 327 LX_SIGRTMIN + 2,
328 328 LX_SIGRTMIN + 3,
329 329 LX_SIGRTMIN + 4,
330 330 LX_SIGRTMIN + 5,
331 331 LX_SIGRTMIN + 6,
332 332 LX_SIGRTMIN + 7,
333 333 LX_SIGRTMIN + 8,
334 334 LX_SIGRTMIN + 9,
335 335 LX_SIGRTMIN + 10,
336 336 LX_SIGRTMIN + 11,
337 337 LX_SIGRTMIN + 12,
338 338 LX_SIGRTMIN + 13,
339 339 LX_SIGRTMIN + 14,
340 340 LX_SIGRTMIN + 15,
341 341 LX_SIGRTMIN + 16,
342 342 LX_SIGRTMIN + 17,
343 343 LX_SIGRTMIN + 18,
344 344 LX_SIGRTMIN + 19,
345 345 LX_SIGRTMIN + 20,
346 346 LX_SIGRTMIN + 21,
347 347 LX_SIGRTMIN + 22,
348 348 LX_SIGRTMIN + 23,
349 349 LX_SIGRTMIN + 24,
350 350 LX_SIGRTMIN + 25,
351 351 LX_SIGRTMIN + 26,
352 352 LX_SIGRTMIN + 27,
353 353 LX_SIGRTMIN + 28,
354 354 LX_SIGRTMIN + 29,
355 355 LX_SIGRTMIN + 30,
356 356 LX_SIGRTMAX,
357 357 };
358 358
359 359 /*
360 360 * lxpr_open(): Vnode operation for VOP_OPEN()
361 361 */
362 362 static int
363 363 lxpr_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
364 364 {
365 365 vnode_t *vp = *vpp;
366 366 lxpr_node_t *lxpnp = VTOLXP(vp);
367 367 lxpr_nodetype_t type = lxpnp->lxpr_type;
368 368 vnode_t *rvp;
369 369 int error = 0;
370 370
371 371 /*
372 372 * We only allow reading in this file systrem
373 373 */
374 374 if (flag & FWRITE)
375 375 return (EROFS);
376 376
377 377 /*
378 378 * If we are opening an underlying file only allow regular files
379 379 * reject the open for anything but a regular file.
380 380 * Just do it if we are opening the current or root directory.
381 381 */
382 382 if (lxpnp->lxpr_realvp != NULL) {
383 383 rvp = lxpnp->lxpr_realvp;
384 384
385 385 if (type == LXPR_PID_FD_FD && rvp->v_type != VREG)
386 386 error = EACCES;
387 387 else {
388 388 /*
389 389 * Need to hold rvp since VOP_OPEN() may release it.
390 390 */
391 391 VN_HOLD(rvp);
392 392 error = VOP_OPEN(&rvp, flag, cr, ct);
393 393 if (error) {
394 394 VN_RELE(rvp);
395 395 } else {
396 396 *vpp = rvp;
397 397 VN_RELE(vp);
398 398 }
399 399 }
400 400 }
401 401
402 402 if (type == LXPR_KMSG) {
403 403 ldi_ident_t li = VTOLXPM(vp)->lxprm_li;
404 404 struct strioctl str;
405 405 int rv;
406 406
407 407 /*
408 408 * Open the zone's console device using the layered driver
409 409 * interface.
410 410 */
411 411 if ((error = ldi_open_by_name("/dev/log", FREAD, cr,
412 412 &lxpnp->lxpr_cons_ldih, li)) != 0)
413 413 return (error);
414 414
415 415 /*
416 416 * Send an ioctl to the underlying console device, letting it
417 417 * know we're interested in getting console messages.
418 418 */
419 419 str.ic_cmd = I_CONSLOG;
420 420 str.ic_timout = 0;
421 421 str.ic_len = 0;
422 422 str.ic_dp = NULL;
423 423 if ((error = ldi_ioctl(lxpnp->lxpr_cons_ldih, I_STR,
424 424 (intptr_t)&str, FKIOCTL, cr, &rv)) != 0)
425 425 return (error);
426 426 }
427 427
428 428 return (error);
429 429 }
430 430
431 431
432 432 /*
433 433 * lxpr_close(): Vnode operation for VOP_CLOSE()
434 434 */
435 435 /* ARGSUSED */
436 436 static int
437 437 lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
438 438 caller_context_t *ct)
439 439 {
440 440 lxpr_node_t *lxpr = VTOLXP(vp);
441 441 lxpr_nodetype_t type = lxpr->lxpr_type;
442 442 int err;
443 443
444 444 /*
445 445 * we should never get here because the close is done on the realvp
446 446 * for these nodes
447 447 */
448 448 ASSERT(type != LXPR_PID_FD_FD &&
449 449 type != LXPR_PID_CURDIR &&
450 450 type != LXPR_PID_ROOTDIR &&
451 451 type != LXPR_PID_EXE);
452 452
453 453 if (type == LXPR_KMSG) {
454 454 if ((err = ldi_close(lxpr->lxpr_cons_ldih, 0, cr)) != 0)
455 455 return (err);
456 456 }
457 457
458 458 return (0);
459 459 }
460 460
461 461 static void (*lxpr_read_function[LXPR_NFILES])() = {
462 462 lxpr_read_isdir, /* /proc */
463 463 lxpr_read_isdir, /* /proc/<pid> */
464 464 lxpr_read_pid_cmdline, /* /proc/<pid>/cmdline */
465 465 lxpr_read_empty, /* /proc/<pid>/cpu */
466 466 lxpr_read_invalid, /* /proc/<pid>/cwd */
467 467 lxpr_read_empty, /* /proc/<pid>/environ */
468 468 lxpr_read_invalid, /* /proc/<pid>/exe */
469 469 lxpr_read_pid_maps, /* /proc/<pid>/maps */
470 470 lxpr_read_empty, /* /proc/<pid>/mem */
471 471 lxpr_read_invalid, /* /proc/<pid>/root */
472 472 lxpr_read_pid_stat, /* /proc/<pid>/stat */
473 473 lxpr_read_pid_statm, /* /proc/<pid>/statm */
474 474 lxpr_read_pid_status, /* /proc/<pid>/status */
475 475 lxpr_read_isdir, /* /proc/<pid>/fd */
476 476 lxpr_read_fd, /* /proc/<pid>/fd/nn */
477 477 lxpr_read_empty, /* /proc/cmdline */
478 478 lxpr_read_cpuinfo, /* /proc/cpuinfo */
479 479 lxpr_read_empty, /* /proc/devices */
480 480 lxpr_read_empty, /* /proc/dma */
481 481 lxpr_read_empty, /* /proc/filesystems */
482 482 lxpr_read_empty, /* /proc/interrupts */
483 483 lxpr_read_empty, /* /proc/ioports */
484 484 lxpr_read_empty, /* /proc/kcore */
485 485 lxpr_read_kmsg, /* /proc/kmsg */
486 486 lxpr_read_loadavg, /* /proc/loadavg */
487 487 lxpr_read_meminfo, /* /proc/meminfo */
488 488 lxpr_read_mounts, /* /proc/mounts */
489 489 lxpr_read_isdir, /* /proc/net */
490 490 lxpr_read_net_arp, /* /proc/net/arp */
491 491 lxpr_read_net_dev, /* /proc/net/dev */
492 492 lxpr_read_net_dev_mcast, /* /proc/net/dev_mcast */
493 493 lxpr_read_net_igmp, /* /proc/net/igmp */
494 494 lxpr_read_net_ip_mr_cache, /* /proc/net/ip_mr_cache */
495 495 lxpr_read_net_ip_mr_vif, /* /proc/net/ip_mr_vif */
496 496 lxpr_read_net_mcfilter, /* /proc/net/mcfilter */
497 497 lxpr_read_net_netstat, /* /proc/net/netstat */
498 498 lxpr_read_net_raw, /* /proc/net/raw */
499 499 lxpr_read_net_route, /* /proc/net/route */
500 500 lxpr_read_net_rpc, /* /proc/net/rpc */
501 501 lxpr_read_net_rt_cache, /* /proc/net/rt_cache */
502 502 lxpr_read_net_sockstat, /* /proc/net/sockstat */
503 503 lxpr_read_net_snmp, /* /proc/net/snmp */
504 504 lxpr_read_net_stat, /* /proc/net/stat */
505 505 lxpr_read_net_tcp, /* /proc/net/tcp */
506 506 lxpr_read_net_udp, /* /proc/net/udp */
507 507 lxpr_read_net_unix, /* /proc/net/unix */
508 508 lxpr_read_partitions, /* /proc/partitions */
509 509 lxpr_read_invalid, /* /proc/self */
510 510 lxpr_read_stat, /* /proc/stat */
511 511 lxpr_read_uptime, /* /proc/uptime */
512 512 lxpr_read_version, /* /proc/version */
513 513 };
514 514
515 515 /*
516 516 * Array of lookup functions, indexed by /lxproc file type.
517 517 */
518 518 static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
519 519 lxpr_lookup_procdir, /* /proc */
520 520 lxpr_lookup_piddir, /* /proc/<pid> */
521 521 lxpr_lookup_not_a_dir, /* /proc/<pid>/cmdline */
522 522 lxpr_lookup_not_a_dir, /* /proc/<pid>/cpu */
523 523 lxpr_lookup_not_a_dir, /* /proc/<pid>/cwd */
524 524 lxpr_lookup_not_a_dir, /* /proc/<pid>/environ */
525 525 lxpr_lookup_not_a_dir, /* /proc/<pid>/exe */
526 526 lxpr_lookup_not_a_dir, /* /proc/<pid>/maps */
527 527 lxpr_lookup_not_a_dir, /* /proc/<pid>/mem */
528 528 lxpr_lookup_not_a_dir, /* /proc/<pid>/root */
529 529 lxpr_lookup_not_a_dir, /* /proc/<pid>/stat */
530 530 lxpr_lookup_not_a_dir, /* /proc/<pid>/statm */
531 531 lxpr_lookup_not_a_dir, /* /proc/<pid>/status */
532 532 lxpr_lookup_fddir, /* /proc/<pid>/fd */
533 533 lxpr_lookup_not_a_dir, /* /proc/<pid>/fd/nn */
534 534 lxpr_lookup_not_a_dir, /* /proc/cmdline */
535 535 lxpr_lookup_not_a_dir, /* /proc/cpuinfo */
536 536 lxpr_lookup_not_a_dir, /* /proc/devices */
537 537 lxpr_lookup_not_a_dir, /* /proc/dma */
538 538 lxpr_lookup_not_a_dir, /* /proc/filesystems */
539 539 lxpr_lookup_not_a_dir, /* /proc/interrupts */
540 540 lxpr_lookup_not_a_dir, /* /proc/ioports */
541 541 lxpr_lookup_not_a_dir, /* /proc/kcore */
542 542 lxpr_lookup_not_a_dir, /* /proc/kmsg */
543 543 lxpr_lookup_not_a_dir, /* /proc/loadavg */
544 544 lxpr_lookup_not_a_dir, /* /proc/meminfo */
545 545 lxpr_lookup_not_a_dir, /* /proc/mounts */
546 546 lxpr_lookup_netdir, /* /proc/net */
547 547 lxpr_lookup_not_a_dir, /* /proc/net/arp */
548 548 lxpr_lookup_not_a_dir, /* /proc/net/dev */
549 549 lxpr_lookup_not_a_dir, /* /proc/net/dev_mcast */
550 550 lxpr_lookup_not_a_dir, /* /proc/net/igmp */
551 551 lxpr_lookup_not_a_dir, /* /proc/net/ip_mr_cache */
552 552 lxpr_lookup_not_a_dir, /* /proc/net/ip_mr_vif */
553 553 lxpr_lookup_not_a_dir, /* /proc/net/mcfilter */
554 554 lxpr_lookup_not_a_dir, /* /proc/net/netstat */
555 555 lxpr_lookup_not_a_dir, /* /proc/net/raw */
556 556 lxpr_lookup_not_a_dir, /* /proc/net/route */
557 557 lxpr_lookup_not_a_dir, /* /proc/net/rpc */
558 558 lxpr_lookup_not_a_dir, /* /proc/net/rt_cache */
559 559 lxpr_lookup_not_a_dir, /* /proc/net/sockstat */
560 560 lxpr_lookup_not_a_dir, /* /proc/net/snmp */
561 561 lxpr_lookup_not_a_dir, /* /proc/net/stat */
562 562 lxpr_lookup_not_a_dir, /* /proc/net/tcp */
563 563 lxpr_lookup_not_a_dir, /* /proc/net/udp */
564 564 lxpr_lookup_not_a_dir, /* /proc/net/unix */
565 565 lxpr_lookup_not_a_dir, /* /proc/partitions */
566 566 lxpr_lookup_not_a_dir, /* /proc/self */
567 567 lxpr_lookup_not_a_dir, /* /proc/stat */
568 568 lxpr_lookup_not_a_dir, /* /proc/uptime */
569 569 lxpr_lookup_not_a_dir, /* /proc/version */
570 570 };
571 571
572 572 /*
573 573 * Array of readdir functions, indexed by /proc file type.
574 574 */
575 575 static int (*lxpr_readdir_function[LXPR_NFILES])() = {
576 576 lxpr_readdir_procdir, /* /proc */
577 577 lxpr_readdir_piddir, /* /proc/<pid> */
578 578 lxpr_readdir_not_a_dir, /* /proc/<pid>/cmdline */
579 579 lxpr_readdir_not_a_dir, /* /proc/<pid>/cpu */
580 580 lxpr_readdir_not_a_dir, /* /proc/<pid>/cwd */
581 581 lxpr_readdir_not_a_dir, /* /proc/<pid>/environ */
582 582 lxpr_readdir_not_a_dir, /* /proc/<pid>/exe */
583 583 lxpr_readdir_not_a_dir, /* /proc/<pid>/maps */
584 584 lxpr_readdir_not_a_dir, /* /proc/<pid>/mem */
585 585 lxpr_readdir_not_a_dir, /* /proc/<pid>/root */
586 586 lxpr_readdir_not_a_dir, /* /proc/<pid>/stat */
587 587 lxpr_readdir_not_a_dir, /* /proc/<pid>/statm */
588 588 lxpr_readdir_not_a_dir, /* /proc/<pid>/status */
589 589 lxpr_readdir_fddir, /* /proc/<pid>/fd */
590 590 lxpr_readdir_not_a_dir, /* /proc/<pid>/fd/nn */
591 591 lxpr_readdir_not_a_dir, /* /proc/cmdline */
592 592 lxpr_readdir_not_a_dir, /* /proc/cpuinfo */
593 593 lxpr_readdir_not_a_dir, /* /proc/devices */
594 594 lxpr_readdir_not_a_dir, /* /proc/dma */
595 595 lxpr_readdir_not_a_dir, /* /proc/filesystems */
596 596 lxpr_readdir_not_a_dir, /* /proc/interrupts */
597 597 lxpr_readdir_not_a_dir, /* /proc/ioports */
598 598 lxpr_readdir_not_a_dir, /* /proc/kcore */
599 599 lxpr_readdir_not_a_dir, /* /proc/kmsg */
600 600 lxpr_readdir_not_a_dir, /* /proc/loadavg */
601 601 lxpr_readdir_not_a_dir, /* /proc/meminfo */
602 602 lxpr_readdir_not_a_dir, /* /proc/mounts */
603 603 lxpr_readdir_netdir, /* /proc/net */
604 604 lxpr_readdir_not_a_dir, /* /proc/net/arp */
605 605 lxpr_readdir_not_a_dir, /* /proc/net/dev */
606 606 lxpr_readdir_not_a_dir, /* /proc/net/dev_mcast */
607 607 lxpr_readdir_not_a_dir, /* /proc/net/igmp */
608 608 lxpr_readdir_not_a_dir, /* /proc/net/ip_mr_cache */
609 609 lxpr_readdir_not_a_dir, /* /proc/net/ip_mr_vif */
610 610 lxpr_readdir_not_a_dir, /* /proc/net/mcfilter */
611 611 lxpr_readdir_not_a_dir, /* /proc/net/netstat */
612 612 lxpr_readdir_not_a_dir, /* /proc/net/raw */
613 613 lxpr_readdir_not_a_dir, /* /proc/net/route */
614 614 lxpr_readdir_not_a_dir, /* /proc/net/rpc */
615 615 lxpr_readdir_not_a_dir, /* /proc/net/rt_cache */
616 616 lxpr_readdir_not_a_dir, /* /proc/net/sockstat */
617 617 lxpr_readdir_not_a_dir, /* /proc/net/snmp */
618 618 lxpr_readdir_not_a_dir, /* /proc/net/stat */
619 619 lxpr_readdir_not_a_dir, /* /proc/net/tcp */
620 620 lxpr_readdir_not_a_dir, /* /proc/net/udp */
621 621 lxpr_readdir_not_a_dir, /* /proc/net/unix */
622 622 lxpr_readdir_not_a_dir, /* /proc/partitions */
623 623 lxpr_readdir_not_a_dir, /* /proc/self */
624 624 lxpr_readdir_not_a_dir, /* /proc/stat */
625 625 lxpr_readdir_not_a_dir, /* /proc/uptime */
626 626 lxpr_readdir_not_a_dir, /* /proc/version */
627 627 };
628 628
629 629
630 630 /*
631 631 * lxpr_read(): Vnode operation for VOP_READ()
632 632 *
633 633 * As the format of all the files that can be read in lxproc is human readable
634 634 * and not binary structures there do not have to be different read variants
635 635 * depending on whether the reading process model is 32- or 64-bit.
636 636 */
637 637 /* ARGSUSED */
638 638 static int
639 639 lxpr_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
640 640 caller_context_t *ct)
641 641 {
642 642 lxpr_node_t *lxpnp = VTOLXP(vp);
643 643 lxpr_nodetype_t type = lxpnp->lxpr_type;
644 644 lxpr_uiobuf_t *uiobuf = lxpr_uiobuf_new(uiop);
645 645 int error;
646 646
647 647 ASSERT(type >= 0 && type < LXPR_NFILES);
648 648
649 649 lxpr_read_function[type](lxpnp, uiobuf);
650 650
651 651 error = lxpr_uiobuf_flush(uiobuf);
652 652 lxpr_uiobuf_free(uiobuf);
653 653
654 654 return (error);
655 655 }
656 656
657 657 /*
658 658 * lxpr_read_invalid(), lxpr_read_isdir(), lxpr_read_empty()
659 659 *
660 660 * Various special case reads:
661 661 * - trying to read a directory
662 662 * - invalid file (used to mean a file that should be implemented,
663 663 * but isn't yet)
664 664 * - empty file
665 665 * - wait to be able to read a file that will never have anything to read
666 666 */
667 667 /* ARGSUSED */
668 668 static void
669 669 lxpr_read_isdir(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
670 670 {
671 671 lxpr_uiobuf_seterr(uiobuf, EISDIR);
672 672 }
673 673
674 674 /* ARGSUSED */
675 675 static void
676 676 lxpr_read_invalid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
677 677 {
678 678 lxpr_uiobuf_seterr(uiobuf, EINVAL);
679 679 }
680 680
681 681 /* ARGSUSED */
682 682 static void
683 683 lxpr_read_empty(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
684 684 {
685 685 }
686 686
687 687 /*
688 688 * lxpr_read_pid_cmdline():
689 689 *
690 690 * This is not precisely compatible with Linux: the Linux cmdline returns argv
691 691 * with the correct separation using \0 between the arguments, but we cannot do
692 692 * that without copying the real argv from the correct process context. This
693 693 * is too difficult to attempt so we pretend that the entire cmdline is just
694 694 * argv[0]. This is good enough for ps and htop to display correctly, but might
695 695 * cause some other things not to work correctly.
696 696 */
697 697 static void
698 698 lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
699 699 {
700 700 proc_t *p;
701 701 char *buf;
702 702
703 703 ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE);
704 704
705 705 p = lxpr_lock(lxpnp->lxpr_pid);
706 706 if (p == NULL) {
707 707 lxpr_uiobuf_seterr(uiobuf, EINVAL);
708 708 return;
709 709 }
710 710
711 711 buf = PTOU(p)->u_argv != 0 ? PTOU(p)->u_psargs : PTOU(p)->u_comm;
712 712
713 713 lxpr_uiobuf_write(uiobuf, buf, strlen(buf) + 1);
714 714 lxpr_unlock(p);
715 715 }
716 716
717 717 /*
718 718 * lxpr_read_pid_maps(): memory map file
719 719 */
720 720 static void
721 721 lxpr_read_pid_maps(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
722 722 {
723 723 proc_t *p;
724 724 struct as *as;
725 725 struct seg *seg;
726 726 char *buf;
727 727 int buflen = MAXPATHLEN;
728 728 struct print_data {
729 729 caddr_t saddr;
730 730 caddr_t eaddr;
731 731 int type;
732 732 char prot[5];
733 733 uint32_t offset;
734 734 vnode_t *vp;
735 735 struct print_data *next;
736 736 } *print_head = NULL;
737 737 struct print_data **print_tail = &print_head;
738 738 struct print_data *pbuf;
739 739
740 740 ASSERT(lxpnp->lxpr_type == LXPR_PID_MAPS);
741 741
742 742 p = lxpr_lock(lxpnp->lxpr_pid);
743 743 if (p == NULL) {
744 744 lxpr_uiobuf_seterr(uiobuf, EINVAL);
745 745 return;
746 746 }
747 747
748 748 as = p->p_as;
749 749
750 750 if (as == &kas) {
751 751 lxpr_unlock(p);
752 752 return;
753 753 }
754 754
755 755 mutex_exit(&p->p_lock);
756 756
757 757 /* Iterate over all segments in the address space */
758 758 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
759 759 for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
760 760 vnode_t *vp;
761 761 uint_t protbits;
762 762
763 763 pbuf = kmem_alloc(sizeof (*pbuf), KM_SLEEP);
764 764
765 765 pbuf->saddr = seg->s_base;
766 766 pbuf->eaddr = seg->s_base+seg->s_size;
767 767 pbuf->type = SEGOP_GETTYPE(seg, seg->s_base);
768 768
769 769 /*
770 770 * Cheat and only use the protection bits of the first page
771 771 * in the segment
772 772 */
773 773 (void) strncpy(pbuf->prot, "----", sizeof (pbuf->prot));
774 774 (void) SEGOP_GETPROT(seg, seg->s_base, 0, &protbits);
775 775
776 776 if (protbits & PROT_READ) pbuf->prot[0] = 'r';
777 777 if (protbits & PROT_WRITE) pbuf->prot[1] = 'w';
778 778 if (protbits & PROT_EXEC) pbuf->prot[2] = 'x';
779 779 if (pbuf->type & MAP_SHARED) pbuf->prot[3] = 's';
780 780 else if (pbuf->type & MAP_PRIVATE) pbuf->prot[3] = 'p';
781 781
782 782 if (seg->s_ops == &segvn_ops &&
783 783 SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
784 784 vp != NULL && vp->v_type == VREG) {
785 785 VN_HOLD(vp);
786 786 pbuf->vp = vp;
787 787 } else {
788 788 pbuf->vp = NULL;
789 789 }
790 790
791 791 pbuf->offset = (uint32_t)SEGOP_GETOFFSET(seg, pbuf->saddr);
792 792
793 793 pbuf->next = NULL;
794 794 *print_tail = pbuf;
795 795 print_tail = &pbuf->next;
796 796 }
797 797 AS_LOCK_EXIT(as, &as->a_lock);
798 798 mutex_enter(&p->p_lock);
799 799 lxpr_unlock(p);
800 800
801 801 buf = kmem_alloc(buflen, KM_SLEEP);
802 802
803 803 /* print the data we've extracted */
804 804 pbuf = print_head;
805 805 while (pbuf != NULL) {
806 806 struct print_data *pbuf_next;
807 807 vattr_t vattr;
808 808
809 809 int maj = 0;
810 810 int min = 0;
811 811 u_longlong_t inode = 0;
812 812
813 813 *buf = '\0';
814 814 if (pbuf->vp != NULL) {
815 815 vattr.va_mask = AT_FSID | AT_NODEID;
816 816 if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED(),
817 817 NULL) == 0) {
818 818 maj = getmajor(vattr.va_fsid);
819 819 min = getminor(vattr.va_fsid);
820 820 inode = vattr.va_nodeid;
821 821 }
822 822 (void) vnodetopath(NULL, pbuf->vp, buf, buflen, CRED());
823 823 VN_RELE(pbuf->vp);
824 824 }
825 825
826 826 if (*buf != '\0') {
827 827 lxpr_uiobuf_printf(uiobuf,
828 828 "%08x-%08x %s %08x %02d:%03d %lld %s\n",
829 829 pbuf->saddr, pbuf->eaddr, pbuf->prot, pbuf->offset,
830 830 maj, min, inode, buf);
831 831 } else {
832 832 lxpr_uiobuf_printf(uiobuf,
833 833 "%08x-%08x %s %08x %02d:%03d %lld\n",
834 834 pbuf->saddr, pbuf->eaddr, pbuf->prot, pbuf->offset,
835 835 maj, min, inode);
836 836 }
837 837
838 838 pbuf_next = pbuf->next;
839 839 kmem_free(pbuf, sizeof (*pbuf));
840 840 pbuf = pbuf_next;
841 841 }
842 842
843 843 kmem_free(buf, buflen);
844 844 }
845 845
846 846 /*
847 847 * lxpr_read_pid_statm(): memory status file
848 848 */
849 849 static void
850 850 lxpr_read_pid_statm(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
851 851 {
852 852 proc_t *p;
853 853 struct as *as;
854 854 size_t vsize;
855 855 size_t rss;
856 856
857 857 ASSERT(lxpnp->lxpr_type == LXPR_PID_STATM);
858 858
859 859 p = lxpr_lock(lxpnp->lxpr_pid);
860 860 if (p == NULL) {
861 861 lxpr_uiobuf_seterr(uiobuf, EINVAL);
862 862 return;
863 863 }
864 864
865 865 as = p->p_as;
866 866
867 867 mutex_exit(&p->p_lock);
868 868
869 869 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
870 870 vsize = btopr(as->a_resvsize);
871 871 rss = rm_asrss(as);
872 872 AS_LOCK_EXIT(as, &as->a_lock);
873 873
874 874 mutex_enter(&p->p_lock);
875 875 lxpr_unlock(p);
876 876
877 877 lxpr_uiobuf_printf(uiobuf,
878 878 "%lu %lu %lu %lu %lu %lu %lu\n",
879 879 vsize, rss, 0l, rss, 0l, 0l, 0l);
880 880 }
881 881
882 882 /*
883 883 * lxpr_read_pid_status(): status file
884 884 */
885 885 static void
886 886 lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
887 887 {
888 888 proc_t *p;
889 889 kthread_t *t;
890 890 user_t *up;
891 891 cred_t *cr;
892 892 const gid_t *groups;
893 893 int ngroups;
894 894 struct as *as;
895 895 char *status;
896 896 pid_t pid, ppid;
897 897 size_t vsize;
898 898 size_t rss;
899 899 k_sigset_t current, ignore, handle;
900 900 int i, lx_sig;
901 901
902 902 ASSERT(lxpnp->lxpr_type == LXPR_PID_STATUS);
903 903
904 904 p = lxpr_lock(lxpnp->lxpr_pid);
905 905 if (p == NULL) {
906 906 lxpr_uiobuf_seterr(uiobuf, EINVAL);
907 907 return;
908 908 }
909 909
910 910 pid = p->p_pid;
911 911
912 912 /*
913 913 * Convert pid to the Linux default of 1 if we're the zone's init
914 914 * process
915 915 */
916 916 if (pid == curproc->p_zone->zone_proc_initpid) {
917 917 pid = 1;
918 918 ppid = 0; /* parent pid for init is 0 */
919 919 } else {
920 920 /*
921 921 * Make sure not to reference parent PIDs that reside outside
922 922 * the zone
923 923 */
924 924 ppid = ((p->p_flag & SZONETOP)
925 925 ? curproc->p_zone->zone_zsched->p_pid : p->p_ppid);
926 926
927 927 /*
928 928 * Convert ppid to the Linux default of 1 if our parent is the
929 929 * zone's init process
930 930 */
931 931 if (ppid == curproc->p_zone->zone_proc_initpid)
932 932 ppid = 1;
933 933 }
934 934
935 935 t = prchoose(p);
936 936 if (t != NULL) {
937 937 switch (t->t_state) {
938 938 case TS_SLEEP:
939 939 status = "S (sleeping)";
940 940 break;
941 941 case TS_RUN:
942 942 case TS_ONPROC:
943 943 status = "R (running)";
944 944 break;
945 945 case TS_ZOMB:
946 946 status = "Z (zombie)";
947 947 break;
948 948 case TS_STOPPED:
949 949 status = "T (stopped)";
950 950 break;
951 951 default:
952 952 status = "! (unknown)";
953 953 break;
954 954 }
955 955 thread_unlock(t);
956 956 } else {
957 957 /*
958 958 * there is a hole in the exit code, where a proc can have
959 959 * no threads but it is yet to be flagged SZOMB. We will
960 960 * assume we are about to become a zombie
961 961 */
962 962 status = "Z (zombie)";
963 963 }
964 964
965 965 up = PTOU(p);
966 966 mutex_enter(&p->p_crlock);
967 967 crhold(cr = p->p_cred);
968 968 mutex_exit(&p->p_crlock);
969 969
970 970 lxpr_uiobuf_printf(uiobuf,
971 971 "Name:\t%s\n"
972 972 "State:\t%s\n"
973 973 "Tgid:\t%d\n"
974 974 "Pid:\t%d\n"
975 975 "PPid:\t%d\n"
976 976 "TracerPid:\t%d\n"
977 977 "Uid:\t%u\t%u\t%u\t%u\n"
978 978 "Gid:\t%u\t%u\t%u\t%u\n"
979 979 "FDSize:\t%d\n"
980 980 "Groups:\t",
981 981 up->u_comm,
982 982 status,
983 983 pid, /* thread group id - same as pid */
984 984 pid,
985 985 ppid,
986 986 0,
987 987 crgetruid(cr), crgetuid(cr), crgetsuid(cr), crgetuid(cr),
988 988 crgetrgid(cr), crgetgid(cr), crgetsgid(cr), crgetgid(cr),
989 989 p->p_fno_ctl);
990 990
991 991 ngroups = crgetngroups(cr);
992 992 groups = crgetgroups(cr);
993 993 for (i = 0; i < ngroups; i++) {
994 994 lxpr_uiobuf_printf(uiobuf,
995 995 "%u ",
996 996 groups[i]);
997 997 }
998 998 crfree(cr);
999 999
1000 1000 as = p->p_as;
1001 1001 if ((p->p_stat != SZOMB) && !(p->p_flag & SSYS) && (as != &kas)) {
1002 1002 mutex_exit(&p->p_lock);
1003 1003 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1004 1004 vsize = as->a_resvsize;
1005 1005 rss = rm_asrss(as);
1006 1006 AS_LOCK_EXIT(as, &as->a_lock);
1007 1007 mutex_enter(&p->p_lock);
1008 1008
1009 1009 lxpr_uiobuf_printf(uiobuf,
1010 1010 "\n"
1011 1011 "VmSize:\t%8lu kB\n"
1012 1012 "VmLck:\t%8lu kB\n"
1013 1013 "VmRSS:\t%8lu kB\n"
1014 1014 "VmData:\t%8lu kB\n"
1015 1015 "VmStk:\t%8lu kB\n"
1016 1016 "VmExe:\t%8lu kB\n"
1017 1017 "VmLib:\t%8lu kB",
1018 1018 btok(vsize),
1019 1019 0l,
1020 1020 ptok(rss),
1021 1021 0l,
1022 1022 btok(p->p_stksize),
1023 1023 ptok(rss),
1024 1024 0l);
1025 1025 }
1026 1026
1027 1027 sigemptyset(¤t);
1028 1028 sigemptyset(&ignore);
1029 1029 sigemptyset(&handle);
1030 1030
1031 1031 for (i = 1; i < NSIG; i++) {
1032 1032 lx_sig = lxpr_sigmap[i];
1033 1033
1034 1034 if ((lx_sig > 0) && (lx_sig < LX_NSIG)) {
1035 1035 if (sigismember(&p->p_sig, i))
1036 1036 sigaddset(¤t, lx_sig);
1037 1037
1038 1038 if (up->u_signal[i - 1] == SIG_IGN)
1039 1039 sigaddset(&ignore, lx_sig);
1040 1040 else if (up->u_signal[i - 1] != SIG_DFL)
1041 1041 sigaddset(&handle, lx_sig);
1042 1042 }
1043 1043 }
1044 1044
1045 1045 lxpr_uiobuf_printf(uiobuf,
1046 1046 "\n"
1047 1047 "SigPnd:\t%08x%08x\n"
1048 1048 "SigBlk:\t%08x%08x\n"
1049 1049 "SigIgn:\t%08x%08x\n"
1050 1050 "SigCgt:\t%08x%08x\n"
1051 1051 "CapInh:\t%016x\n"
1052 1052 "CapPrm:\t%016x\n"
1053 1053 "CapEff:\t%016x\n",
1054 1054 current.__sigbits[1], current.__sigbits[0],
1055 1055 0, 0, /* signals blocked on per thread basis */
1056 1056 ignore.__sigbits[1], ignore.__sigbits[0],
1057 1057 handle.__sigbits[1], handle.__sigbits[0],
1058 1058 /* Can't do anything with linux capabilities */
1059 1059 0,
1060 1060 0,
1061 1061 0);
1062 1062
1063 1063 lxpr_unlock(p);
1064 1064 }
1065 1065
1066 1066
1067 1067 /*
1068 1068 * lxpr_read_pid_stat(): pid stat file
1069 1069 */
1070 1070 static void
1071 1071 lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1072 1072 {
1073 1073 proc_t *p;
1074 1074 kthread_t *t;
1075 1075 struct as *as;
1076 1076 char stat;
1077 1077 pid_t pid, ppid, pgpid, spid;
1078 1078 gid_t psgid;
1079 1079 dev_t psdev;
1080 1080 size_t rss, vsize;
1081 1081 int nice, pri;
1082 1082 caddr_t wchan;
1083 1083 processorid_t cpu;
1084 1084
1085 1085 ASSERT(lxpnp->lxpr_type == LXPR_PID_STAT);
1086 1086
1087 1087 p = lxpr_lock(lxpnp->lxpr_pid);
1088 1088 if (p == NULL) {
1089 1089 lxpr_uiobuf_seterr(uiobuf, EINVAL);
1090 1090 return;
1091 1091 }
1092 1092
1093 1093 pid = p->p_pid;
1094 1094
1095 1095 /*
1096 1096 * Set Linux defaults if we're the zone's init process
1097 1097 */
1098 1098 if (pid == curproc->p_zone->zone_proc_initpid) {
1099 1099 pid = 1; /* PID for init */
1100 1100 ppid = 0; /* parent PID for init is 0 */
1101 1101 pgpid = 0; /* process group for init is 0 */
1102 1102 psgid = (gid_t)-1; /* credential GID for init is -1 */
1103 1103 spid = 0; /* session id for init is 0 */
1104 1104 psdev = 0; /* session device for init is 0 */
1105 1105 } else {
1106 1106 /*
1107 1107 * Make sure not to reference parent PIDs that reside outside
1108 1108 * the zone
1109 1109 */
1110 1110 ppid = ((p->p_flag & SZONETOP) ?
1111 1111 curproc->p_zone->zone_zsched->p_pid : p->p_ppid);
1112 1112
1113 1113 /*
1114 1114 * Convert ppid to the Linux default of 1 if our parent is the
1115 1115 * zone's init process
1116 1116 */
1117 1117 if (ppid == curproc->p_zone->zone_proc_initpid)
1118 1118 ppid = 1;
1119 1119
1120 1120 pgpid = p->p_pgrp;
1121 1121
1122 1122 mutex_enter(&p->p_splock);
1123 1123 mutex_enter(&p->p_sessp->s_lock);
1124 1124 spid = p->p_sessp->s_sid;
1125 1125 psdev = p->p_sessp->s_dev;
1126 1126 if (p->p_sessp->s_cred)
1127 1127 psgid = crgetgid(p->p_sessp->s_cred);
1128 1128 else
1129 1129 psgid = crgetgid(p->p_cred);
1130 1130
1131 1131 mutex_exit(&p->p_sessp->s_lock);
1132 1132 mutex_exit(&p->p_splock);
1133 1133 }
1134 1134
1135 1135 t = prchoose(p);
1136 1136 if (t != NULL) {
1137 1137 switch (t->t_state) {
1138 1138 case TS_SLEEP:
1139 1139 stat = 'S'; break;
1140 1140 case TS_RUN:
1141 1141 case TS_ONPROC:
1142 1142 stat = 'R'; break;
1143 1143 case TS_ZOMB:
1144 1144 stat = 'Z'; break;
1145 1145 case TS_STOPPED:
1146 1146 stat = 'T'; break;
1147 1147 default:
1148 1148 stat = '!'; break;
1149 1149 }
1150 1150
1151 1151 if (CL_DONICE(t, NULL, 0, &nice) != 0)
1152 1152 nice = 0;
1153 1153
1154 1154 pri = t->t_pri;
1155 1155 wchan = t->t_wchan;
1156 1156 cpu = t->t_cpu->cpu_id;
1157 1157 thread_unlock(t);
1158 1158 } else {
1159 1159 /* Only zombies have no threads */
1160 1160 stat = 'Z';
1161 1161 nice = 0;
1162 1162 pri = 0;
1163 1163 wchan = 0;
1164 1164 cpu = 0;
1165 1165 }
1166 1166 as = p->p_as;
1167 1167 mutex_exit(&p->p_lock);
1168 1168 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1169 1169 vsize = as->a_resvsize;
1170 1170 rss = rm_asrss(as);
1171 1171 AS_LOCK_EXIT(as, &as->a_lock);
1172 1172 mutex_enter(&p->p_lock);
1173 1173
1174 1174 lxpr_uiobuf_printf(uiobuf,
1175 1175 "%d (%s) %c %d %d %d %d %d "
1176 1176 "%lu %lu %lu %lu %lu "
1177 1177 "%lu %lu %ld %ld "
1178 1178 "%d %d %d "
1179 1179 "%lu "
1180 1180 "%lu "
1181 1181 "%lu %ld %llu "
1182 1182 "%lu %lu %u "
1183 1183 "%lu %lu "
1184 1184 "%lu %lu %lu %lu "
1185 1185 "%lu "
1186 1186 "%lu %lu "
1187 1187 "%d "
1188 1188 "%d"
1189 1189 "\n",
1190 1190 pid, PTOU(p)->u_comm, stat, ppid, pgpid, spid, psdev, psgid,
1191 1191 0l, 0l, 0l, 0l, 0l, /* flags, minflt, cminflt, majflt, cmajflt */
1192 1192 p->p_utime, p->p_stime, p->p_cutime, p->p_cstime,
1193 1193 pri, nice, p->p_lwpcnt,
1194 1194 0l, /* itrealvalue (time before next SIGALRM) */
1195 1195 PTOU(p)->u_ticks,
1196 1196 vsize, rss, p->p_vmem_ctl,
1197 1197 0l, 0l, USRSTACK, /* startcode, endcode, startstack */
1198 1198 0l, 0l, /* kstkesp, kstkeip */
1199 1199 0l, 0l, 0l, 0l, /* signal, blocked, sigignore, sigcatch */
1200 1200 wchan,
1201 1201 0l, 0l, /* nswap, cnswap */
1202 1202 0, /* exit_signal */
1203 1203 cpu);
1204 1204
1205 1205 lxpr_unlock(p);
1206 1206 }
1207 1207
1208 1208 /* ARGSUSED */
1209 1209 static void
1210 1210 lxpr_read_net_arp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1211 1211 {
1212 1212 }
1213 1213
1214 1214 /* ARGSUSED */
1215 1215 static void
1216 1216 lxpr_read_net_dev(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1217 1217 {
1218 1218 lxpr_uiobuf_printf(uiobuf, "Inter-| Receive "
1219 1219 " | Transmit\n");
1220 1220 lxpr_uiobuf_printf(uiobuf, " face |bytes packets errs drop fifo"
1221 1221 " frame compressed multicast|bytes packets errs drop fifo"
1222 1222 " colls carrier compressed\n");
1223 1223
1224 1224 /*
1225 1225 * Data about each interface should go here, but that shouldn't be added
1226 1226 * unless there is an lxproc reader that actually makes use of it (and
1227 1227 * doesn't need anything else that we refuse to provide)...
1228 1228 */
1229 1229 }
1230 1230
1231 1231 /* ARGSUSED */
1232 1232 static void
1233 1233 lxpr_read_net_dev_mcast(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1234 1234 {
1235 1235 }
1236 1236
1237 1237 /* ARGSUSED */
1238 1238 static void
1239 1239 lxpr_read_net_igmp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1240 1240 {
1241 1241 }
1242 1242
1243 1243 /* ARGSUSED */
1244 1244 static void
1245 1245 lxpr_read_net_ip_mr_cache(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1246 1246 {
1247 1247 }
1248 1248
1249 1249 /* ARGSUSED */
1250 1250 static void
1251 1251 lxpr_read_net_ip_mr_vif(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1252 1252 {
1253 1253 }
1254 1254
1255 1255 /* ARGSUSED */
1256 1256 static void
1257 1257 lxpr_read_net_mcfilter(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1258 1258 {
1259 1259 }
1260 1260
1261 1261 /* ARGSUSED */
1262 1262 static void
1263 1263 lxpr_read_net_netstat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1264 1264 {
1265 1265 }
1266 1266
1267 1267 /* ARGSUSED */
1268 1268 static void
1269 1269 lxpr_read_net_raw(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1270 1270 {
1271 1271 }
1272 1272
1273 1273 /* ARGSUSED */
1274 1274 static void
1275 1275 lxpr_read_net_route(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1276 1276 {
1277 1277 }
1278 1278
1279 1279 /* ARGSUSED */
1280 1280 static void
1281 1281 lxpr_read_net_rpc(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1282 1282 {
1283 1283 }
1284 1284
1285 1285 /* ARGSUSED */
1286 1286 static void
1287 1287 lxpr_read_net_rt_cache(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1288 1288 {
1289 1289 }
1290 1290
1291 1291 /* ARGSUSED */
1292 1292 static void
1293 1293 lxpr_read_net_sockstat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1294 1294 {
1295 1295 }
1296 1296
1297 1297 /* ARGSUSED */
1298 1298 static void
1299 1299 lxpr_read_net_snmp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1300 1300 {
1301 1301 }
1302 1302
1303 1303 /* ARGSUSED */
1304 1304 static void
1305 1305 lxpr_read_net_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1306 1306 {
1307 1307 }
1308 1308
1309 1309 /* ARGSUSED */
1310 1310 static void
1311 1311 lxpr_read_net_tcp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1312 1312 {
1313 1313 }
1314 1314
1315 1315 /* ARGSUSED */
1316 1316 static void
1317 1317 lxpr_read_net_udp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1318 1318 {
1319 1319 }
1320 1320
1321 1321 /* ARGSUSED */
1322 1322 static void
1323 1323 lxpr_read_net_unix(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1324 1324 {
1325 1325 }
1326 1326
1327 1327 /*
1328 1328 * lxpr_read_kmsg(): read the contents of the kernel message queue. We
1329 1329 * translate this into the reception of console messages for this zone; each
1330 1330 * read copies out a single zone console message, or blocks until the next one
1331 1331 * is produced.
1332 1332 */
1333 1333
1334 1334 #define LX_KMSG_PRI "<0>"
1335 1335
1336 1336 static void
1337 1337 lxpr_read_kmsg(lxpr_node_t *lxpnp, struct lxpr_uiobuf *uiobuf)
1338 1338 {
1339 1339 ldi_handle_t lh = lxpnp->lxpr_cons_ldih;
1340 1340 mblk_t *mp;
1341 1341
1342 1342 if (ldi_getmsg(lh, &mp, NULL) == 0) {
1343 1343 /*
1344 1344 * lxproc doesn't like successive reads to the same file
1345 1345 * descriptor unless we do an explicit rewind each time.
1346 1346 */
1347 1347 lxpr_uiobuf_seek(uiobuf, 0);
1348 1348
1349 1349 lxpr_uiobuf_printf(uiobuf, "%s%s", LX_KMSG_PRI,
1350 1350 mp->b_cont->b_rptr);
1351 1351
1352 1352 freemsg(mp);
1353 1353 }
1354 1354 }
1355 1355
1356 1356 /*
1357 1357 * lxpr_read_loadavg(): read the contents of the "loadavg" file. We do just
1358 1358 * enough for uptime and other simple lxproc readers to work
1359 1359 */
1360 1360 extern int nthread;
1361 1361
1362 1362 static void
1363 1363 lxpr_read_loadavg(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1364 1364 {
1365 1365 ulong_t avenrun1;
1366 1366 ulong_t avenrun5;
1367 1367 ulong_t avenrun15;
1368 1368 ulong_t avenrun1_cs;
1369 1369 ulong_t avenrun5_cs;
1370 1370 ulong_t avenrun15_cs;
1371 1371 int loadavg[3];
1372 1372 int *loadbuf;
1373 1373 cpupart_t *cp;
1374 1374 zone_t *zone = LXPTOZ(lxpnp);
1375 1375
1376 1376 uint_t nrunnable = 0;
1377 1377 rctl_qty_t nlwps;
1378 1378
1379 1379 ASSERT(lxpnp->lxpr_type == LXPR_LOADAVG);
1380 1380
1381 1381 mutex_enter(&cpu_lock);
1382 1382
1383 1383 /*
1384 1384 * Need to add up values over all CPU partitions. If pools are active,
1385 1385 * only report the values of the zone's partition, which by definition
1386 1386 * includes the current CPU.
1387 1387 */
1388 1388 if (pool_pset_enabled()) {
1389 1389 psetid_t psetid = zone_pset_get(curproc->p_zone);
1390 1390
1391 1391 ASSERT(curproc->p_zone != &zone0);
1392 1392 cp = CPU->cpu_part;
1393 1393
1394 1394 nrunnable = cp->cp_nrunning + cp->cp_nrunnable;
1395 1395 (void) cpupart_get_loadavg(psetid, &loadavg[0], 3);
1396 1396 loadbuf = &loadavg[0];
1397 1397 } else {
1398 1398 cp = cp_list_head;
1399 1399 do {
1400 1400 nrunnable += cp->cp_nrunning + cp->cp_nrunnable;
1401 1401 } while ((cp = cp->cp_next) != cp_list_head);
1402 1402
1403 1403 loadbuf = zone == global_zone ?
1404 1404 &avenrun[0] : zone->zone_avenrun;
1405 1405 }
1406 1406
1407 1407 /*
1408 1408 * If we're in the non-global zone, we'll report the total number of
1409 1409 * LWPs in the zone for the "nproc" parameter of /proc/loadavg,
1410 1410 * otherwise will just use nthread (which will include kernel threads,
1411 1411 * but should be good enough for lxproc).
1412 1412 */
1413 1413 nlwps = zone == global_zone ? nthread : zone->zone_nlwps;
1414 1414
1415 1415 mutex_exit(&cpu_lock);
1416 1416
1417 1417 avenrun1 = loadbuf[0] >> FSHIFT;
1418 1418 avenrun1_cs = ((loadbuf[0] & (FSCALE-1)) * 100) >> FSHIFT;
1419 1419 avenrun5 = loadbuf[1] >> FSHIFT;
1420 1420 avenrun5_cs = ((loadbuf[1] & (FSCALE-1)) * 100) >> FSHIFT;
1421 1421 avenrun15 = loadbuf[2] >> FSHIFT;
1422 1422 avenrun15_cs = ((loadbuf[2] & (FSCALE-1)) * 100) >> FSHIFT;
1423 1423
1424 1424 lxpr_uiobuf_printf(uiobuf,
1425 1425 "%ld.%02d %ld.%02d %ld.%02d %d/%d %d\n",
1426 1426 avenrun1, avenrun1_cs,
1427 1427 avenrun5, avenrun5_cs,
1428 1428 avenrun15, avenrun15_cs,
1429 1429 nrunnable, nlwps, 0);
1430 1430 }
1431 1431
1432 1432 /*
1433 1433 * lxpr_read_meminfo(): read the contents of the "meminfo" file.
1434 1434 */
1435 1435 static void
1436 1436 lxpr_read_meminfo(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1437 1437 {
1438 1438 zone_t *zone = LXPTOZ(lxpnp);
1439 1439 int global = zone == global_zone;
1440 1440 long total_mem, free_mem, total_swap, used_swap;
1441 1441
1442 1442 ASSERT(lxpnp->lxpr_type == LXPR_MEMINFO);
1443 1443
1444 1444 if (global || zone->zone_phys_mem_ctl == UINT64_MAX) {
1445 1445 total_mem = physmem * PAGESIZE;
1446 1446 free_mem = freemem * PAGESIZE;
1447 1447 } else {
1448 1448 total_mem = zone->zone_phys_mem_ctl;
1449 1449 free_mem = zone->zone_phys_mem_ctl - zone->zone_phys_mem;
1450 1450 }
1451 1451
1452 1452 if (global || zone->zone_max_swap_ctl == UINT64_MAX) {
1453 1453 total_swap = k_anoninfo.ani_max * PAGESIZE;
1454 1454 used_swap = k_anoninfo.ani_phys_resv * PAGESIZE;
1455 1455 } else {
1456 1456 mutex_enter(&zone->zone_mem_lock);
1457 1457 total_swap = zone->zone_max_swap_ctl;
1458 1458 used_swap = zone->zone_max_swap;
1459 1459 mutex_exit(&zone->zone_mem_lock);
1460 1460 }
1461 1461
1462 1462 lxpr_uiobuf_printf(uiobuf,
1463 1463 " total: used: free: shared: buffers: cached:\n"
1464 1464 "Mem: %8lu %8lu %8lu %8u %8u %8u\n"
1465 1465 "Swap: %8lu %8lu %8lu\n"
1466 1466 "MemTotal: %8lu kB\n"
1467 1467 "MemFree: %8lu kB\n"
1468 1468 "MemShared: %8u kB\n"
1469 1469 "Buffers: %8u kB\n"
1470 1470 "Cached: %8u kB\n"
1471 1471 "SwapCached:%8u kB\n"
1472 1472 "Active: %8u kB\n"
1473 1473 "Inactive: %8u kB\n"
1474 1474 "HighTotal: %8u kB\n"
1475 1475 "HighFree: %8u kB\n"
1476 1476 "LowTotal: %8u kB\n"
1477 1477 "LowFree: %8u kB\n"
1478 1478 "SwapTotal: %8lu kB\n"
1479 1479 "SwapFree: %8lu kB\n",
1480 1480 total_mem, total_mem - free_mem, free_mem, 0, 0, 0,
1481 1481 total_swap, used_swap, total_swap - used_swap,
1482 1482 btok(total_mem), /* MemTotal */
1483 1483 btok(free_mem), /* MemFree */
1484 1484 0, /* MemShared */
1485 1485 0, /* Buffers */
1486 1486 0, /* Cached */
1487 1487 0, /* SwapCached */
1488 1488 0, /* Active */
1489 1489 0, /* Inactive */
1490 1490 0, /* HighTotal */
1491 1491 0, /* HighFree */
1492 1492 btok(total_mem), /* LowTotal */
1493 1493 btok(free_mem), /* LowFree */
1494 1494 btok(total_swap), /* SwapTotal */
1495 1495 btok(total_swap - used_swap)); /* SwapFree */
1496 1496 }
1497 1497
1498 1498 /*
1499 1499 * lxpr_read_mounts():
1500 1500 */
1501 1501 /* ARGSUSED */
1502 1502 static void
1503 1503 lxpr_read_mounts(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1504 1504 {
1505 1505 struct vfs *vfsp;
1506 1506 struct vfs *vfslist;
1507 1507 zone_t *zone = LXPTOZ(lxpnp);
1508 1508 struct print_data {
1509 1509 refstr_t *vfs_mntpt;
1510 1510 refstr_t *vfs_resource;
1511 1511 uint_t vfs_flag;
1512 1512 int vfs_fstype;
1513 1513 struct print_data *next;
1514 1514 } *print_head = NULL;
1515 1515 struct print_data **print_tail = &print_head;
1516 1516 struct print_data *printp;
1517 1517
1518 1518 vfs_list_read_lock();
1519 1519
1520 1520 if (zone == global_zone) {
1521 1521 vfsp = vfslist = rootvfs;
1522 1522 } else {
1523 1523 vfsp = vfslist = zone->zone_vfslist;
1524 1524 /*
1525 1525 * If the zone has a root entry, it will be the first in
1526 1526 * the list. If it doesn't, we conjure one up.
1527 1527 */
1528 1528 if (vfslist == NULL || strcmp(refstr_value(vfsp->vfs_mntpt),
1529 1529 zone->zone_rootpath) != 0) {
1530 1530 struct vfs *tvfsp;
1531 1531 /*
1532 1532 * The root of the zone is not a mount point. The vfs
1533 1533 * we want to report is that of the zone's root vnode.
1534 1534 */
1535 1535 tvfsp = zone->zone_rootvp->v_vfsp;
1536 1536
1537 1537 lxpr_uiobuf_printf(uiobuf,
1538 1538 "/ / %s %s 0 0\n",
1539 1539 vfssw[tvfsp->vfs_fstype].vsw_name,
1540 1540 tvfsp->vfs_flag & VFS_RDONLY ? "ro" : "rw");
1541 1541
1542 1542 }
1543 1543 if (vfslist == NULL) {
1544 1544 vfs_list_unlock();
1545 1545 return;
1546 1546 }
1547 1547 }
1548 1548
1549 1549 /*
1550 1550 * Later on we have to do a lookupname, which can end up causing
1551 1551 * another vfs_list_read_lock() to be called. Which can lead to a
1552 1552 * deadlock. To avoid this, we extract the data we need into a local
1553 1553 * list, then we can run this list without holding vfs_list_read_lock()
1554 1554 * We keep the list in the same order as the vfs_list
1555 1555 */
1556 1556 do {
1557 1557 /* Skip mounts we shouldn't show */
1558 1558 if (vfsp->vfs_flag & VFS_NOMNTTAB) {
1559 1559 goto nextfs;
1560 1560 }
1561 1561
1562 1562 printp = kmem_alloc(sizeof (*printp), KM_SLEEP);
1563 1563 refstr_hold(vfsp->vfs_mntpt);
1564 1564 printp->vfs_mntpt = vfsp->vfs_mntpt;
1565 1565 refstr_hold(vfsp->vfs_resource);
1566 1566 printp->vfs_resource = vfsp->vfs_resource;
1567 1567 printp->vfs_flag = vfsp->vfs_flag;
1568 1568 printp->vfs_fstype = vfsp->vfs_fstype;
1569 1569 printp->next = NULL;
1570 1570
1571 1571 *print_tail = printp;
1572 1572 print_tail = &printp->next;
1573 1573
1574 1574 nextfs:
1575 1575 vfsp = (zone == global_zone) ?
1576 1576 vfsp->vfs_next : vfsp->vfs_zone_next;
1577 1577
1578 1578 } while (vfsp != vfslist);
1579 1579
1580 1580 vfs_list_unlock();
1581 1581
1582 1582 /*
1583 1583 * now we can run through what we've extracted without holding
1584 1584 * vfs_list_read_lock()
1585 1585 */
1586 1586 printp = print_head;
1587 1587 while (printp != NULL) {
1588 1588 struct print_data *printp_next;
1589 1589 const char *resource;
1590 1590 char *mntpt;
1591 1591 struct vnode *vp;
1592 1592 int error;
1593 1593
1594 1594 mntpt = (char *)refstr_value(printp->vfs_mntpt);
1595 1595 resource = refstr_value(printp->vfs_resource);
1596 1596
1597 1597 if (mntpt != NULL && mntpt[0] != '\0')
1598 1598 mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
1599 1599 else
1600 1600 mntpt = "-";
1601 1601
1602 1602 error = lookupname(mntpt, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
1603 1603
1604 1604 if (error != 0)
1605 1605 goto nextp;
1606 1606
1607 1607 if (!(vp->v_flag & VROOT)) {
1608 1608 VN_RELE(vp);
1609 1609 goto nextp;
1610 1610 }
1611 1611 VN_RELE(vp);
1612 1612
1613 1613 if (resource != NULL && resource[0] != '\0') {
1614 1614 if (resource[0] == '/') {
1615 1615 resource = ZONE_PATH_VISIBLE(resource, zone) ?
1616 1616 ZONE_PATH_TRANSLATE(resource, zone) :
1617 1617 mntpt;
1618 1618 }
1619 1619 } else {
1620 1620 resource = "-";
1621 1621 }
1622 1622
1623 1623 lxpr_uiobuf_printf(uiobuf,
1624 1624 "%s %s %s %s 0 0\n",
1625 1625 resource, mntpt, vfssw[printp->vfs_fstype].vsw_name,
1626 1626 printp->vfs_flag & VFS_RDONLY ? "ro" : "rw");
1627 1627
1628 1628 nextp:
1629 1629 printp_next = printp->next;
1630 1630 refstr_rele(printp->vfs_mntpt);
1631 1631 refstr_rele(printp->vfs_resource);
1632 1632 kmem_free(printp, sizeof (*printp));
1633 1633 printp = printp_next;
1634 1634
1635 1635 }
1636 1636 }
1637 1637
1638 1638 /*
1639 1639 * lxpr_read_partitions():
1640 1640 *
1641 1641 * We don't support partitions in a local zone because it requires access to
1642 1642 * physical devices. But we need to fake up enough of the file to show that we
1643 1643 * have no partitions.
1644 1644 */
1645 1645 /* ARGSUSED */
1646 1646 static void
1647 1647 lxpr_read_partitions(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1648 1648 {
1649 1649 lxpr_uiobuf_printf(uiobuf,
1650 1650 "major minor #blocks name rio rmerge rsect ruse "
1651 1651 "wio wmerge wsect wuse running use aveq\n\n");
1652 1652 }
1653 1653
1654 1654 /*
1655 1655 * lxpr_read_version(): read the contents of the "version" file. Note that
1656 1656 * we don't lie here -- we don't pretend that we're Linux. If lxproc is to
1657 1657 * be used in a Linux-branded zone, there will need to be a mount option to
1658 1658 * indicate that Linux should be more fully mimicked.
1659 1659 */
1660 1660 /* ARGSUSED */
1661 1661 static void
1662 1662 lxpr_read_version(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1663 1663 {
1664 1664 lxpr_uiobuf_printf(uiobuf,
1665 1665 "%s version %s (%s version %d.%d.%d) "
1666 1666 "#%s SMP %s\n",
1667 1667 utsname.sysname, utsname.release,
1668 1668 #if defined(__GNUC__)
1669 1669 "gcc",
1670 1670 __GNUC__,
1671 1671 __GNUC_MINOR__,
1672 1672 __GNUC_PATCHLEVEL__,
1673 1673 #else
1674 1674 "Sun C",
1675 1675 __SUNPRO_C / 0x100,
1676 1676 (__SUNPRO_C & 0xff) / 0x10,
1677 1677 __SUNPRO_C & 0xf,
1678 1678 #endif
1679 1679 utsname.version,
1680 1680 "00:00:00 00/00/00");
1681 1681 }
1682 1682
1683 1683 /*
1684 1684 * lxpr_read_stat(): read the contents of the "stat" file.
1685 1685 *
1686 1686 */
1687 1687 /* ARGSUSED */
1688 1688 static void
1689 1689 lxpr_read_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1690 1690 {
1691 1691 cpu_t *cp, *cpstart;
1692 1692 int pools_enabled;
1693 1693 ulong_t idle_cum = 0;
1694 1694 ulong_t sys_cum = 0;
1695 1695 ulong_t user_cum = 0;
1696 1696 ulong_t irq_cum = 0;
1697 1697 uint_t cpu_nrunnable_cum = 0;
1698 1698 uint_t w_io_cum = 0;
1699 1699
1700 1700 ulong_t pgpgin_cum = 0;
1701 1701 ulong_t pgpgout_cum = 0;
1702 1702 ulong_t pgswapout_cum = 0;
1703 1703 ulong_t pgswapin_cum = 0;
1704 1704 ulong_t intr_cum = 0;
1705 1705 ulong_t pswitch_cum = 0;
1706 1706 ulong_t forks_cum = 0;
1707 1707 hrtime_t msnsecs[NCMSTATES];
1708 1708
1709 1709 /* temporary variable since scalehrtime modifies data in place */
1710 1710 hrtime_t tmptime;
1711 1711
1712 1712 ASSERT(lxpnp->lxpr_type == LXPR_STAT);
1713 1713
1714 1714 mutex_enter(&cpu_lock);
1715 1715 pools_enabled = pool_pset_enabled();
1716 1716
1717 1717 /* Calculate cumulative stats */
1718 1718 cp = cpstart = CPU->cpu_part->cp_cpulist;
1719 1719 do {
1720 1720 int i;
1721 1721
1722 1722 /*
1723 1723 * Don't count CPUs that aren't even in the system
1724 1724 * or aren't up yet.
1725 1725 */
1726 1726 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1727 1727 continue;
1728 1728 }
1729 1729
1730 1730 get_cpu_mstate(cp, msnsecs);
1731 1731
1732 1732 idle_cum += NSEC_TO_TICK(msnsecs[CMS_IDLE]);
1733 1733 sys_cum += NSEC_TO_TICK(msnsecs[CMS_SYSTEM]);
1734 1734 user_cum += NSEC_TO_TICK(msnsecs[CMS_USER]);
1735 1735
1736 1736 pgpgin_cum += CPU_STATS(cp, vm.pgpgin);
1737 1737 pgpgout_cum += CPU_STATS(cp, vm.pgpgout);
1738 1738 pgswapin_cum += CPU_STATS(cp, vm.pgswapin);
1739 1739 pgswapout_cum += CPU_STATS(cp, vm.pgswapout);
1740 1740
1741 1741 cpu_nrunnable_cum += cp->cpu_disp->disp_nrunnable;
1742 1742 w_io_cum += CPU_STATS(cp, sys.iowait);
1743 1743 for (i = 0; i < NCMSTATES; i++) {
1744 1744 tmptime = cp->cpu_intracct[i];
1745 1745 scalehrtime(&tmptime);
1746 1746 irq_cum += NSEC_TO_TICK(tmptime);
1747 1747 }
1748 1748
1749 1749 for (i = 0; i < PIL_MAX; i++)
1750 1750 intr_cum += CPU_STATS(cp, sys.intr[i]);
1751 1751
1752 1752 pswitch_cum += CPU_STATS(cp, sys.pswitch);
1753 1753 forks_cum += CPU_STATS(cp, sys.sysfork);
1754 1754 forks_cum += CPU_STATS(cp, sys.sysvfork);
1755 1755
1756 1756 if (pools_enabled)
1757 1757 cp = cp->cpu_next_part;
1758 1758 else
1759 1759 cp = cp->cpu_next;
1760 1760 } while (cp != cpstart);
1761 1761
1762 1762 lxpr_uiobuf_printf(uiobuf, "cpu %ld %ld %ld %ld %ld %ld %ld\n",
1763 1763 user_cum, 0, sys_cum, idle_cum, 0, irq_cum, 0);
1764 1764
1765 1765 /* Do per processor stats */
1766 1766 do {
1767 1767 int i;
1768 1768
1769 1769 ulong_t idle_ticks;
1770 1770 ulong_t sys_ticks;
1771 1771 ulong_t user_ticks;
1772 1772 ulong_t irq_ticks = 0;
1773 1773
1774 1774 /*
1775 1775 * Don't count CPUs that aren't even in the system
1776 1776 * or aren't up yet.
1777 1777 */
1778 1778 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1779 1779 continue;
1780 1780 }
1781 1781
1782 1782 get_cpu_mstate(cp, msnsecs);
1783 1783
1784 1784 idle_ticks = NSEC_TO_TICK(msnsecs[CMS_IDLE]);
1785 1785 sys_ticks = NSEC_TO_TICK(msnsecs[CMS_SYSTEM]);
1786 1786 user_ticks = NSEC_TO_TICK(msnsecs[CMS_USER]);
1787 1787
1788 1788 for (i = 0; i < NCMSTATES; i++) {
1789 1789 tmptime = cp->cpu_intracct[i];
1790 1790 scalehrtime(&tmptime);
1791 1791 irq_ticks += NSEC_TO_TICK(tmptime);
1792 1792 }
1793 1793
1794 1794 lxpr_uiobuf_printf(uiobuf,
1795 1795 "cpu%d %ld %ld %ld %ld %ld %ld %ld\n",
1796 1796 cp->cpu_id, user_ticks, 0, sys_ticks, idle_ticks,
1797 1797 0, irq_ticks, 0);
1798 1798
1799 1799 if (pools_enabled)
1800 1800 cp = cp->cpu_next_part;
1801 1801 else
1802 1802 cp = cp->cpu_next;
1803 1803 } while (cp != cpstart);
1804 1804
1805 1805 mutex_exit(&cpu_lock);
1806 1806
1807 1807 lxpr_uiobuf_printf(uiobuf,
1808 1808 "page %lu %lu\n"
1809 1809 "swap %lu %lu\n"
1810 1810 "intr %lu\n"
1811 1811 "ctxt %lu\n"
1812 1812 "btime %lu\n"
1813 1813 "processes %lu\n"
1814 1814 "procs_running %lu\n"
1815 1815 "procs_blocked %lu\n",
1816 1816 pgpgin_cum, pgpgout_cum,
1817 1817 pgswapin_cum, pgswapout_cum,
1818 1818 intr_cum,
1819 1819 pswitch_cum,
1820 1820 boot_time,
1821 1821 forks_cum,
1822 1822 cpu_nrunnable_cum,
1823 1823 w_io_cum);
1824 1824 }
1825 1825
1826 1826 /*
1827 1827 * lxpr_read_uptime(): read the contents of the "uptime" file.
1828 1828 *
1829 1829 * format is: "%.2lf, %.2lf",uptime_secs, idle_secs
1830 1830 * Use fixed point arithmetic to get 2 decimal places
1831 1831 */
1832 1832 /* ARGSUSED */
1833 1833 static void
1834 1834 lxpr_read_uptime(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1835 1835 {
1836 1836 cpu_t *cp, *cpstart;
1837 1837 int pools_enabled;
1838 1838 ulong_t idle_cum = 0;
1839 1839 ulong_t cpu_count = 0;
1840 1840 ulong_t idle_s;
1841 1841 ulong_t idle_cs;
1842 1842 ulong_t up_s;
1843 1843 ulong_t up_cs;
1844 1844 hrtime_t birthtime;
1845 1845 hrtime_t centi_sec = 10000000; /* 10^7 */
1846 1846
1847 1847 ASSERT(lxpnp->lxpr_type == LXPR_UPTIME);
1848 1848
1849 1849 /* Calculate cumulative stats */
1850 1850 mutex_enter(&cpu_lock);
1851 1851 pools_enabled = pool_pset_enabled();
1852 1852
1853 1853 cp = cpstart = CPU;
1854 1854 do {
1855 1855 /*
1856 1856 * Don't count CPUs that aren't even in the system
1857 1857 * or aren't up yet.
1858 1858 */
1859 1859 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1860 1860 continue;
1861 1861 }
1862 1862
1863 1863 idle_cum += CPU_STATS(cp, sys.cpu_ticks_idle);
1864 1864 idle_cum += CPU_STATS(cp, sys.cpu_ticks_wait);
1865 1865 cpu_count += 1;
1866 1866
1867 1867 if (pools_enabled)
1868 1868 cp = cp->cpu_next_part;
1869 1869 else
1870 1870 cp = cp->cpu_next;
1871 1871 } while (cp != cpstart);
1872 1872 mutex_exit(&cpu_lock);
1873 1873
1874 1874 /* Getting the Zone zsched process startup time */
1875 1875 birthtime = LXPTOZ(lxpnp)->zone_zsched->p_mstart;
1876 1876 up_cs = (gethrtime() - birthtime) / centi_sec;
1877 1877 up_s = up_cs / 100;
1878 1878 up_cs %= 100;
1879 1879
1880 1880 ASSERT(cpu_count > 0);
1881 1881 idle_cum /= cpu_count;
1882 1882 idle_s = idle_cum / hz;
1883 1883 idle_cs = idle_cum % hz;
1884 1884 idle_cs *= 100;
1885 1885 idle_cs /= hz;
1886 1886
1887 1887 lxpr_uiobuf_printf(uiobuf,
1888 1888 "%ld.%02d %ld.%02d\n", up_s, up_cs, idle_s, idle_cs);
1889 1889 }
1890 1890
1891 1891 static const char *amd_x_edx[] = {
1892 1892 NULL, NULL, NULL, NULL,
1893 1893 NULL, NULL, NULL, NULL,
1894 1894 NULL, NULL, NULL, "syscall",
1895 1895 NULL, NULL, NULL, NULL,
1896 1896 NULL, NULL, NULL, "mp",
1897 1897 "nx", NULL, "mmxext", NULL,
1898 1898 NULL, NULL, NULL, NULL,
1899 1899 NULL, "lm", "3dnowext", "3dnow"
1900 1900 };
1901 1901
1902 1902 static const char *amd_x_ecx[] = {
1903 1903 "lahf_lm", NULL, "svm", NULL,
1904 1904 "altmovcr8"
1905 1905 };
1906 1906
1907 1907 static const char *tm_x_edx[] = {
1908 1908 "recovery", "longrun", NULL, "lrti"
1909 1909 };
1910 1910
1911 1911 /*
1912 1912 * Intel calls no-execute "xd" in its docs, but Linux still reports it as "nx."
1913 1913 */
1914 1914 static const char *intc_x_edx[] = {
1915 1915 NULL, NULL, NULL, NULL,
1916 1916 NULL, NULL, NULL, NULL,
1917 1917 NULL, NULL, NULL, "syscall",
1918 1918 NULL, NULL, NULL, NULL,
1919 1919 NULL, NULL, NULL, NULL,
1920 1920 "nx", NULL, NULL, NULL,
1921 1921 NULL, NULL, NULL, NULL,
1922 1922 NULL, "lm", NULL, NULL
1923 1923 };
1924 1924
1925 1925 static const char *intc_edx[] = {
1926 1926 "fpu", "vme", "de", "pse",
1927 1927 "tsc", "msr", "pae", "mce",
1928 1928 "cx8", "apic", NULL, "sep",
1929 1929 "mtrr", "pge", "mca", "cmov",
1930 1930 "pat", "pse36", "pn", "clflush",
1931 1931 NULL, "dts", "acpi", "mmx",
1932 1932 "fxsr", "sse", "sse2", "ss",
1933 1933 "ht", "tm", "ia64", "pbe"
1934 1934 };
1935 1935
1936 1936 /*
1937 1937 * "sse3" on linux is called "pni" (Prescott New Instructions).
1938 1938 */
1939 1939 static const char *intc_ecx[] = {
1940 1940 "pni", NULL, NULL, "monitor",
1941 1941 "ds_cpl", NULL, NULL, "est",
1942 1942 "tm2", NULL, "cid", NULL,
1943 1943 NULL, "cx16", "xtpr"
1944 1944 };
1945 1945
1946 1946 static void
1947 1947 lxpr_read_cpuinfo(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1948 1948 {
1949 1949 int i;
1950 1950 uint32_t bits;
1951 1951 cpu_t *cp, *cpstart;
1952 1952 int pools_enabled;
1953 1953 const char **fp;
1954 1954 char brandstr[CPU_IDSTRLEN];
1955 1955 struct cpuid_regs cpr;
1956 1956 int maxeax;
1957 1957 int std_ecx, std_edx, ext_ecx, ext_edx;
1958 1958
1959 1959 ASSERT(lxpnp->lxpr_type == LXPR_CPUINFO);
1960 1960
1961 1961 mutex_enter(&cpu_lock);
1962 1962 pools_enabled = pool_pset_enabled();
1963 1963
1964 1964 cp = cpstart = CPU;
1965 1965 do {
1966 1966 /*
1967 1967 * This returns the maximum eax value for standard cpuid
1968 1968 * functions in eax.
1969 1969 */
1970 1970 cpr.cp_eax = 0;
1971 1971 (void) cpuid_insn(cp, &cpr);
1972 1972 maxeax = cpr.cp_eax;
1973 1973
1974 1974 /*
1975 1975 * Get standard x86 feature flags.
1976 1976 */
1977 1977 cpr.cp_eax = 1;
1978 1978 (void) cpuid_insn(cp, &cpr);
1979 1979 std_ecx = cpr.cp_ecx;
1980 1980 std_edx = cpr.cp_edx;
1981 1981
1982 1982 /*
1983 1983 * Now get extended feature flags.
1984 1984 */
1985 1985 cpr.cp_eax = 0x80000001;
1986 1986 (void) cpuid_insn(cp, &cpr);
1987 1987 ext_ecx = cpr.cp_ecx;
1988 1988 ext_edx = cpr.cp_edx;
1989 1989
1990 1990 (void) cpuid_getbrandstr(cp, brandstr, CPU_IDSTRLEN);
1991 1991
1992 1992 lxpr_uiobuf_printf(uiobuf,
1993 1993 "processor\t: %d\n"
1994 1994 "vendor_id\t: %s\n"
1995 1995 "cpu family\t: %d\n"
1996 1996 "model\t\t: %d\n"
1997 1997 "model name\t: %s\n"
1998 1998 "stepping\t: %d\n"
1999 1999 "cpu MHz\t\t: %u.%03u\n",
2000 2000 cp->cpu_id, cpuid_getvendorstr(cp), cpuid_getfamily(cp),
2001 2001 cpuid_getmodel(cp), brandstr, cpuid_getstep(cp),
2002 2002 (uint32_t)(cpu_freq_hz / 1000000),
2003 2003 ((uint32_t)(cpu_freq_hz / 1000)) % 1000);
2004 2004
2005 2005 lxpr_uiobuf_printf(uiobuf, "cache size\t: %u KB\n",
2006 2006 getl2cacheinfo(cp, NULL, NULL, NULL) / 1024);
2007 2007
2008 2008 if (is_x86_feature(x86_featureset, X86FSET_HTT)) {
2009 2009 /*
2010 2010 * 'siblings' is used for HT-style threads
2011 2011 */
2012 2012 lxpr_uiobuf_printf(uiobuf,
2013 2013 "physical id\t: %lu\n"
2014 2014 "siblings\t: %u\n",
2015 2015 pg_plat_hw_instance_id(cp, PGHW_CHIP),
2016 2016 cpuid_get_ncpu_per_chip(cp));
2017 2017 }
2018 2018
2019 2019 /*
2020 2020 * Since we're relatively picky about running on older hardware,
2021 2021 * we can be somewhat cavalier about the answers to these ones.
2022 2022 *
2023 2023 * In fact, given the hardware we support, we just say:
2024 2024 *
2025 2025 * fdiv_bug : no (if we're on a 64-bit kernel)
2026 2026 * hlt_bug : no
2027 2027 * f00f_bug : no
2028 2028 * coma_bug : no
2029 2029 * wp : yes (write protect in supervsr mode)
2030 2030 */
2031 2031 lxpr_uiobuf_printf(uiobuf,
2032 2032 "fdiv_bug\t: %s\n"
2033 2033 "hlt_bug \t: no\n"
2034 2034 "f00f_bug\t: no\n"
2035 2035 "coma_bug\t: no\n"
2036 2036 "fpu\t\t: %s\n"
2037 2037 "fpu_exception\t: %s\n"
2038 2038 "cpuid level\t: %d\n"
2039 2039 "flags\t\t:",
2040 2040 #if defined(__i386)
2041 2041 fpu_pentium_fdivbug ? "yes" : "no",
2042 2042 #else
2043 2043 "no",
2044 2044 #endif /* __i386 */
2045 2045 fpu_exists ? "yes" : "no", fpu_exists ? "yes" : "no",
2046 2046 maxeax);
2047 2047
2048 2048 for (bits = std_edx, fp = intc_edx, i = 0;
2049 2049 i < sizeof (intc_edx) / sizeof (intc_edx[0]); fp++, i++)
2050 2050 if ((bits & (1 << i)) != 0 && *fp)
2051 2051 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2052 2052
2053 2053 /*
2054 2054 * name additional features where appropriate
2055 2055 */
2056 2056 switch (x86_vendor) {
2057 2057 case X86_VENDOR_Intel:
2058 2058 for (bits = ext_edx, fp = intc_x_edx, i = 0;
2059 2059 i < sizeof (intc_x_edx) / sizeof (intc_x_edx[0]);
2060 2060 fp++, i++)
2061 2061 if ((bits & (1 << i)) != 0 && *fp)
2062 2062 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2063 2063 break;
2064 2064
2065 2065 case X86_VENDOR_AMD:
2066 2066 for (bits = ext_edx, fp = amd_x_edx, i = 0;
2067 2067 i < sizeof (amd_x_edx) / sizeof (amd_x_edx[0]);
2068 2068 fp++, i++)
2069 2069 if ((bits & (1 << i)) != 0 && *fp)
2070 2070 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2071 2071
2072 2072 for (bits = ext_ecx, fp = amd_x_ecx, i = 0;
2073 2073 i < sizeof (amd_x_ecx) / sizeof (amd_x_ecx[0]);
2074 2074 fp++, i++)
2075 2075 if ((bits & (1 << i)) != 0 && *fp)
2076 2076 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2077 2077 break;
2078 2078
2079 2079 case X86_VENDOR_TM:
2080 2080 for (bits = ext_edx, fp = tm_x_edx, i = 0;
2081 2081 i < sizeof (tm_x_edx) / sizeof (tm_x_edx[0]);
2082 2082 fp++, i++)
2083 2083 if ((bits & (1 << i)) != 0 && *fp)
2084 2084 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2085 2085 break;
2086 2086 default:
2087 2087 break;
2088 2088 }
2089 2089
2090 2090 for (bits = std_ecx, fp = intc_ecx, i = 0;
2091 2091 i < sizeof (intc_ecx) / sizeof (intc_ecx[0]); fp++, i++)
2092 2092 if ((bits & (1 << i)) != 0 && *fp)
2093 2093 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2094 2094
2095 2095 lxpr_uiobuf_printf(uiobuf, "\n\n");
2096 2096
2097 2097 if (pools_enabled)
2098 2098 cp = cp->cpu_next_part;
2099 2099 else
2100 2100 cp = cp->cpu_next;
2101 2101 } while (cp != cpstart);
2102 2102
2103 2103 mutex_exit(&cpu_lock);
2104 2104 }
2105 2105
2106 2106 /* ARGSUSED */
2107 2107 static void
2108 2108 lxpr_read_fd(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
2109 2109 {
2110 2110 ASSERT(lxpnp->lxpr_type == LXPR_PID_FD_FD);
2111 2111 lxpr_uiobuf_seterr(uiobuf, EFAULT);
2112 2112 }
2113 2113
2114 2114 /*
2115 2115 * lxpr_getattr(): Vnode operation for VOP_GETATTR()
2116 2116 */
2117 2117 static int
2118 2118 lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
2119 2119 caller_context_t *ct)
2120 2120 {
2121 2121 register lxpr_node_t *lxpnp = VTOLXP(vp);
2122 2122 lxpr_nodetype_t type = lxpnp->lxpr_type;
2123 2123 extern uint_t nproc;
2124 2124 int error;
2125 2125
2126 2126 /*
2127 2127 * Return attributes of underlying vnode if ATTR_REAL
2128 2128 *
2129 2129 * but keep fd files with the symlink permissions
2130 2130 */
2131 2131 if (lxpnp->lxpr_realvp != NULL && (flags & ATTR_REAL)) {
2132 2132 vnode_t *rvp = lxpnp->lxpr_realvp;
2133 2133
2134 2134 /*
2135 2135 * withold attribute information to owner or root
2136 2136 */
2137 2137 if ((error = VOP_ACCESS(rvp, 0, 0, cr, ct)) != 0) {
2138 2138 return (error);
2139 2139 }
2140 2140
2141 2141 /*
2142 2142 * now its attributes
2143 2143 */
2144 2144 if ((error = VOP_GETATTR(rvp, vap, flags, cr, ct)) != 0) {
2145 2145 return (error);
2146 2146 }
2147 2147
2148 2148 /*
2149 2149 * if it's a file in lx /proc/pid/fd/xx then set its
2150 2150 * mode and keep it looking like a symlink
2151 2151 */
2152 2152 if (type == LXPR_PID_FD_FD) {
2153 2153 vap->va_mode = lxpnp->lxpr_mode;
2154 2154 vap->va_type = vp->v_type;
2155 2155 vap->va_size = 0;
2156 2156 vap->va_nlink = 1;
2157 2157 }
2158 2158 return (0);
2159 2159 }
2160 2160
2161 2161 /* Default attributes, that may be overridden below */
2162 2162 bzero(vap, sizeof (*vap));
2163 2163 vap->va_atime = vap->va_mtime = vap->va_ctime = lxpnp->lxpr_time;
2164 2164 vap->va_nlink = 1;
2165 2165 vap->va_type = vp->v_type;
2166 2166 vap->va_mode = lxpnp->lxpr_mode;
2167 2167 vap->va_fsid = vp->v_vfsp->vfs_dev;
2168 2168 vap->va_blksize = DEV_BSIZE;
2169 2169 vap->va_uid = lxpnp->lxpr_uid;
2170 2170 vap->va_gid = lxpnp->lxpr_gid;
2171 2171 vap->va_nodeid = lxpnp->lxpr_ino;
2172 2172
2173 2173 switch (type) {
2174 2174 case LXPR_PROCDIR:
2175 2175 vap->va_nlink = nproc + 2 + PROCDIRFILES;
2176 2176 vap->va_size = (nproc + 2 + PROCDIRFILES) * LXPR_SDSIZE;
2177 2177 break;
2178 2178 case LXPR_PIDDIR:
2179 2179 vap->va_nlink = PIDDIRFILES;
2180 2180 vap->va_size = PIDDIRFILES * LXPR_SDSIZE;
2181 2181 break;
2182 2182 case LXPR_SELF:
2183 2183 vap->va_uid = crgetruid(curproc->p_cred);
2184 2184 vap->va_gid = crgetrgid(curproc->p_cred);
2185 2185 break;
2186 2186 default:
2187 2187 break;
2188 2188 }
2189 2189
2190 2190 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
2191 2191 return (0);
2192 2192 }
2193 2193
2194 2194 /*
2195 2195 * lxpr_access(): Vnode operation for VOP_ACCESS()
2196 2196 */
2197 2197 static int
2198 2198 lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
2199 2199 {
2200 2200 lxpr_node_t *lxpnp = VTOLXP(vp);
2201 2201 int shift = 0;
2202 2202 proc_t *tp;
2203 2203
2204 2204 /* lx /proc is a read only file system */
2205 2205 if (mode & VWRITE)
2206 2206 return (EROFS);
2207 2207
2208 2208 /*
2209 2209 * If this is a restricted file, check access permissions.
2210 2210 */
2211 2211 switch (lxpnp->lxpr_type) {
2212 2212 case LXPR_PIDDIR:
2213 2213 return (0);
2214 2214 case LXPR_PID_CURDIR:
2215 2215 case LXPR_PID_ENV:
2216 2216 case LXPR_PID_EXE:
2217 2217 case LXPR_PID_MAPS:
2218 2218 case LXPR_PID_MEM:
2219 2219 case LXPR_PID_ROOTDIR:
2220 2220 case LXPR_PID_FDDIR:
2221 2221 case LXPR_PID_FD_FD:
2222 2222 if ((tp = lxpr_lock(lxpnp->lxpr_pid)) == NULL)
2223 2223 return (ENOENT);
2224 2224 if (tp != curproc && secpolicy_proc_access(cr) != 0 &&
2225 2225 priv_proc_cred_perm(cr, tp, NULL, mode) != 0) {
2226 2226 lxpr_unlock(tp);
2227 2227 return (EACCES);
2228 2228 }
2229 2229 lxpr_unlock(tp);
2230 2230 default:
2231 2231 break;
2232 2232 }
2233 2233
2234 2234 if (lxpnp->lxpr_realvp != NULL) {
2235 2235 /*
2236 2236 * For these we use the underlying vnode's accessibility.
2237 2237 */
2238 2238 return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr, ct));
2239 2239 }
2240 2240
2241 2241 /* If user is root allow access regardless of permission bits */
2242 2242 if (secpolicy_proc_access(cr) == 0)
2243 2243 return (0);
2244 2244
2245 2245 /*
2246 2246 * Access check is based on only one of owner, group, public. If not
2247 2247 * owner, then check group. If not a member of the group, then check
2248 2248 * public access.
2249 2249 */
2250 2250 if (crgetuid(cr) != lxpnp->lxpr_uid) {
2251 2251 shift += 3;
2252 2252 if (!groupmember((uid_t)lxpnp->lxpr_gid, cr))
2253 2253 shift += 3;
2254 2254 }
2255 2255
2256 2256 mode &= ~(lxpnp->lxpr_mode << shift);
2257 2257
2258 2258 if (mode == 0)
2259 2259 return (0);
2260 2260
2261 2261 return (EACCES);
2262 2262 }
2263 2263
2264 2264 /* ARGSUSED */
2265 2265 static vnode_t *
2266 2266 lxpr_lookup_not_a_dir(vnode_t *dp, char *comp)
2267 2267 {
2268 2268 return (NULL);
2269 2269 }
2270 2270
2271 2271 /*
2272 2272 * lxpr_lookup(): Vnode operation for VOP_LOOKUP()
2273 2273 */
2274 2274 /* ARGSUSED */
2275 2275 static int
2276 2276 lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
2277 2277 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
2278 2278 int *direntflags, pathname_t *realpnp)
2279 2279 {
2280 2280 lxpr_node_t *lxpnp = VTOLXP(dp);
2281 2281 lxpr_nodetype_t type = lxpnp->lxpr_type;
2282 2282 int error;
2283 2283
2284 2284 ASSERT(dp->v_type == VDIR);
2285 2285 ASSERT(type >= 0 && type < LXPR_NFILES);
2286 2286
2287 2287 /*
2288 2288 * we should never get here because the lookup
2289 2289 * is done on the realvp for these nodes
2290 2290 */
2291 2291 ASSERT(type != LXPR_PID_FD_FD &&
2292 2292 type != LXPR_PID_CURDIR &&
2293 2293 type != LXPR_PID_ROOTDIR);
2294 2294
2295 2295 /*
2296 2296 * restrict lookup permission to owner or root
2297 2297 */
2298 2298 if ((error = lxpr_access(dp, VEXEC, 0, cr, ct)) != 0) {
2299 2299 return (error);
2300 2300 }
2301 2301
2302 2302 /*
2303 2303 * Just return the parent vnode if that's where we are trying to go.
2304 2304 */
2305 2305 if (strcmp(comp, "..") == 0) {
2306 2306 VN_HOLD(lxpnp->lxpr_parent);
2307 2307 *vpp = lxpnp->lxpr_parent;
2308 2308 return (0);
2309 2309 }
2310 2310
2311 2311 /*
2312 2312 * Special handling for directory searches. Note: null component name
2313 2313 * denotes that the current directory is being searched.
2314 2314 */
2315 2315 if ((dp->v_type == VDIR) && (*comp == '\0' || strcmp(comp, ".") == 0)) {
2316 2316 VN_HOLD(dp);
2317 2317 *vpp = dp;
2318 2318 return (0);
2319 2319 }
2320 2320
2321 2321 *vpp = (lxpr_lookup_function[type](dp, comp));
2322 2322 return ((*vpp == NULL) ? ENOENT : 0);
2323 2323 }
2324 2324
2325 2325 /*
2326 2326 * Do a sequential search on the given directory table
2327 2327 */
2328 2328 static vnode_t *
2329 2329 lxpr_lookup_common(vnode_t *dp, char *comp, proc_t *p,
2330 2330 lxpr_dirent_t *dirtab, int dirtablen)
2331 2331 {
2332 2332 lxpr_node_t *lxpnp;
2333 2333 int count;
2334 2334
2335 2335 for (count = 0; count < dirtablen; count++) {
2336 2336 if (strcmp(dirtab[count].d_name, comp) == 0) {
2337 2337 lxpnp = lxpr_getnode(dp, dirtab[count].d_type, p, 0);
2338 2338 dp = LXPTOV(lxpnp);
2339 2339 ASSERT(dp != NULL);
2340 2340 return (dp);
2341 2341 }
2342 2342 }
2343 2343 return (NULL);
2344 2344 }
2345 2345
2346 2346 static vnode_t *
2347 2347 lxpr_lookup_piddir(vnode_t *dp, char *comp)
2348 2348 {
2349 2349 proc_t *p;
2350 2350
2351 2351 ASSERT(VTOLXP(dp)->lxpr_type == LXPR_PIDDIR);
2352 2352
2353 2353 p = lxpr_lock(VTOLXP(dp)->lxpr_pid);
2354 2354 if (p == NULL)
2355 2355 return (NULL);
2356 2356
2357 2357 dp = lxpr_lookup_common(dp, comp, p, piddir, PIDDIRFILES);
2358 2358
2359 2359 lxpr_unlock(p);
2360 2360
2361 2361 return (dp);
2362 2362 }
2363 2363
2364 2364 /*
2365 2365 * Lookup one of the process's open files.
2366 2366 */
2367 2367 static vnode_t *
2368 2368 lxpr_lookup_fddir(vnode_t *dp, char *comp)
2369 2369 {
2370 2370 lxpr_node_t *dlxpnp = VTOLXP(dp);
2371 2371 lxpr_node_t *lxpnp;
2372 2372 vnode_t *vp = NULL;
2373 2373 proc_t *p;
2374 2374 file_t *fp;
2375 2375 uint_t fd;
2376 2376 int c;
2377 2377 uf_entry_t *ufp;
2378 2378 uf_info_t *fip;
2379 2379
2380 2380 ASSERT(dlxpnp->lxpr_type == LXPR_PID_FDDIR);
2381 2381
2382 2382 /*
2383 2383 * convert the string rendition of the filename
2384 2384 * to a file descriptor
2385 2385 */
2386 2386 fd = 0;
2387 2387 while ((c = *comp++) != '\0') {
2388 2388 int ofd;
2389 2389 if (c < '0' || c > '9')
2390 2390 return (NULL);
2391 2391
2392 2392 ofd = fd;
2393 2393 fd = 10*fd + c - '0';
2394 2394 /* integer overflow */
2395 2395 if (fd / 10 != ofd)
2396 2396 return (NULL);
2397 2397 }
2398 2398
2399 2399 /*
2400 2400 * get the proc to work with and lock it
2401 2401 */
2402 2402 p = lxpr_lock(dlxpnp->lxpr_pid);
2403 2403 if ((p == NULL))
2404 2404 return (NULL);
2405 2405
2406 2406 /*
2407 2407 * If the process is a zombie or system process
2408 2408 * it can't have any open files.
2409 2409 */
2410 2410 if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas)) {
2411 2411 lxpr_unlock(p);
2412 2412 return (NULL);
2413 2413 }
2414 2414
2415 2415 /*
2416 2416 * get us a fresh node/vnode
2417 2417 */
2418 2418 lxpnp = lxpr_getnode(dp, LXPR_PID_FD_FD, p, fd);
2419 2419
2420 2420 /*
2421 2421 * get open file info
2422 2422 */
2423 2423 fip = (&(p)->p_user.u_finfo);
2424 2424 mutex_enter(&fip->fi_lock);
2425 2425
2426 2426 /*
2427 2427 * got the fd data so now done with this proc
2428 2428 */
2429 2429 lxpr_unlock(p);
2430 2430
2431 2431 if (fd < fip->fi_nfiles) {
2432 2432 UF_ENTER(ufp, fip, fd);
2433 2433 /*
2434 2434 * ensure the fd is still kosher.
2435 2435 * it may have gone between the readdir and
2436 2436 * the lookup
2437 2437 */
2438 2438 if (fip->fi_list[fd].uf_file == NULL) {
2439 2439 mutex_exit(&fip->fi_lock);
2440 2440 UF_EXIT(ufp);
2441 2441 lxpr_freenode(lxpnp);
2442 2442 return (NULL);
2443 2443 }
2444 2444
2445 2445 if ((fp = ufp->uf_file) != NULL)
2446 2446 vp = fp->f_vnode;
2447 2447 UF_EXIT(ufp);
2448 2448 }
2449 2449 mutex_exit(&fip->fi_lock);
2450 2450
2451 2451 if (vp == NULL) {
2452 2452 lxpr_freenode(lxpnp);
2453 2453 return (NULL);
2454 2454 } else {
2455 2455 /*
2456 2456 * Fill in the lxpr_node so future references will be able to
2457 2457 * find the underlying vnode. The vnode is held on the realvp.
2458 2458 */
2459 2459 lxpnp->lxpr_realvp = vp;
2460 2460 VN_HOLD(lxpnp->lxpr_realvp);
2461 2461 }
2462 2462
2463 2463 dp = LXPTOV(lxpnp);
2464 2464 ASSERT(dp != NULL);
2465 2465
2466 2466 return (dp);
2467 2467 }
2468 2468
2469 2469 static vnode_t *
2470 2470 lxpr_lookup_netdir(vnode_t *dp, char *comp)
2471 2471 {
2472 2472 ASSERT(VTOLXP(dp)->lxpr_type == LXPR_NETDIR);
2473 2473
2474 2474 dp = lxpr_lookup_common(dp, comp, NULL, netdir, NETDIRFILES);
2475 2475
2476 2476 return (dp);
2477 2477 }
2478 2478
2479 2479 static vnode_t *
2480 2480 lxpr_lookup_procdir(vnode_t *dp, char *comp)
2481 2481 {
2482 2482 ASSERT(VTOLXP(dp)->lxpr_type == LXPR_PROCDIR);
2483 2483
2484 2484 /*
2485 2485 * We know all the names of files & dirs in our file system structure
2486 2486 * except those that are pid names. These change as pids are created/
2487 2487 * deleted etc., so we just look for a number as the first char to see
2488 2488 * if we are we doing pid lookups.
2489 2489 *
2490 2490 * Don't need to check for "self" as it is implemented as a symlink
2491 2491 */
2492 2492 if (*comp >= '0' && *comp <= '9') {
2493 2493 pid_t pid = 0;
2494 2494 lxpr_node_t *lxpnp = NULL;
2495 2495 proc_t *p;
2496 2496 int c;
2497 2497
2498 2498 while ((c = *comp++) != '\0')
2499 2499 pid = 10 * pid + c - '0';
2500 2500
2501 2501 /*
2502 2502 * Can't continue if the process is still loading or it doesn't
2503 2503 * really exist yet (or maybe it just died!)
2504 2504 */
2505 2505 p = lxpr_lock(pid);
2506 2506 if (p == NULL)
2507 2507 return (NULL);
2508 2508
2509 2509 if (secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
2510 2510 lxpr_unlock(p);
2511 2511 return (NULL);
2512 2512 }
2513 2513
2514 2514 /*
2515 2515 * allocate and fill in a new lxpr node
2516 2516 */
2517 2517 lxpnp = lxpr_getnode(dp, LXPR_PIDDIR, p, 0);
2518 2518
2519 2519 lxpr_unlock(p);
2520 2520
2521 2521 dp = LXPTOV(lxpnp);
2522 2522 ASSERT(dp != NULL);
2523 2523
2524 2524 return (dp);
2525 2525 }
2526 2526
2527 2527 /* Lookup fixed names */
2528 2528 return (lxpr_lookup_common(dp, comp, NULL, lxpr_dir, PROCDIRFILES));
2529 2529 }
2530 2530
2531 2531 /*
2532 2532 * lxpr_readdir(): Vnode operation for VOP_READDIR()
2533 2533 */
2534 2534 /* ARGSUSED */
2535 2535 static int
2536 2536 lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp,
2537 2537 caller_context_t *ct, int flags)
2538 2538 {
2539 2539 lxpr_node_t *lxpnp = VTOLXP(dp);
2540 2540 lxpr_nodetype_t type = lxpnp->lxpr_type;
2541 2541 ssize_t uresid;
2542 2542 off_t uoffset;
2543 2543 int error;
2544 2544
2545 2545 ASSERT(dp->v_type == VDIR);
2546 2546 ASSERT(type >= 0 && type < LXPR_NFILES);
2547 2547
2548 2548 /*
2549 2549 * we should never get here because the readdir
2550 2550 * is done on the realvp for these nodes
2551 2551 */
2552 2552 ASSERT(type != LXPR_PID_FD_FD &&
2553 2553 type != LXPR_PID_CURDIR &&
2554 2554 type != LXPR_PID_ROOTDIR);
2555 2555
2556 2556 /*
2557 2557 * restrict readdir permission to owner or root
2558 2558 */
2559 2559 if ((error = lxpr_access(dp, VREAD, 0, cr, ct)) != 0)
2560 2560 return (error);
2561 2561
2562 2562 uoffset = uiop->uio_offset;
2563 2563 uresid = uiop->uio_resid;
2564 2564
2565 2565 /* can't do negative reads */
2566 2566 if (uoffset < 0 || uresid <= 0)
2567 2567 return (EINVAL);
2568 2568
2569 2569 /* can't read directory entries that don't exist! */
2570 2570 if (uoffset % LXPR_SDSIZE)
2571 2571 return (ENOENT);
2572 2572
2573 2573 return (lxpr_readdir_function[lxpnp->lxpr_type](lxpnp, uiop, eofp));
2574 2574 }
2575 2575
2576 2576 /* ARGSUSED */
2577 2577 static int
2578 2578 lxpr_readdir_not_a_dir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2579 2579 {
2580 2580 return (ENOTDIR);
2581 2581 }
2582 2582
2583 2583 /*
2584 2584 * This has the common logic for returning directory entries
2585 2585 */
2586 2586 static int
2587 2587 lxpr_readdir_common(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp,
2588 2588 lxpr_dirent_t *dirtab, int dirtablen)
2589 2589 {
2590 2590 /* bp holds one dirent64 structure */
2591 2591 longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2592 2592 dirent64_t *dirent = (dirent64_t *)bp;
2593 2593 ssize_t oresid; /* save a copy for testing later */
2594 2594 ssize_t uresid;
2595 2595
2596 2596 oresid = uiop->uio_resid;
2597 2597
2598 2598 /* clear out the dirent buffer */
2599 2599 bzero(bp, sizeof (bp));
2600 2600
2601 2601 /*
2602 2602 * Satisfy user request
2603 2603 */
2604 2604 while ((uresid = uiop->uio_resid) > 0) {
2605 2605 int dirindex;
2606 2606 off_t uoffset;
2607 2607 int reclen;
2608 2608 int error;
2609 2609
2610 2610 uoffset = uiop->uio_offset;
2611 2611 dirindex = (uoffset / LXPR_SDSIZE) - 2;
2612 2612
2613 2613 if (uoffset == 0) {
2614 2614
2615 2615 dirent->d_ino = lxpnp->lxpr_ino;
2616 2616 dirent->d_name[0] = '.';
2617 2617 dirent->d_name[1] = '\0';
2618 2618 reclen = DIRENT64_RECLEN(1);
2619 2619
2620 2620 } else if (uoffset == LXPR_SDSIZE) {
2621 2621
2622 2622 dirent->d_ino = lxpr_parentinode(lxpnp);
2623 2623 dirent->d_name[0] = '.';
2624 2624 dirent->d_name[1] = '.';
2625 2625 dirent->d_name[2] = '\0';
2626 2626 reclen = DIRENT64_RECLEN(2);
2627 2627
2628 2628 } else if (dirindex < dirtablen) {
2629 2629 int slen = strlen(dirtab[dirindex].d_name);
2630 2630
2631 2631 dirent->d_ino = lxpr_inode(dirtab[dirindex].d_type,
2632 2632 lxpnp->lxpr_pid, 0);
2633 2633
2634 2634 ASSERT(slen < LXPNSIZ);
2635 2635 (void) strcpy(dirent->d_name, dirtab[dirindex].d_name);
2636 2636 reclen = DIRENT64_RECLEN(slen);
2637 2637
2638 2638 } else {
2639 2639 /* Run out of table entries */
2640 2640 if (eofp) {
2641 2641 *eofp = 1;
2642 2642 }
2643 2643 return (0);
2644 2644 }
2645 2645
2646 2646 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2647 2647 dirent->d_reclen = (ushort_t)reclen;
2648 2648
2649 2649 /*
2650 2650 * if the size of the data to transfer is greater
2651 2651 * that that requested then we can't do it this transfer.
2652 2652 */
2653 2653 if (reclen > uresid) {
2654 2654 /*
2655 2655 * Error if no entries have been returned yet.
2656 2656 */
2657 2657 if (uresid == oresid) {
2658 2658 return (EINVAL);
2659 2659 }
↓ open down ↓ |
2659 lines elided |
↑ open up ↑ |
2660 2660 break;
2661 2661 }
2662 2662
2663 2663 /*
2664 2664 * uiomove() updates both uiop->uio_resid and uiop->uio_offset
2665 2665 * by the same amount. But we want uiop->uio_offset to change
2666 2666 * in increments of LXPR_SDSIZE, which is different from the
2667 2667 * number of bytes being returned to the user. So we set
2668 2668 * uiop->uio_offset separately, ignoring what uiomove() does.
2669 2669 */
2670 - if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop)) {
2670 + if ((error = uiomove((caddr_t)dirent, reclen, UIO_READ,
2671 + uiop)) != 0)
2671 2672 return (error);
2672 - }
2673 2673
2674 2674 uiop->uio_offset = uoffset + LXPR_SDSIZE;
2675 2675 }
2676 2676
2677 2677 /* Have run out of space, but could have just done last table entry */
2678 2678 if (eofp) {
2679 2679 *eofp =
2680 2680 (uiop->uio_offset >= ((dirtablen+2) * LXPR_SDSIZE)) ? 1 : 0;
2681 2681 }
2682 2682 return (0);
2683 2683 }
2684 2684
2685 2685
2686 2686 static int
2687 2687 lxpr_readdir_procdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2688 2688 {
2689 2689 /* bp holds one dirent64 structure */
2690 2690 longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2691 2691 dirent64_t *dirent = (dirent64_t *)bp;
2692 2692 ssize_t oresid; /* save a copy for testing later */
2693 2693 ssize_t uresid;
2694 2694 off_t uoffset;
2695 2695 zoneid_t zoneid;
2696 2696 pid_t pid;
2697 2697 int error;
2698 2698 int ceof;
2699 2699
2700 2700 ASSERT(lxpnp->lxpr_type == LXPR_PROCDIR);
2701 2701
2702 2702 oresid = uiop->uio_resid;
2703 2703 zoneid = LXPTOZ(lxpnp)->zone_id;
2704 2704
2705 2705 /*
2706 2706 * We return directory entries in the order: "." and ".." then the
2707 2707 * unique lxproc files, then the directories corresponding to the
2708 2708 * running processes. We have defined this as the ordering because
2709 2709 * it allows us to more easily keep track of where we are betwen calls
2710 2710 * to getdents(). If the number of processes changes between calls
2711 2711 * then we can't lose track of where we are in the lxproc files.
2712 2712 */
2713 2713
2714 2714 /* Do the fixed entries */
2715 2715 error = lxpr_readdir_common(lxpnp, uiop, &ceof, lxpr_dir,
2716 2716 PROCDIRFILES);
2717 2717
2718 2718 /* Finished if we got an error or if we couldn't do all the table */
2719 2719 if (error != 0 || ceof == 0)
2720 2720 return (error);
2721 2721
2722 2722 /* clear out the dirent buffer */
2723 2723 bzero(bp, sizeof (bp));
2724 2724
2725 2725 /* Do the process entries */
2726 2726 while ((uresid = uiop->uio_resid) > 0) {
2727 2727 proc_t *p;
2728 2728 int len;
2729 2729 int reclen;
2730 2730 int i;
2731 2731
2732 2732 uoffset = uiop->uio_offset;
2733 2733
2734 2734 /*
2735 2735 * Stop when entire proc table has been examined.
2736 2736 */
2737 2737 i = (uoffset / LXPR_SDSIZE) - 2 - PROCDIRFILES;
2738 2738 if (i >= v.v_proc) {
2739 2739 /* Run out of table entries */
2740 2740 if (eofp) {
2741 2741 *eofp = 1;
2742 2742 }
2743 2743 return (0);
2744 2744 }
2745 2745 mutex_enter(&pidlock);
2746 2746
2747 2747 /*
2748 2748 * Skip indices for which there is no pid_entry, PIDs for
2749 2749 * which there is no corresponding process, a PID of 0,
2750 2750 * and anything the security policy doesn't allow
2751 2751 * us to look at.
2752 2752 */
2753 2753 if ((p = pid_entry(i)) == NULL || p->p_stat == SIDL ||
2754 2754 p->p_pid == 0 ||
2755 2755 secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
2756 2756 mutex_exit(&pidlock);
2757 2757 goto next;
2758 2758 }
2759 2759 mutex_exit(&pidlock);
2760 2760
2761 2761 /*
2762 2762 * Convert pid to the Linux default of 1 if we're the zone's
2763 2763 * init process, otherwise use the value from the proc
2764 2764 * structure
2765 2765 */
2766 2766 pid = ((p->p_pid != curproc->p_zone->zone_proc_initpid) ?
2767 2767 p->p_pid : 1);
2768 2768
2769 2769 /*
2770 2770 * If this /proc was mounted in the global zone, view
2771 2771 * all procs; otherwise, only view zone member procs.
2772 2772 */
2773 2773 if (zoneid != GLOBAL_ZONEID && p->p_zone->zone_id != zoneid) {
2774 2774 goto next;
2775 2775 }
2776 2776
2777 2777 ASSERT(p->p_stat != 0);
2778 2778
2779 2779 dirent->d_ino = lxpr_inode(LXPR_PIDDIR, pid, 0);
2780 2780 len = snprintf(dirent->d_name, LXPNSIZ, "%d", pid);
2781 2781 ASSERT(len < LXPNSIZ);
2782 2782 reclen = DIRENT64_RECLEN(len);
2783 2783
2784 2784 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2785 2785 dirent->d_reclen = (ushort_t)reclen;
2786 2786
2787 2787 /*
2788 2788 * if the size of the data to transfer is greater
2789 2789 * that that requested then we can't do it this transfer.
2790 2790 */
2791 2791 if (reclen > uresid) {
2792 2792 /*
2793 2793 * Error if no entries have been returned yet.
2794 2794 */
2795 2795 if (uresid == oresid)
2796 2796 return (EINVAL);
2797 2797 break;
↓ open down ↓ |
115 lines elided |
↑ open up ↑ |
2798 2798 }
2799 2799
2800 2800 /*
2801 2801 * uiomove() updates both uiop->uio_resid and uiop->uio_offset
2802 2802 * by the same amount. But we want uiop->uio_offset to change
2803 2803 * in increments of LXPR_SDSIZE, which is different from the
2804 2804 * number of bytes being returned to the user. So we set
2805 2805 * uiop->uio_offset separately, in the increment of this for
2806 2806 * the loop, ignoring what uiomove() does.
2807 2807 */
2808 - if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop))
2808 + if ((error = uiomove((caddr_t)dirent, reclen, UIO_READ,
2809 + uiop)) != 0)
2809 2810 return (error);
2810 2811 next:
2811 2812 uiop->uio_offset = uoffset + LXPR_SDSIZE;
2812 2813 }
2813 2814
2814 2815 if (eofp != NULL) {
2815 2816 *eofp = (uiop->uio_offset >=
2816 2817 ((v.v_proc + PROCDIRFILES + 2) * LXPR_SDSIZE)) ? 1 : 0;
2817 2818 }
2818 2819
2819 2820 return (0);
2820 2821 }
2821 2822
2822 2823 static int
2823 2824 lxpr_readdir_piddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2824 2825 {
2825 2826 proc_t *p;
2826 2827
2827 2828 ASSERT(lxpnp->lxpr_type == LXPR_PIDDIR);
2828 2829
2829 2830 /* can't read its contents if it died */
2830 2831 mutex_enter(&pidlock);
2831 2832
2832 2833 p = prfind((lxpnp->lxpr_pid == 1) ?
2833 2834 curproc->p_zone->zone_proc_initpid : lxpnp->lxpr_pid);
2834 2835
2835 2836 if (p == NULL || p->p_stat == SIDL) {
2836 2837 mutex_exit(&pidlock);
2837 2838 return (ENOENT);
2838 2839 }
2839 2840 mutex_exit(&pidlock);
2840 2841
2841 2842 return (lxpr_readdir_common(lxpnp, uiop, eofp, piddir, PIDDIRFILES));
2842 2843 }
2843 2844
2844 2845 static int
2845 2846 lxpr_readdir_netdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2846 2847 {
2847 2848 ASSERT(lxpnp->lxpr_type == LXPR_NETDIR);
2848 2849 return (lxpr_readdir_common(lxpnp, uiop, eofp, netdir, NETDIRFILES));
2849 2850 }
2850 2851
2851 2852 static int
2852 2853 lxpr_readdir_fddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2853 2854 {
2854 2855 /* bp holds one dirent64 structure */
2855 2856 longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2856 2857 dirent64_t *dirent = (dirent64_t *)bp;
2857 2858 ssize_t oresid; /* save a copy for testing later */
2858 2859 ssize_t uresid;
2859 2860 off_t uoffset;
2860 2861 int error;
2861 2862 int ceof;
2862 2863 proc_t *p;
2863 2864 int fddirsize;
2864 2865 uf_info_t *fip;
2865 2866
2866 2867 ASSERT(lxpnp->lxpr_type == LXPR_PID_FDDIR);
2867 2868
2868 2869 oresid = uiop->uio_resid;
2869 2870
2870 2871 /* can't read its contents if it died */
2871 2872 p = lxpr_lock(lxpnp->lxpr_pid);
2872 2873 if (p == NULL)
2873 2874 return (ENOENT);
2874 2875
2875 2876 /* Get open file info */
2876 2877 fip = (&(p)->p_user.u_finfo);
2877 2878
2878 2879 if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas)) {
2879 2880 fddirsize = 0;
2880 2881 } else {
2881 2882 fddirsize = fip->fi_nfiles;
2882 2883 }
2883 2884
2884 2885 mutex_enter(&fip->fi_lock);
2885 2886 lxpr_unlock(p);
2886 2887
2887 2888 /* Do the fixed entries (in this case just "." & "..") */
2888 2889 error = lxpr_readdir_common(lxpnp, uiop, &ceof, 0, 0);
2889 2890
2890 2891 /* Finished if we got an error or if we couldn't do all the table */
2891 2892 if (error != 0 || ceof == 0)
2892 2893 return (error);
2893 2894
2894 2895 /* clear out the dirent buffer */
2895 2896 bzero(bp, sizeof (bp));
2896 2897
2897 2898 /*
2898 2899 * Loop until user's request is satisfied or until
2899 2900 * all file descriptors have been examined.
2900 2901 */
2901 2902 for (; (uresid = uiop->uio_resid) > 0;
2902 2903 uiop->uio_offset = uoffset + LXPR_SDSIZE) {
2903 2904 int reclen;
2904 2905 int fd;
2905 2906 int len;
2906 2907
2907 2908 uoffset = uiop->uio_offset;
2908 2909
2909 2910 /*
2910 2911 * Stop at the end of the fd list
2911 2912 */
2912 2913 fd = (uoffset / LXPR_SDSIZE) - 2;
2913 2914 if (fd >= fddirsize) {
2914 2915 if (eofp) {
2915 2916 *eofp = 1;
2916 2917 }
2917 2918 goto out;
2918 2919 }
2919 2920
2920 2921 if (fip->fi_list[fd].uf_file == NULL)
2921 2922 continue;
2922 2923
2923 2924 dirent->d_ino = lxpr_inode(LXPR_PID_FD_FD, lxpnp->lxpr_pid, fd);
2924 2925 len = snprintf(dirent->d_name, LXPNSIZ, "%d", fd);
2925 2926 ASSERT(len < LXPNSIZ);
2926 2927 reclen = DIRENT64_RECLEN(len);
2927 2928
2928 2929 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2929 2930 dirent->d_reclen = (ushort_t)reclen;
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
2930 2931
2931 2932 if (reclen > uresid) {
2932 2933 /*
2933 2934 * Error if no entries have been returned yet.
2934 2935 */
2935 2936 if (uresid == oresid)
2936 2937 error = EINVAL;
2937 2938 goto out;
2938 2939 }
2939 2940
2940 - if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop))
2941 + if ((error = uiomove((caddr_t)dirent, reclen, UIO_READ,
2942 + uiop)) != 0)
2941 2943 goto out;
2942 2944 }
2943 2945
2944 2946 if (eofp != NULL) {
2945 2947 *eofp =
2946 2948 (uiop->uio_offset >= ((fddirsize+2) * LXPR_SDSIZE)) ? 1 : 0;
2947 2949 }
2948 2950
2949 2951 out:
2950 2952 mutex_exit(&fip->fi_lock);
2951 2953 return (error);
2952 2954 }
2953 2955
2954 2956
2955 2957 /*
2956 2958 * lxpr_readlink(): Vnode operation for VOP_READLINK()
2957 2959 */
2958 2960 /* ARGSUSED */
2959 2961 static int
2960 2962 lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
2961 2963 {
2962 2964 char bp[MAXPATHLEN + 1];
2963 2965 size_t buflen = sizeof (bp);
2964 2966 lxpr_node_t *lxpnp = VTOLXP(vp);
2965 2967 vnode_t *rvp = lxpnp->lxpr_realvp;
2966 2968 pid_t pid;
2967 2969 int error = 0;
2968 2970
2969 2971 /* must be a symbolic link file */
2970 2972 if (vp->v_type != VLNK)
2971 2973 return (EINVAL);
2972 2974
2973 2975 /* Try to produce a symlink name for anything that has a realvp */
2974 2976 if (rvp != NULL) {
2975 2977 if ((error = lxpr_access(vp, VREAD, 0, CRED(), ct)) != 0)
2976 2978 return (error);
2977 2979 if ((error = vnodetopath(NULL, rvp, bp, buflen, CRED())) != 0)
2978 2980 return (error);
2979 2981 } else {
2980 2982 switch (lxpnp->lxpr_type) {
2981 2983 case LXPR_SELF:
2982 2984 /*
2983 2985 * Convert pid to the Linux default of 1 if we're the
2984 2986 * zone's init process
2985 2987 */
2986 2988 pid = ((curproc->p_pid !=
2987 2989 curproc->p_zone->zone_proc_initpid)
2988 2990 ? curproc->p_pid : 1);
2989 2991
2990 2992 /*
2991 2993 * Don't need to check result as every possible int
2992 2994 * will fit within MAXPATHLEN bytes.
2993 2995 */
2994 2996 (void) snprintf(bp, buflen, "%d", pid);
2995 2997 break;
2996 2998 case LXPR_PID_CURDIR:
2997 2999 case LXPR_PID_ROOTDIR:
2998 3000 case LXPR_PID_EXE:
2999 3001 return (EACCES);
3000 3002 default:
3001 3003 /*
3002 3004 * Need to return error so that nothing thinks
3003 3005 * that the symlink is empty and hence "."
3004 3006 */
3005 3007 return (EINVAL);
3006 3008 }
3007 3009 }
3008 3010
3009 3011 /* copy the link data to user space */
3010 3012 return (uiomove(bp, strlen(bp), UIO_READ, uiop));
3011 3013 }
3012 3014
3013 3015 /*
3014 3016 * lxpr_inactive(): Vnode operation for VOP_INACTIVE()
3015 3017 * Vnode is no longer referenced, deallocate the file
3016 3018 * and all its resources.
3017 3019 */
3018 3020 /* ARGSUSED */
3019 3021 static void
3020 3022 lxpr_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
3021 3023 {
3022 3024 lxpr_freenode(VTOLXP(vp));
3023 3025 }
3024 3026
3025 3027 /*
3026 3028 * lxpr_sync(): Vnode operation for VOP_SYNC()
3027 3029 */
3028 3030 static int
3029 3031 lxpr_sync()
3030 3032 {
3031 3033 /*
3032 3034 * Nothing to sync but this function must never fail
3033 3035 */
3034 3036 return (0);
3035 3037 }
3036 3038
3037 3039 /*
3038 3040 * lxpr_cmp(): Vnode operation for VOP_CMP()
3039 3041 */
3040 3042 static int
3041 3043 lxpr_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
3042 3044 {
3043 3045 vnode_t *rvp;
3044 3046
3045 3047 while (vn_matchops(vp1, lxpr_vnodeops) &&
3046 3048 (rvp = VTOLXP(vp1)->lxpr_realvp) != NULL) {
3047 3049 vp1 = rvp;
3048 3050 }
3049 3051
3050 3052 while (vn_matchops(vp2, lxpr_vnodeops) &&
3051 3053 (rvp = VTOLXP(vp2)->lxpr_realvp) != NULL) {
3052 3054 vp2 = rvp;
3053 3055 }
3054 3056
3055 3057 if (vn_matchops(vp1, lxpr_vnodeops) || vn_matchops(vp2, lxpr_vnodeops))
3056 3058 return (vp1 == vp2);
3057 3059
3058 3060 return (VOP_CMP(vp1, vp2, ct));
3059 3061 }
3060 3062
3061 3063 /*
3062 3064 * lxpr_realvp(): Vnode operation for VOP_REALVP()
3063 3065 */
3064 3066 static int
3065 3067 lxpr_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
3066 3068 {
3067 3069 vnode_t *rvp;
3068 3070
3069 3071 if ((rvp = VTOLXP(vp)->lxpr_realvp) != NULL) {
3070 3072 vp = rvp;
3071 3073 if (VOP_REALVP(vp, &rvp, ct) == 0)
3072 3074 vp = rvp;
3073 3075 }
3074 3076
3075 3077 *vpp = vp;
3076 3078 return (0);
3077 3079 }
↓ open down ↓ |
127 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX