1211416Skib/*-
2232388Skib * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
3211416Skib * All rights reserved.
4211416Skib *
5211416Skib * Redistribution and use in source and binary forms, with or without
6211416Skib * modification, are permitted provided that the following conditions
7211416Skib * are met:
8211416Skib * 1. Redistributions of source code must retain the above copyright
9211416Skib *    notice, this list of conditions and the following disclaimer.
10211416Skib * 2. Redistributions in binary form must reproduce the above copyright
11211416Skib *    notice, this list of conditions and the following disclaimer in the
12211416Skib *    documentation and/or other materials provided with the distribution.
13211416Skib *
14211416Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15211416Skib * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16211416Skib * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17211416Skib * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18211416Skib * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19211416Skib * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20211416Skib * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21211416Skib * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22211416Skib * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23211416Skib * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24211416Skib *
25211416Skib */
26211416Skib
27211416Skib#include <sys/cdefs.h>
28211416Skib__FBSDID("$FreeBSD$");
29211416Skib
30211416Skib#include "namespace.h"
31211416Skib#include <elf.h>
32211416Skib#include <errno.h>
33211416Skib#include <link.h>
34211416Skib#include <pthread.h>
35211416Skib#include <string.h>
36211416Skib#include "un-namespace.h"
37211416Skib#include "libc_private.h"
38211416Skib
39232388Skibextern char **environ;
40232388Skibextern int _DYNAMIC;
41232388Skib#pragma weak _DYNAMIC
42211416Skib
43232388Skibvoid *__elf_aux_vector;
44232388Skibstatic pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
45232388Skib
46232388Skibstatic void
47232388Skibinit_aux_vector_once(void)
48232388Skib{
49232388Skib	Elf_Addr *sp;
50232388Skib
51232388Skib	sp = (Elf_Addr *)environ;
52232388Skib	while (*sp++ != 0)
53232388Skib		;
54232388Skib	__elf_aux_vector = (Elf_Auxinfo *)sp;
55232388Skib}
56232388Skib
57232388Skibvoid
58232388Skib__init_elf_aux_vector(void)
59232388Skib{
60232388Skib
61232388Skib	if (&_DYNAMIC != NULL)
62232388Skib		return;
63232388Skib	_once(&aux_vector_once, init_aux_vector_once);
64232388Skib}
65232388Skib
66211416Skibstatic pthread_once_t aux_once = PTHREAD_ONCE_INIT;
67211416Skibstatic int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
68211416Skibstatic char *canary, *pagesizes;
69240819Skibstatic void *timekeep;
70211416Skib
71211416Skibstatic void
72211416Skibinit_aux(void)
73211416Skib{
74211416Skib	Elf_Auxinfo *aux;
75211416Skib
76211416Skib	for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
77211416Skib		switch (aux->a_type) {
78211416Skib		case AT_CANARY:
79211416Skib			canary = (char *)(aux->a_un.a_ptr);
80211416Skib			break;
81211416Skib
82211416Skib		case AT_CANARYLEN:
83211416Skib			canary_len = aux->a_un.a_val;
84211416Skib			break;
85211416Skib
86211416Skib		case AT_PAGESIZES:
87211416Skib			pagesizes = (char *)(aux->a_un.a_ptr);
88211416Skib			break;
89211416Skib
90211416Skib		case AT_PAGESIZESLEN:
91211416Skib			pagesizes_len = aux->a_un.a_val;
92211416Skib			break;
93211416Skib
94211416Skib		case AT_PAGESZ:
95211416Skib			pagesize = aux->a_un.a_val;
96211416Skib			break;
97211416Skib
98211416Skib		case AT_OSRELDATE:
99211416Skib			osreldate = aux->a_un.a_val;
100211416Skib			break;
101211416Skib
102211416Skib		case AT_NCPUS:
103211416Skib			ncpus = aux->a_un.a_val;
104211416Skib			break;
105240819Skib
106240819Skib		case AT_TIMEKEEP:
107240819Skib			timekeep = aux->a_un.a_ptr;
108240819Skib			break;
109211416Skib		}
110211416Skib	}
111211416Skib}
112211416Skib
113211416Skibint
114211416Skib_elf_aux_info(int aux, void *buf, int buflen)
115211416Skib{
116211416Skib	int res;
117211416Skib
118232388Skib	__init_elf_aux_vector();
119211416Skib	if (__elf_aux_vector == NULL)
120211416Skib		return (ENOSYS);
121211416Skib	_once(&aux_once, init_aux);
122211416Skib
123211416Skib	switch (aux) {
124211416Skib	case AT_CANARY:
125211416Skib		if (canary != NULL && canary_len >= buflen) {
126211416Skib			memcpy(buf, canary, buflen);
127211416Skib			memset(canary, 0, canary_len);
128211416Skib			canary = NULL;
129211416Skib			res = 0;
130211416Skib		} else
131211416Skib			res = ENOENT;
132211416Skib		break;
133211416Skib	case AT_PAGESIZES:
134211416Skib		if (pagesizes != NULL && pagesizes_len >= buflen) {
135211416Skib			memcpy(buf, pagesizes, buflen);
136211416Skib			res = 0;
137211416Skib		} else
138211416Skib			res = ENOENT;
139211416Skib		break;
140211416Skib
141211416Skib	case AT_PAGESZ:
142211416Skib		if (buflen == sizeof(int)) {
143211416Skib			if (pagesize != 0) {
144211416Skib				*(int *)buf = pagesize;
145211416Skib				res = 0;
146211416Skib			} else
147211416Skib				res = ENOENT;
148211416Skib		} else
149211416Skib			res = EINVAL;
150211416Skib		break;
151211416Skib	case AT_OSRELDATE:
152211416Skib		if (buflen == sizeof(int)) {
153211416Skib			if (osreldate != 0) {
154211416Skib				*(int *)buf = osreldate;
155211416Skib				res = 0;
156211416Skib			} else
157211416Skib				res = ENOENT;
158211416Skib		} else
159211416Skib			res = EINVAL;
160211416Skib		break;
161211416Skib	case AT_NCPUS:
162211416Skib		if (buflen == sizeof(int)) {
163211416Skib			if (ncpus != 0) {
164211416Skib				*(int *)buf = ncpus;
165211416Skib				res = 0;
166211416Skib			} else
167211416Skib				res = ENOENT;
168211416Skib		} else
169211416Skib			res = EINVAL;
170211416Skib		break;
171240819Skib	case AT_TIMEKEEP:
172240819Skib		if (buflen == sizeof(void *)) {
173240819Skib			if (timekeep != NULL) {
174240819Skib				*(void **)buf = timekeep;
175240819Skib				res = 0;
176240819Skib			} else
177240819Skib				res = ENOENT;
178240819Skib		} else
179240819Skib			res = EINVAL;
180240819Skib		break;
181211416Skib	default:
182211416Skib		res = ENOENT;
183211416Skib		break;
184211416Skib	}
185211416Skib	return (res);
186211416Skib}
187