xref: /illumos-gate/usr/src/lib/libproc/common/pr_stat.c (revision 27954b0d964ffcb749cf19296906e7fecdf3da1b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/isa_defs.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/fcntl.h>
35 #include <sys/sysmacros.h>
36 #include "libproc.h"
37 
38 #ifdef _LP64
39 /*
40  * in case of 64-bit *stat() and *stat64 library call and 32-bit subject
41  * process convert 64-bit struct stat/stat64 into 32-bit struct stat64
42  */
43 static void
44 stat64_32_to_n(struct stat64_32 *src, struct stat *dest)
45 {
46 	(void) memset(dest, 0, sizeof (*dest));
47 	dest->st_dev = DEVEXPL(src->st_dev);
48 	dest->st_ino = (ino_t)src->st_ino;
49 	dest->st_mode = (mode_t)src->st_mode;
50 	dest->st_nlink = (nlink_t)src->st_nlink;
51 	dest->st_uid = (uid_t)src->st_uid;
52 	dest->st_gid = (gid_t)src->st_gid;
53 	dest->st_rdev = DEVEXPL(src->st_rdev);
54 	dest->st_size = (off_t)src->st_size;
55 	TIMESPEC32_TO_TIMESPEC(&dest->st_atim, &src->st_atim);
56 	TIMESPEC32_TO_TIMESPEC(&dest->st_mtim, &src->st_mtim);
57 	TIMESPEC32_TO_TIMESPEC(&dest->st_ctim, &src->st_ctim);
58 	dest->st_blksize = (blksize_t)src->st_blksize;
59 	dest->st_blocks = (blkcnt_t)src->st_blocks;
60 	(void) memcpy(dest->st_fstype, src->st_fstype,
61 	    sizeof (dest->st_fstype));
62 }
63 #endif	/* _LP64 */
64 
65 /*
66  * stat() system call -- executed by subject process
67  */
68 int
69 pr_stat(struct ps_prochandle *Pr, const char *path, struct stat *buf)
70 {
71 	sysret_t rval;			/* return value from stat() */
72 	argdes_t argd[4];		/* arg descriptors for fstatat() */
73 	argdes_t *adp = &argd[0];	/* first argument */
74 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
75 	int error;
76 #ifdef _LP64
77 	struct stat64_32 statb64_32;
78 #endif	/* _LP64 */
79 
80 	if (Pr == NULL)		/* no subject process */
81 		return (stat(path, buf));
82 
83 	if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
84 		/* 64-bit process controls 32-bit subject process */
85 		syscall = SYS_fstatat64;
86 	} else {
87 		syscall = SYS_fstatat;
88 	}
89 
90 	adp->arg_value = AT_FDCWD;
91 	adp->arg_object = NULL;
92 	adp->arg_type = AT_BYVAL;
93 	adp->arg_inout = AI_INPUT;
94 	adp->arg_size = 0;
95 	adp++;			/* move to path argument */
96 
97 	adp->arg_value = 0;
98 	adp->arg_object = (void *)path;
99 	adp->arg_type = AT_BYREF;
100 	adp->arg_inout = AI_INPUT;
101 	adp->arg_size = strlen(path) + 1;
102 	adp++;			/* move to buffer argument */
103 
104 	adp->arg_value = 0;
105 	adp->arg_type = AT_BYREF;
106 	adp->arg_inout = AI_OUTPUT;
107 #ifdef _LP64
108 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
109 		adp->arg_object = &statb64_32;
110 		adp->arg_size = sizeof (statb64_32);
111 	} else {
112 		adp->arg_object = buf;
113 		adp->arg_size = sizeof (*buf);
114 	}
115 #else	/* _LP64 */
116 	adp->arg_object = buf;
117 	adp->arg_size = sizeof (*buf);
118 #endif	/* _LP64 */
119 	adp++;			/* move to flags argument */
120 
121 	adp->arg_value = 0;
122 	adp->arg_object = NULL;
123 	adp->arg_type = AT_BYVAL;
124 	adp->arg_inout = AI_INPUT;
125 	adp->arg_size = 0;
126 
127 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
128 
129 	if (error) {
130 		errno = (error > 0)? error : ENOSYS;
131 		return (-1);
132 	}
133 #ifdef _LP64
134 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
135 		stat64_32_to_n(&statb64_32, buf);
136 #endif	/* _LP64 */
137 	return (0);
138 }
139 
140 /*
141  * lstat() system call -- executed by subject process
142  */
143 int
144 pr_lstat(struct ps_prochandle *Pr, const char *path, struct stat *buf)
145 {
146 	sysret_t rval;			/* return value from stat() */
147 	argdes_t argd[4];		/* arg descriptors for fstatat() */
148 	argdes_t *adp = &argd[0];	/* first argument */
149 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
150 	int error;
151 #ifdef _LP64
152 	struct stat64_32 statb64_32;
153 #endif	/* _LP64 */
154 
155 	if (Pr == NULL)		/* no subject process */
156 		return (lstat(path, buf));
157 
158 	if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
159 		/* 64-bit process controls 32-bit subject process */
160 		syscall = SYS_fstatat64;
161 	} else {
162 		syscall = SYS_fstatat;
163 	}
164 
165 	adp->arg_value = AT_FDCWD;
166 	adp->arg_object = NULL;
167 	adp->arg_type = AT_BYVAL;
168 	adp->arg_inout = AI_INPUT;
169 	adp->arg_size = 0;
170 	adp++;			/* move to path argument */
171 
172 	adp->arg_value = 0;
173 	adp->arg_object = (void *)path;
174 	adp->arg_type = AT_BYREF;
175 	adp->arg_inout = AI_INPUT;
176 	adp->arg_size = strlen(path) + 1;
177 	adp++;			/* move to buffer argument */
178 
179 	adp->arg_value = 0;
180 	adp->arg_type = AT_BYREF;
181 	adp->arg_inout = AI_OUTPUT;
182 #ifdef _LP64
183 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
184 		adp->arg_object = &statb64_32;
185 		adp->arg_size = sizeof (statb64_32);
186 	} else {
187 		adp->arg_object = buf;
188 		adp->arg_size = sizeof (*buf);
189 	}
190 #else	/* _LP64 */
191 	adp->arg_object = buf;
192 	adp->arg_size = sizeof (*buf);
193 #endif	/* _LP64 */
194 	adp++;			/* move to flags argument */
195 
196 	adp->arg_value = AT_SYMLINK_NOFOLLOW;
197 	adp->arg_object = NULL;
198 	adp->arg_type = AT_BYVAL;
199 	adp->arg_inout = AI_INPUT;
200 	adp->arg_size = 0;
201 
202 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
203 
204 	if (error) {
205 		errno = (error > 0)? error : ENOSYS;
206 		return (-1);
207 	}
208 #ifdef _LP64
209 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
210 		stat64_32_to_n(&statb64_32, buf);
211 #endif	/* _LP64 */
212 	return (0);
213 }
214 
215 /*
216  * fstat() system call -- executed by subject process
217  */
218 int
219 pr_fstat(struct ps_prochandle *Pr, int fd, struct stat *buf)
220 {
221 	sysret_t rval;			/* return value from stat() */
222 	argdes_t argd[4];		/* arg descriptors for fstatat() */
223 	argdes_t *adp = &argd[0];	/* first argument */
224 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
225 	int error;
226 #ifdef _LP64
227 	struct stat64_32 statb64_32;
228 #endif	/* _LP64 */
229 
230 	if (Pr == NULL)		/* no subject process */
231 		return (fstat(fd, buf));
232 
233 	if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
234 		/* 64-bit process controls 32-bit subject process */
235 		syscall = SYS_fstatat64;
236 	} else {
237 		syscall = SYS_fstatat;
238 	}
239 
240 	adp->arg_value = fd;
241 	adp->arg_object = NULL;
242 	adp->arg_type = AT_BYVAL;
243 	adp->arg_inout = AI_INPUT;
244 	adp->arg_size = 0;
245 	adp++;			/* move to path argument */
246 
247 	adp->arg_value = 0;
248 	adp->arg_object = NULL;
249 	adp->arg_type = AT_BYVAL;
250 	adp->arg_inout = AI_INPUT;
251 	adp->arg_size = 0;
252 	adp++;			/* move to buffer argument */
253 
254 	adp->arg_value = 0;
255 	adp->arg_type = AT_BYREF;
256 	adp->arg_inout = AI_OUTPUT;
257 #ifdef _LP64
258 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
259 		adp->arg_object = &statb64_32;
260 		adp->arg_size = sizeof (statb64_32);
261 	} else {
262 		adp->arg_object = buf;
263 		adp->arg_size = sizeof (*buf);
264 	}
265 #else	/* _LP64 */
266 	adp->arg_object = buf;
267 	adp->arg_size = sizeof (*buf);
268 #endif	/* _LP64 */
269 	adp++;			/* move to flags argument */
270 
271 	adp->arg_value = 0;
272 	adp->arg_object = NULL;
273 	adp->arg_type = AT_BYVAL;
274 	adp->arg_inout = AI_INPUT;
275 	adp->arg_size = 0;
276 
277 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
278 
279 	if (error) {
280 		errno = (error > 0)? error : ENOSYS;
281 		return (-1);
282 	}
283 #ifdef _LP64
284 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
285 		stat64_32_to_n(&statb64_32, buf);
286 #endif	/* _LP64 */
287 	return (0);
288 }
289 
290 /*
291  * stat64() system call -- executed by subject process
292  */
293 int
294 pr_stat64(struct ps_prochandle *Pr, const char *path, struct stat64 *buf)
295 {
296 	sysret_t rval;			/* return value from stat() */
297 	argdes_t argd[4];		/* arg descriptors for fstatat() */
298 	argdes_t *adp = &argd[0];	/* first argument */
299 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
300 	int error;
301 #ifdef _LP64
302 	struct stat64_32 statb64_32;
303 #endif	/* _LP64 */
304 
305 	if (Pr == NULL)		/* no subject process */
306 		return (stat64(path, buf));
307 
308 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
309 		/*
310 		 * 32-bit native and
311 		 * 64-bit process controls 32-bit subject process
312 		 */
313 		syscall = SYS_fstatat64;
314 	} else {
315 		/* 64-bit native */
316 		syscall = SYS_fstatat;
317 	}
318 
319 	adp->arg_value = AT_FDCWD;
320 	adp->arg_object = NULL;
321 	adp->arg_type = AT_BYVAL;
322 	adp->arg_inout = AI_INPUT;
323 	adp->arg_size = 0;
324 	adp++;			/* move to path argument */
325 
326 	adp->arg_value = 0;
327 	adp->arg_object = (void *)path;
328 	adp->arg_type = AT_BYREF;
329 	adp->arg_inout = AI_INPUT;
330 	adp->arg_size = strlen(path) + 1;
331 	adp++;			/* move to buffer argument */
332 
333 	adp->arg_value = 0;
334 	adp->arg_type = AT_BYREF;
335 	adp->arg_inout = AI_OUTPUT;
336 #ifdef _LP64
337 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
338 		adp->arg_object = &statb64_32;
339 		adp->arg_size = sizeof (statb64_32);
340 	} else {
341 		adp->arg_object = buf;
342 		adp->arg_size = sizeof (*buf);
343 	}
344 #else	/* _LP64 */
345 	adp->arg_object = buf;
346 	adp->arg_size = sizeof (*buf);
347 #endif	/* _LP64 */
348 	adp++;			/* move to flags argument */
349 
350 	adp->arg_value = 0;
351 	adp->arg_object = NULL;
352 	adp->arg_type = AT_BYVAL;
353 	adp->arg_inout = AI_INPUT;
354 	adp->arg_size = 0;
355 
356 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
357 
358 	if (error) {
359 		errno = (error > 0)? error : ENOSYS;
360 		return (-1);
361 	}
362 #ifdef _LP64
363 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
364 		stat64_32_to_n(&statb64_32, (struct stat *)buf);
365 #endif	/* _LP64 */
366 	return (0);
367 }
368 
369 /*
370  * lstat64() system call -- executed by subject process
371  */
372 int
373 pr_lstat64(struct ps_prochandle *Pr, const char *path, struct stat64 *buf)
374 {
375 	sysret_t rval;			/* return value from stat() */
376 	argdes_t argd[4];		/* arg descriptors for fstatat() */
377 	argdes_t *adp = &argd[0];	/* first argument */
378 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
379 	int error;
380 #ifdef _LP64
381 	struct stat64_32 statb64_32;
382 #endif	/* _LP64 */
383 
384 	if (Pr == NULL)		/* no subject process */
385 		return (lstat64(path, buf));
386 
387 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
388 		/*
389 		 * 32-bit native and
390 		 * 64-bit process controls 32-bit subject process
391 		 */
392 		syscall = SYS_fstatat64;
393 	} else {
394 		/* 64-bit native */
395 		syscall = SYS_fstatat;
396 	}
397 
398 	adp->arg_value = AT_FDCWD;
399 	adp->arg_object = NULL;
400 	adp->arg_type = AT_BYVAL;
401 	adp->arg_inout = AI_INPUT;
402 	adp->arg_size = 0;
403 	adp++;			/* move to path argument */
404 
405 	adp->arg_value = 0;
406 	adp->arg_object = (void *)path;
407 	adp->arg_type = AT_BYREF;
408 	adp->arg_inout = AI_INPUT;
409 	adp->arg_size = strlen(path) + 1;
410 	adp++;			/* move to buffer argument */
411 
412 	adp->arg_value = 0;
413 	adp->arg_type = AT_BYREF;
414 	adp->arg_inout = AI_OUTPUT;
415 #ifdef _LP64
416 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
417 		adp->arg_object = &statb64_32;
418 		adp->arg_size = sizeof (statb64_32);
419 	} else {
420 		adp->arg_object = buf;
421 		adp->arg_size = sizeof (*buf);
422 	}
423 #else	/* _LP64 */
424 	adp->arg_object = buf;
425 	adp->arg_size = sizeof (*buf);
426 #endif	/* _LP64 */
427 	adp++;			/* move to flags argument */
428 
429 	adp->arg_value = AT_SYMLINK_NOFOLLOW;
430 	adp->arg_object = NULL;
431 	adp->arg_type = AT_BYVAL;
432 	adp->arg_inout = AI_INPUT;
433 	adp->arg_size = 0;
434 
435 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
436 
437 	if (error) {
438 		errno = (error > 0)? error : ENOSYS;
439 		return (-1);
440 	}
441 #ifdef _LP64
442 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
443 		stat64_32_to_n(&statb64_32, (struct stat *)buf);
444 #endif	/* _LP64 */
445 	return (0);
446 }
447 
448 /*
449  * fstat64() system call -- executed by subject process
450  */
451 int
452 pr_fstat64(struct ps_prochandle *Pr, int fd, struct stat64 *buf)
453 {
454 	sysret_t rval;			/* return value from stat() */
455 	argdes_t argd[4];		/* arg descriptors for fstatat() */
456 	argdes_t *adp = &argd[0];	/* first argument */
457 	int syscall;			/* SYS_fstatat or SYS_fstatat64 */
458 	int error;
459 #ifdef _LP64
460 	struct stat64_32 statb64_32;
461 #endif	/* _LP64 */
462 
463 	if (Pr == NULL)		/* no subject process */
464 		return (fstat64(fd, buf));
465 
466 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
467 		/*
468 		 * 32-bit native and
469 		 * 64-bit process controls 32-bit subject process
470 		 */
471 		syscall = SYS_fstatat64;
472 	} else {
473 		/* 64-bit native */
474 		syscall = SYS_fstatat;
475 	}
476 
477 	adp->arg_value = fd;
478 	adp->arg_object = NULL;
479 	adp->arg_type = AT_BYVAL;
480 	adp->arg_inout = AI_INPUT;
481 	adp->arg_size = 0;
482 	adp++;			/* move to path argument */
483 
484 	adp->arg_value = 0;
485 	adp->arg_object = NULL;
486 	adp->arg_type = AT_BYVAL;
487 	adp->arg_inout = AI_INPUT;
488 	adp->arg_size = 0;
489 	adp++;			/* move to buffer argument */
490 
491 	adp->arg_value = 0;
492 	adp->arg_type = AT_BYREF;
493 	adp->arg_inout = AI_OUTPUT;
494 #ifdef _LP64
495 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
496 		adp->arg_object = &statb64_32;
497 		adp->arg_size = sizeof (statb64_32);
498 	} else {
499 		adp->arg_object = buf;
500 		adp->arg_size = sizeof (*buf);
501 	}
502 #else	/* _LP64 */
503 	adp->arg_object = buf;
504 	adp->arg_size = sizeof (*buf);
505 #endif	/* _LP64 */
506 	adp++;			/* move to flags argument */
507 
508 	adp->arg_value = 0;
509 	adp->arg_object = NULL;
510 	adp->arg_type = AT_BYVAL;
511 	adp->arg_inout = AI_INPUT;
512 	adp->arg_size = 0;
513 
514 	error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
515 
516 	if (error) {
517 		errno = (error > 0)? error : ENOSYS;
518 		return (-1);
519 	}
520 #ifdef _LP64
521 	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
522 		stat64_32_to_n(&statb64_32, (struct stat *)buf);
523 #endif	/* _LP64 */
524 	return (0);
525 }
526