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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
36 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/sysmacros.h>
47 extern int gmatch(const char *s
, const char *p
);
49 #pragma init(__mpssmain)
51 static const char *mpssident
= "mpss.so.1";
53 /* environment variables */
55 #define ENV_MPSSCFGFILE "MPSSCFGFILE"
56 #define ENV_MPSSSTACK "MPSSSTACK"
57 #define ENV_MPSSHEAP "MPSSHEAP"
58 #define ENV_MPSSERRFILE "MPSSERRFILE"
65 #define DEF_MPSSCFGFILE "/etc/mpss.conf"
66 #define MAXLINELEN MAXPATHLEN + 64
67 #define CFGDELIMITER ':'
68 #define ARGDELIMITER ' '
71 * avoid malloc which causes certain applications to crash
73 static char lbuf
[MAXLINELEN
];
74 static char pbuf
[MAXPATHLEN
];
77 #define ENV_MPSSDEBUG "MPSSDEBUG"
78 #define MPSSPRINT(x, y) if (mpssdebug & x) (void) fprintf y;
82 #define MPSSPRINT(x, y)
85 #if !defined(TEXT_DOMAIN)
86 #define TEXT_DOMAIN "SYS_TEST"
91 mpsserr(FILE *fp
, char *fmt
, ...)
96 (void) vfprintf(fp
, fmt
, ap
);
98 vsyslog(LOG_ERR
, fmt
, ap
);
103 * Return the pointer to the fully-resolved path name of the process's
104 * executable file obtained from the AT_SUN_EXECNAME aux vector entry.
109 const char *execname
= NULL
;
113 * The first time through, read the initial aux vector that was
114 * passed to the process at exec(2). Only do this once.
116 int fd
= open("/proc/self/auxv", O_RDONLY
);
119 while (read(fd
, &auxb
, sizeof (auxv_t
)) == sizeof (auxv_t
)) {
120 if (auxb
.a_type
== AT_SUN_EXECNAME
) {
121 execname
= auxb
.a_un
.a_ptr
;
136 sz
= strtoll(szstr
, &endptr
, 0);
138 while (c
= *endptr
++) {
163 #define PGSZELEM (8 * sizeof (void *))
164 static size_t pgsz
[PGSZELEM
];
175 for (i
= 0; i
< nelem
; i
++) {
186 nelem
= getpagesizes(NULL
, 0);
191 if (nelem
> PGSZELEM
)
194 (void) getpagesizes(pgsz
, nelem
);
196 pgsz
[nelem
] = 0x800000;
203 pgszset(size_t sz
, uint_t flags
)
205 struct memcntl_mha mpss
;
208 mpss
.mha_cmd
= (flags
== MPSSHEAP
) ?
209 MHA_MAPSIZE_BSSBRK
: MHA_MAPSIZE_STACK
;
210 mpss
.mha_pagesize
= sz
;
212 rc
= memcntl(NULL
, 0, MC_HAT_ADVISE
, (caddr_t
)&mpss
, 0, 0);
218 * check if exec name matches cfgname found in mpss cfg file.
221 fnmatch(const char *execname
, char *cfgname
, char *cwd
)
226 /* cfgname should not have a '/' unless it begins with one */
227 if (cfgname
[0] == '/') {
229 * if execname does not begin with a '/', prepend the
232 if (execname
[0] != '/') {
233 ename
= (const char *)strcat(cwd
, execname
);
236 } else { /* simple cfg name */
237 if (ename
= strrchr(execname
, '/'))
238 /* execname is a path name - get the base name */
243 rc
= gmatch(ename
, cfgname
);
244 MPSSPRINT(2, (stderr
, "gmatch: %s %s %s %d\n",
245 cfgname
, ename
, execname
, rc
));
251 * Check if string matches any of exec arguments.
254 argmatch(char *str
, FILE *errfp
)
262 fd
= open("/proc/self/psinfo", O_RDONLY
);
265 if (read(fd
, &pi
, sizeof (pi
)) == sizeof (pi
)) {
266 argv
= (char **)pi
.pr_argv
;
268 MPSSPRINT(2, (stderr
, "argmatch: %s ", str
));
269 for (arg
= 1; arg
< pi
.pr_argc
; arg
++, argv
++) {
270 if (rc
= gmatch(*argv
, str
)) {
271 MPSSPRINT(2, (stderr
, "%s ", *argv
));
275 MPSSPRINT(2, (stderr
, "%d\n", rc
));
277 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
278 "%s: /proc/self/psinfo read failed [%s]\n"),
279 mpssident
, strerror(errno
));
283 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
284 "%s: /proc/self/psinfo open failed [%s]\n"),
285 mpssident
, strerror(errno
));
295 while ((c
= *str
) == '\n' || c
== ' ' || c
== '\t')
297 return (*str
== '\0');
303 static size_t heapsz
= (size_t)-1, stacksz
= (size_t)-1, sz
;
304 char *cfgfile
, *errfile
;
305 const char *execname
;
308 FILE *fp
= NULL
, *errfp
= NULL
;
309 char *tok
, *tokheap
= NULL
, *tokstack
= NULL
, *tokarg
;
310 char *str
, *envheap
, *envstack
;
315 * If a private error file is indicated then set the locale
316 * for error messages for the duration of this routine.
317 * Error messages destined for syslog should not be translated
318 * and thus come from the default C locale.
320 if ((errfile
= getenv(ENV_MPSSERRFILE
)) != NULL
) {
321 errfp
= fopen(errfile
, "aF");
323 locale
= setlocale(LC_MESSAGES
, "");
325 mpsserr(NULL
, dgettext(TEXT_DOMAIN
,
326 "%s: cannot open error file: %s [%s]\n"),
327 mpssident
, errfile
, strerror(errno
));
332 if (str
= getenv(ENV_MPSSDEBUG
))
333 mpssdebug
= atosz(str
);
338 if (envstack
= getenv(ENV_MPSSSTACK
)) {
339 sz
= atosz(envstack
);
343 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
344 "%s: invalid stack page size specified:"
346 mpssident
, envstack
);
349 if (envheap
= getenv(ENV_MPSSHEAP
)) {
354 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
355 "%s: invalid heap page size specified:"
361 * Open specified cfg file or default one.
363 if (cfgfile
= getenv(ENV_MPSSCFGFILE
)) {
364 fp
= fopen(cfgfile
, "rF");
366 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
367 "%s: cannot open configuration file: %s [%s]\n"),
368 mpssident
, cfgfile
, strerror(errno
));
371 cfgfile
= DEF_MPSSCFGFILE
;
372 fp
= fopen(cfgfile
, "rF");
375 execname
= mygetexecname();
379 cwd
= getcwd(pbuf
, MAXPATHLEN
);
383 cwd
= strcat(cwd
, "/");
384 cwdlen
= strlen(cwd
);
386 while (fgets(lbuf
, MAXLINELEN
, fp
)) {
391 * Make sure line wasn't truncated.
393 if (strlen(lbuf
) >= MAXLINELEN
- 1) {
394 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
395 "%s: invalid entry, "
396 "line too long - cfgfile:"
398 mpssident
, cfgfile
, lineno
);
402 * parse right to left in case delimiter is
405 if (!(tokstack
= strrchr(lbuf
, CFGDELIMITER
))) {
406 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
407 "%s: no delimiters specified - cfgfile:"
409 mpssident
, cfgfile
, lineno
);
412 /* found delimiter in lbuf */
414 /* remove for error message */
415 if (str
= strrchr(tokstack
, '\n'))
417 if (!(tokheap
= strrchr(lbuf
, CFGDELIMITER
))) {
418 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
419 "%s: invalid entry, "
420 "missing delimiter - cfgfile: %s,"
422 mpssident
, cfgfile
, lineno
);
427 /* exec-args is optional */
428 if (tokarg
= strrchr(lbuf
, ARGDELIMITER
)) {
434 if (!fnmatch(execname
, tok
, cwd
)) {
435 tokheap
= tokstack
= tokarg
= NULL
;
442 !argmatch(tokarg
, errfp
)) {
443 tokheap
= tokstack
= tokarg
= NULL
;
449 if (empty(tokheap
)) {
450 /* empty cfg entry */
457 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
458 "%s: invalid heap page size"
459 " specified (%s) for %s - "
460 "cfgfile: %s, line: %d\n"),
469 if (empty(tokstack
)) {
470 stacksz
= (size_t)-1;
473 sz
= atosz(tokstack
);
477 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
478 "%s: invalid stack page size"
479 " specified (%s) for %s - "
480 "cfgfile: %s, line: %d\n"),
482 execname
, cfgfile
, lineno
);
483 stacksz
= (size_t)-1;
491 if ((heapsz
!= (size_t)-1) && (pgszset(heapsz
, MPSSHEAP
) < 0))
492 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
493 "%s: memcntl() failed [%s]: heap page size (%s)"
494 " for %s not set\n"),
495 mpssident
, strerror(errno
), (tokheap
) ? tokheap
: envheap
,
497 if ((stacksz
!= (size_t)-1) && (pgszset(stacksz
, MPSSSTACK
) < 0))
498 mpsserr(errfp
, dgettext(TEXT_DOMAIN
,
499 "%s: memcntl() failed [%s]: stack page size (%s)"
500 " for %s not set\n"),
501 mpssident
, strerror(errno
), (tokstack
) ? tokstack
: envstack
,
505 (void) fclose(errfp
);
506 (void) setlocale(LC_MESSAGES
, locale
);
508 /* close log file: no-op if nothing logged to syslog */