198a7f915SMatthew Dillon /* 28c10bfcfSMatthew Dillon * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 38c10bfcfSMatthew Dillon * 48c10bfcfSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 58c10bfcfSMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 698a7f915SMatthew Dillon * 798a7f915SMatthew Dillon * Redistribution and use in source and binary forms, with or without 898a7f915SMatthew Dillon * modification, are permitted provided that the following conditions 998a7f915SMatthew Dillon * are met: 108c10bfcfSMatthew Dillon * 1198a7f915SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 1298a7f915SMatthew Dillon * notice, this list of conditions and the following disclaimer. 1398a7f915SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 148c10bfcfSMatthew Dillon * notice, this list of conditions and the following disclaimer in 158c10bfcfSMatthew Dillon * the documentation and/or other materials provided with the 168c10bfcfSMatthew Dillon * distribution. 178c10bfcfSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 188c10bfcfSMatthew Dillon * contributors may be used to endorse or promote products derived 198c10bfcfSMatthew Dillon * from this software without specific, prior written permission. 2098a7f915SMatthew Dillon * 218c10bfcfSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 228c10bfcfSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 238c10bfcfSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 248c10bfcfSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 258c10bfcfSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 268c10bfcfSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 278c10bfcfSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 288c10bfcfSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 298c10bfcfSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 308c10bfcfSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 318c10bfcfSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3298a7f915SMatthew Dillon * SUCH DAMAGE. 3398a7f915SMatthew Dillon */ 3498a7f915SMatthew Dillon 3598a7f915SMatthew Dillon /* 3698a7f915SMatthew Dillon * This module implements variable storage and management for variant 3798a7f915SMatthew Dillon * symlinks. These variables may also be used for general purposes. 3898a7f915SMatthew Dillon */ 3998a7f915SMatthew Dillon 4098a7f915SMatthew Dillon #include <sys/param.h> 4198a7f915SMatthew Dillon #include <sys/systm.h> 4298a7f915SMatthew Dillon #include <sys/kernel.h> 4398a7f915SMatthew Dillon #include <sys/ucred.h> 4498a7f915SMatthew Dillon #include <sys/resourcevar.h> 4598a7f915SMatthew Dillon #include <sys/proc.h> 46895c1f85SMichael Neumann #include <sys/priv.h> 47dbc282dfSJoerg Sonnenberger #include <sys/jail.h> 4898a7f915SMatthew Dillon #include <sys/queue.h> 4998a7f915SMatthew Dillon #include <sys/sysctl.h> 5098a7f915SMatthew Dillon #include <sys/malloc.h> 5198a7f915SMatthew Dillon #include <sys/varsym.h> 5298a7f915SMatthew Dillon #include <sys/sysproto.h> 5398a7f915SMatthew Dillon 5498a7f915SMatthew Dillon MALLOC_DEFINE(M_VARSYM, "varsym", "variable sets for variant symlinks"); 5598a7f915SMatthew Dillon 5698a7f915SMatthew Dillon struct varsymset varsymset_sys; 5798a7f915SMatthew Dillon 5898a7f915SMatthew Dillon /* 5998a7f915SMatthew Dillon * Initialize the variant symlink subsystem 6098a7f915SMatthew Dillon */ 6198a7f915SMatthew Dillon static void 6298a7f915SMatthew Dillon varsym_sysinit(void *dummy) 6398a7f915SMatthew Dillon { 6498a7f915SMatthew Dillon varsymset_init(&varsymset_sys, NULL); 6598a7f915SMatthew Dillon } 66ba39e2e0SMatthew Dillon SYSINIT(announce, SI_BOOT2_MACHDEP, SI_ORDER_FIRST, varsym_sysinit, NULL); 6798a7f915SMatthew Dillon 6898a7f915SMatthew Dillon /* 69063147e5SMatthew Dillon * varsymreplace() - called from namei 70063147e5SMatthew Dillon * 71063147e5SMatthew Dillon * Do variant symlink variable substitution 72063147e5SMatthew Dillon */ 73063147e5SMatthew Dillon int 74063147e5SMatthew Dillon varsymreplace(char *cp, int linklen, int maxlen) 75063147e5SMatthew Dillon { 76063147e5SMatthew Dillon int rlen; 77063147e5SMatthew Dillon int xlen; 78063147e5SMatthew Dillon int nlen; 79063147e5SMatthew Dillon int i; 80063147e5SMatthew Dillon varsym_t var; 81063147e5SMatthew Dillon 82063147e5SMatthew Dillon rlen = linklen; 83063147e5SMatthew Dillon while (linklen > 1) { 84063147e5SMatthew Dillon if (cp[0] == '$' && cp[1] == '{') { 85063147e5SMatthew Dillon for (i = 2; i < linklen; ++i) { 86063147e5SMatthew Dillon if (cp[i] == '}') 87063147e5SMatthew Dillon break; 88063147e5SMatthew Dillon } 89063147e5SMatthew Dillon if (i < linklen && 90063147e5SMatthew Dillon (var = varsymfind(VARSYM_ALL_MASK, cp + 2, i - 2)) != NULL 91063147e5SMatthew Dillon ) { 92063147e5SMatthew Dillon xlen = i + 1; /* bytes to strike */ 93063147e5SMatthew Dillon nlen = strlen(var->vs_data); /* bytes to add */ 94063147e5SMatthew Dillon if (linklen + nlen - xlen >= maxlen) { 95063147e5SMatthew Dillon varsymdrop(var); 96063147e5SMatthew Dillon return(-1); 97063147e5SMatthew Dillon } 98063147e5SMatthew Dillon KKASSERT(linklen >= xlen); 99063147e5SMatthew Dillon if (linklen != xlen) 100063147e5SMatthew Dillon bcopy(cp + xlen, cp + nlen, linklen - xlen); 101063147e5SMatthew Dillon bcopy(var->vs_data, cp, nlen); 102063147e5SMatthew Dillon linklen += nlen - xlen; /* new relative length */ 103063147e5SMatthew Dillon rlen += nlen - xlen; /* returned total length */ 104063147e5SMatthew Dillon cp += nlen; /* adjust past replacement */ 105063147e5SMatthew Dillon linklen -= nlen; /* adjust past replacement */ 106063147e5SMatthew Dillon maxlen -= nlen; /* adjust past replacement */ 107063147e5SMatthew Dillon } else { 108063147e5SMatthew Dillon /* 109063147e5SMatthew Dillon * It's ok if i points to the '}', it will simply be 110063147e5SMatthew Dillon * skipped. i could also have hit linklen. 111063147e5SMatthew Dillon */ 112063147e5SMatthew Dillon cp += i; 113063147e5SMatthew Dillon linklen -= i; 114063147e5SMatthew Dillon maxlen -= i; 115063147e5SMatthew Dillon } 116063147e5SMatthew Dillon } else { 117063147e5SMatthew Dillon ++cp; 118063147e5SMatthew Dillon --linklen; 119063147e5SMatthew Dillon --maxlen; 120063147e5SMatthew Dillon } 121063147e5SMatthew Dillon } 122063147e5SMatthew Dillon return(rlen); 123063147e5SMatthew Dillon } 124063147e5SMatthew Dillon 125063147e5SMatthew Dillon /* 12698a7f915SMatthew Dillon * varsym_set() system call 12798a7f915SMatthew Dillon * 12898a7f915SMatthew Dillon * (int level, const char *name, const char *data) 12998a7f915SMatthew Dillon */ 13098a7f915SMatthew Dillon int 131753fd850SMatthew Dillon sys_varsym_set(struct varsym_set_args *uap) 13298a7f915SMatthew Dillon { 13398a7f915SMatthew Dillon char name[MAXVARSYM_NAME]; 13498a7f915SMatthew Dillon char *buf; 1359910d07bSMatthew Dillon struct thread *td; 1369910d07bSMatthew Dillon struct lwp *lp; 13798a7f915SMatthew Dillon int error; 13898a7f915SMatthew Dillon 1399910d07bSMatthew Dillon td = curthread; 1409910d07bSMatthew Dillon lp = td->td_lwp; 141e61b3df7SMichael Neumann 14298a7f915SMatthew Dillon if ((error = copyinstr(uap->name, name, sizeof(name), NULL)) != 0) 14398a7f915SMatthew Dillon goto done2; 144efda3bd0SMatthew Dillon buf = kmalloc(MAXVARSYM_DATA, M_TEMP, M_WAITOK); 14598a7f915SMatthew Dillon if (uap->data && 14698a7f915SMatthew Dillon (error = copyinstr(uap->data, buf, MAXVARSYM_DATA, NULL)) != 0) 14798a7f915SMatthew Dillon { 14898a7f915SMatthew Dillon goto done1; 14998a7f915SMatthew Dillon } 1503919ced0SMatthew Dillon 15198a7f915SMatthew Dillon switch(uap->level) { 15298a7f915SMatthew Dillon case VARSYM_SYS: 1539910d07bSMatthew Dillon if (lp != NULL && td->td_ucred->cr_prison != NULL) 154dbc282dfSJoerg Sonnenberger uap->level = VARSYM_PRISON; 155*f8bfbc51SMatthew Dillon /* fall through */ 156dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 1579910d07bSMatthew Dillon if (lp != NULL && 1589910d07bSMatthew Dillon (error = priv_check_cred(td->td_ucred, PRIV_VARSYM_SYS, 0)) != 0) 15998a7f915SMatthew Dillon break; 16098a7f915SMatthew Dillon /* fall through */ 16198a7f915SMatthew Dillon case VARSYM_USER: 16298a7f915SMatthew Dillon /* XXX check jail / implement per-jail user */ 16398a7f915SMatthew Dillon /* fall through */ 16498a7f915SMatthew Dillon case VARSYM_PROC: 16598a7f915SMatthew Dillon if (uap->data) { 16698a7f915SMatthew Dillon (void)varsymmake(uap->level, name, NULL); 16798a7f915SMatthew Dillon error = varsymmake(uap->level, name, buf); 16898a7f915SMatthew Dillon } else { 16998a7f915SMatthew Dillon error = varsymmake(uap->level, name, NULL); 17098a7f915SMatthew Dillon } 17198a7f915SMatthew Dillon break; 17298a7f915SMatthew Dillon } 17398a7f915SMatthew Dillon done1: 174efda3bd0SMatthew Dillon kfree(buf, M_TEMP); 17598a7f915SMatthew Dillon done2: 17698a7f915SMatthew Dillon return(error); 17798a7f915SMatthew Dillon } 17898a7f915SMatthew Dillon 17998a7f915SMatthew Dillon /* 18098a7f915SMatthew Dillon * varsym_get() system call 18198a7f915SMatthew Dillon * 18298a7f915SMatthew Dillon * (int mask, const char *wild, char *buf, int bufsize) 1833919ced0SMatthew Dillon * 1843919ced0SMatthew Dillon * MPALMOSTSAFE 18598a7f915SMatthew Dillon */ 18698a7f915SMatthew Dillon int 187753fd850SMatthew Dillon sys_varsym_get(struct varsym_get_args *uap) 18898a7f915SMatthew Dillon { 18998a7f915SMatthew Dillon char wild[MAXVARSYM_NAME]; 19098a7f915SMatthew Dillon varsym_t sym; 19198a7f915SMatthew Dillon int error; 19298a7f915SMatthew Dillon int dlen; 19398a7f915SMatthew Dillon 19498a7f915SMatthew Dillon if ((error = copyinstr(uap->wild, wild, sizeof(wild), NULL)) != 0) 19598a7f915SMatthew Dillon goto done; 19698a7f915SMatthew Dillon sym = varsymfind(uap->mask, wild, strlen(wild)); 19798a7f915SMatthew Dillon if (sym == NULL) { 19898a7f915SMatthew Dillon error = ENOENT; 19998a7f915SMatthew Dillon goto done; 20098a7f915SMatthew Dillon } 20198a7f915SMatthew Dillon dlen = strlen(sym->vs_data); 20298a7f915SMatthew Dillon if (dlen < uap->bufsize) { 20398a7f915SMatthew Dillon copyout(sym->vs_data, uap->buf, dlen + 1); 20498a7f915SMatthew Dillon } else if (uap->bufsize) { 20598a7f915SMatthew Dillon copyout("", uap->buf, 1); 20698a7f915SMatthew Dillon } 20798a7f915SMatthew Dillon uap->sysmsg_result = dlen + 1; 20898a7f915SMatthew Dillon varsymdrop(sym); 20998a7f915SMatthew Dillon done: 210*f8bfbc51SMatthew Dillon 21198a7f915SMatthew Dillon return(error); 21298a7f915SMatthew Dillon } 21398a7f915SMatthew Dillon 21498a7f915SMatthew Dillon /* 2150a004aa2SMatthew Dillon * varsym_list() system call 2160a004aa2SMatthew Dillon * 2170a004aa2SMatthew Dillon * (int level, char *buf, int maxsize, int *marker) 2183919ced0SMatthew Dillon * 2193919ced0SMatthew Dillon * MPALMOSTSAFE 2200a004aa2SMatthew Dillon */ 2210a004aa2SMatthew Dillon int 222753fd850SMatthew Dillon sys_varsym_list(struct varsym_list_args *uap) 2230a004aa2SMatthew Dillon { 2240a004aa2SMatthew Dillon struct varsymset *vss; 2250a004aa2SMatthew Dillon struct varsyment *ve; 2269910d07bSMatthew Dillon struct thread *td; 2270a004aa2SMatthew Dillon struct proc *p; 2289910d07bSMatthew Dillon struct lwp *lp; 2290a004aa2SMatthew Dillon int i; 2300a004aa2SMatthew Dillon int error; 2310a004aa2SMatthew Dillon int bytes; 2320a004aa2SMatthew Dillon int earlyterm; 2330a004aa2SMatthew Dillon int marker; 2340a004aa2SMatthew Dillon 2350a004aa2SMatthew Dillon /* 2360a004aa2SMatthew Dillon * Get the marker from userspace. 2370a004aa2SMatthew Dillon */ 2380a004aa2SMatthew Dillon if ((error = copyin(uap->marker, &marker, sizeof(marker))) != 0) 2390a004aa2SMatthew Dillon goto done; 2400a004aa2SMatthew Dillon 2410a004aa2SMatthew Dillon /* 2420a004aa2SMatthew Dillon * Figure out the varsym set. 2430a004aa2SMatthew Dillon */ 2449910d07bSMatthew Dillon td = curthread; 2459910d07bSMatthew Dillon lp = td->td_lwp; 2469910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 2479910d07bSMatthew Dillon 2480a004aa2SMatthew Dillon vss = NULL; 2490a004aa2SMatthew Dillon 2500a004aa2SMatthew Dillon switch (uap->level) { 2510a004aa2SMatthew Dillon case VARSYM_PROC: 2520a004aa2SMatthew Dillon if (p) 2530a004aa2SMatthew Dillon vss = &p->p_varsymset; 2540a004aa2SMatthew Dillon break; 2550a004aa2SMatthew Dillon case VARSYM_USER: 2569910d07bSMatthew Dillon if (lp) 2579910d07bSMatthew Dillon vss = &td->td_ucred->cr_uidinfo->ui_varsymset; 2580a004aa2SMatthew Dillon break; 2590a004aa2SMatthew Dillon case VARSYM_SYS: 2600a004aa2SMatthew Dillon vss = &varsymset_sys; 2610a004aa2SMatthew Dillon break; 262dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 2639910d07bSMatthew Dillon if (lp && td->td_ucred->cr_prison) 2649910d07bSMatthew Dillon vss = &td->td_ucred->cr_prison->pr_varsymset; 265dbc282dfSJoerg Sonnenberger break; 2660a004aa2SMatthew Dillon } 2670a004aa2SMatthew Dillon if (vss == NULL) { 2680a004aa2SMatthew Dillon error = EINVAL; 2690a004aa2SMatthew Dillon goto done; 2700a004aa2SMatthew Dillon } 2710a004aa2SMatthew Dillon 2720a004aa2SMatthew Dillon /* 2730a004aa2SMatthew Dillon * Loop through the variables and dump them to uap->buf 2740a004aa2SMatthew Dillon */ 2750a004aa2SMatthew Dillon i = 0; 2760a004aa2SMatthew Dillon bytes = 0; 2770a004aa2SMatthew Dillon earlyterm = 0; 2780a004aa2SMatthew Dillon 2799d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_SHARED); 2800a004aa2SMatthew Dillon TAILQ_FOREACH(ve, &vss->vx_queue, ve_entry) { 2810a004aa2SMatthew Dillon varsym_t sym = ve->ve_sym; 2820a004aa2SMatthew Dillon int namelen = strlen(sym->vs_name); 2830a004aa2SMatthew Dillon int datalen = strlen(sym->vs_data); 2840a004aa2SMatthew Dillon int totlen = namelen + datalen + 2; 2850a004aa2SMatthew Dillon 2860a004aa2SMatthew Dillon /* 2870a004aa2SMatthew Dillon * Skip to our index point 2880a004aa2SMatthew Dillon */ 2890a004aa2SMatthew Dillon if (i < marker) { 2900a004aa2SMatthew Dillon ++i; 2910a004aa2SMatthew Dillon continue; 2920a004aa2SMatthew Dillon } 2930a004aa2SMatthew Dillon 2940a004aa2SMatthew Dillon /* 2950a004aa2SMatthew Dillon * Stop if there is insufficient space in the user buffer. 2960a004aa2SMatthew Dillon * If we haven't stored anything yet return EOVERFLOW. 2970a004aa2SMatthew Dillon * Note that the marker index (i) does not change. 2980a004aa2SMatthew Dillon */ 2990a004aa2SMatthew Dillon if (bytes + totlen > uap->maxsize) { 3000a004aa2SMatthew Dillon if (bytes == 0) 3010a004aa2SMatthew Dillon error = EOVERFLOW; 3020a004aa2SMatthew Dillon earlyterm = 1; 3030a004aa2SMatthew Dillon break; 3040a004aa2SMatthew Dillon } 3050a004aa2SMatthew Dillon 3060a004aa2SMatthew Dillon error = copyout(sym->vs_name, uap->buf + bytes, namelen + 1); 3070a004aa2SMatthew Dillon if (error == 0) { 3080a004aa2SMatthew Dillon bytes += namelen + 1; 3090a004aa2SMatthew Dillon error = copyout(sym->vs_data, uap->buf + bytes, datalen + 1); 3100a004aa2SMatthew Dillon if (error == 0) 3110a004aa2SMatthew Dillon bytes += datalen + 1; 3120a004aa2SMatthew Dillon else 3130a004aa2SMatthew Dillon bytes -= namelen + 1; /* revert if error */ 3140a004aa2SMatthew Dillon } 3150a004aa2SMatthew Dillon if (error) { 3160a004aa2SMatthew Dillon earlyterm = 1; 3170a004aa2SMatthew Dillon break; 3180a004aa2SMatthew Dillon } 3190a004aa2SMatthew Dillon ++i; 3200a004aa2SMatthew Dillon } 3219d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 3220a004aa2SMatthew Dillon 3230a004aa2SMatthew Dillon /* 3240a004aa2SMatthew Dillon * Save the marker back. If no error occured and earlyterm is clear 3250a004aa2SMatthew Dillon * the marker is set to -1 indicating that the variable list has been 3260a004aa2SMatthew Dillon * exhausted. If no error occured the number of bytes loaded into 3270a004aa2SMatthew Dillon * the buffer will be returned, otherwise the syscall code returns -1. 3280a004aa2SMatthew Dillon */ 3290a004aa2SMatthew Dillon if (error == 0 && earlyterm == 0) 3300a004aa2SMatthew Dillon marker = -1; 3310a004aa2SMatthew Dillon else 3320a004aa2SMatthew Dillon marker = i; 3330a004aa2SMatthew Dillon if (error == 0) 3340a004aa2SMatthew Dillon error = copyout(&marker, uap->marker, sizeof(marker)); 3350a004aa2SMatthew Dillon uap->sysmsg_result = bytes; 3360a004aa2SMatthew Dillon done: 3370a004aa2SMatthew Dillon return(error); 3380a004aa2SMatthew Dillon } 3390a004aa2SMatthew Dillon 3400a004aa2SMatthew Dillon /* 34198a7f915SMatthew Dillon * Lookup a variant symlink. XXX use a hash table. 34298a7f915SMatthew Dillon */ 34398a7f915SMatthew Dillon static 34498a7f915SMatthew Dillon struct varsyment * 34598a7f915SMatthew Dillon varsymlookup(struct varsymset *vss, const char *name, int namelen) 34698a7f915SMatthew Dillon { 34798a7f915SMatthew Dillon struct varsyment *ve; 34898a7f915SMatthew Dillon 3499d7a637eSAggelos Economopoulos KKASSERT(lockstatus(&vss->vx_lock, curthread) != 0); 35098a7f915SMatthew Dillon TAILQ_FOREACH(ve, &vss->vx_queue, ve_entry) { 35198a7f915SMatthew Dillon varsym_t var = ve->ve_sym; 35298a7f915SMatthew Dillon if (var->vs_namelen == namelen && 35398a7f915SMatthew Dillon bcmp(name, var->vs_name, namelen) == 0 35498a7f915SMatthew Dillon ) { 35598a7f915SMatthew Dillon return(ve); 35698a7f915SMatthew Dillon } 35798a7f915SMatthew Dillon } 35898a7f915SMatthew Dillon return(NULL); 35998a7f915SMatthew Dillon } 36098a7f915SMatthew Dillon 3619d7a637eSAggelos Economopoulos static 3629d7a637eSAggelos Economopoulos void 3639d7a637eSAggelos Economopoulos vsslock(struct varsymset **vss, struct varsymset *n) 3649d7a637eSAggelos Economopoulos { 3659d7a637eSAggelos Economopoulos if (*vss) { 3669d7a637eSAggelos Economopoulos lockmgr(&(*vss)->vx_lock, LK_RELEASE); 3679d7a637eSAggelos Economopoulos } 3689d7a637eSAggelos Economopoulos lockmgr(&n->vx_lock, LK_SHARED); 3699d7a637eSAggelos Economopoulos *vss = n; 3709d7a637eSAggelos Economopoulos } 3719d7a637eSAggelos Economopoulos 37298a7f915SMatthew Dillon varsym_t 37398a7f915SMatthew Dillon varsymfind(int mask, const char *name, int namelen) 37498a7f915SMatthew Dillon { 37598a7f915SMatthew Dillon struct varsyment *ve = NULL; 3769d7a637eSAggelos Economopoulos struct varsymset *vss = NULL; 3779910d07bSMatthew Dillon struct thread *td; 3789910d07bSMatthew Dillon struct lwp *lp; 3799910d07bSMatthew Dillon struct proc *p; 38098a7f915SMatthew Dillon varsym_t sym; 38198a7f915SMatthew Dillon 3829910d07bSMatthew Dillon td = curthread; 3839910d07bSMatthew Dillon lp = td->td_lwp; 3849910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 3859910d07bSMatthew Dillon 3869910d07bSMatthew Dillon if ((mask & (VARSYM_PROC_MASK|VARSYM_USER_MASK)) && lp != NULL) { 3879d7a637eSAggelos Economopoulos if (mask & VARSYM_PROC_MASK) { 3889d7a637eSAggelos Economopoulos vsslock(&vss, &p->p_varsymset); 3899d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 3909d7a637eSAggelos Economopoulos } 3919d7a637eSAggelos Economopoulos if (ve == NULL && (mask & VARSYM_USER_MASK)) { 3929910d07bSMatthew Dillon vsslock(&vss, &td->td_ucred->cr_uidinfo->ui_varsymset); 3939d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 3949d7a637eSAggelos Economopoulos } 39598a7f915SMatthew Dillon } 396dbc282dfSJoerg Sonnenberger if (ve == NULL && (mask & VARSYM_SYS_MASK)) { 3979910d07bSMatthew Dillon if (lp != NULL && td->td_ucred->cr_prison) { 3989910d07bSMatthew Dillon vsslock(&vss, &td->td_ucred->cr_prison->pr_varsymset); 3999d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4009d7a637eSAggelos Economopoulos } else { 4019d7a637eSAggelos Economopoulos vsslock(&vss, &varsymset_sys); 4029d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4039d7a637eSAggelos Economopoulos } 404dbc282dfSJoerg Sonnenberger } 40598a7f915SMatthew Dillon if (ve) { 40698a7f915SMatthew Dillon sym = ve->ve_sym; 4079d7a637eSAggelos Economopoulos atomic_add_int(&sym->vs_refs, 1); 40898a7f915SMatthew Dillon } else { 4099d7a637eSAggelos Economopoulos sym = NULL; 41098a7f915SMatthew Dillon } 411548d73efSSascha Wildner if (vss) 4129d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 4139d7a637eSAggelos Economopoulos return sym; 41498a7f915SMatthew Dillon } 41598a7f915SMatthew Dillon 41698a7f915SMatthew Dillon int 41798a7f915SMatthew Dillon varsymmake(int level, const char *name, const char *data) 41898a7f915SMatthew Dillon { 41998a7f915SMatthew Dillon struct varsymset *vss = NULL; 42098a7f915SMatthew Dillon struct varsyment *ve; 4219910d07bSMatthew Dillon struct thread *td; 4229910d07bSMatthew Dillon struct proc *p; 4239910d07bSMatthew Dillon struct lwp *lp; 42498a7f915SMatthew Dillon varsym_t sym; 42598a7f915SMatthew Dillon int namelen = strlen(name); 42698a7f915SMatthew Dillon int datalen; 42798a7f915SMatthew Dillon int error; 42898a7f915SMatthew Dillon 4299910d07bSMatthew Dillon td = curthread; 4309910d07bSMatthew Dillon lp = td->td_lwp; 4319910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 4329910d07bSMatthew Dillon 43398a7f915SMatthew Dillon switch(level) { 43498a7f915SMatthew Dillon case VARSYM_PROC: 43598a7f915SMatthew Dillon if (p) 43698a7f915SMatthew Dillon vss = &p->p_varsymset; 43798a7f915SMatthew Dillon break; 43898a7f915SMatthew Dillon case VARSYM_USER: 4399910d07bSMatthew Dillon if (lp) 4409910d07bSMatthew Dillon vss = &td->td_ucred->cr_uidinfo->ui_varsymset; 44198a7f915SMatthew Dillon break; 44298a7f915SMatthew Dillon case VARSYM_SYS: 44398a7f915SMatthew Dillon vss = &varsymset_sys; 44498a7f915SMatthew Dillon break; 445dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 4469910d07bSMatthew Dillon if (lp && td->td_ucred->cr_prison) 4479910d07bSMatthew Dillon vss = &td->td_ucred->cr_prison->pr_varsymset; 448dbc282dfSJoerg Sonnenberger break; 44998a7f915SMatthew Dillon } 45098a7f915SMatthew Dillon if (vss == NULL) { 4519d7a637eSAggelos Economopoulos return EINVAL; 4529d7a637eSAggelos Economopoulos } 4539d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_EXCLUSIVE); 4549d7a637eSAggelos Economopoulos if (data && vss->vx_setsize >= MAXVARSYM_SET) { 45598a7f915SMatthew Dillon error = E2BIG; 45698a7f915SMatthew Dillon } else if (data) { 45798a7f915SMatthew Dillon datalen = strlen(data); 458efda3bd0SMatthew Dillon ve = kmalloc(sizeof(struct varsyment), M_VARSYM, M_WAITOK|M_ZERO); 459efda3bd0SMatthew Dillon sym = kmalloc(sizeof(struct varsym) + namelen + datalen + 2, M_VARSYM, M_WAITOK); 46098a7f915SMatthew Dillon ve->ve_sym = sym; 46198a7f915SMatthew Dillon sym->vs_refs = 1; 46298a7f915SMatthew Dillon sym->vs_namelen = namelen; 46398a7f915SMatthew Dillon sym->vs_name = (char *)(sym + 1); 46498a7f915SMatthew Dillon sym->vs_data = sym->vs_name + namelen + 1; 46598a7f915SMatthew Dillon strcpy(sym->vs_name, name); 46698a7f915SMatthew Dillon strcpy(sym->vs_data, data); 46798a7f915SMatthew Dillon TAILQ_INSERT_TAIL(&vss->vx_queue, ve, ve_entry); 46898a7f915SMatthew Dillon vss->vx_setsize += sizeof(struct varsyment) + sizeof(struct varsym) + namelen + datalen + 8; 46998a7f915SMatthew Dillon error = 0; 47098a7f915SMatthew Dillon } else { 47198a7f915SMatthew Dillon if ((ve = varsymlookup(vss, name, namelen)) != NULL) { 47298a7f915SMatthew Dillon TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry); 47398a7f915SMatthew Dillon vss->vx_setsize -= sizeof(struct varsyment) + sizeof(struct varsym) + namelen + strlen(ve->ve_sym->vs_data) + 8; 47498a7f915SMatthew Dillon varsymdrop(ve->ve_sym); 475efda3bd0SMatthew Dillon kfree(ve, M_VARSYM); 47698a7f915SMatthew Dillon error = 0; 47798a7f915SMatthew Dillon } else { 47898a7f915SMatthew Dillon error = ENOENT; 47998a7f915SMatthew Dillon } 48098a7f915SMatthew Dillon } 4819d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 48298a7f915SMatthew Dillon return(error); 48398a7f915SMatthew Dillon } 48498a7f915SMatthew Dillon 48598a7f915SMatthew Dillon void 48698a7f915SMatthew Dillon varsymdrop(varsym_t sym) 48798a7f915SMatthew Dillon { 48898a7f915SMatthew Dillon KKASSERT(sym->vs_refs > 0); 4899d7a637eSAggelos Economopoulos if (atomic_fetchadd_int(&sym->vs_refs, -1) == 1) { 490efda3bd0SMatthew Dillon kfree(sym, M_VARSYM); 49198a7f915SMatthew Dillon } 49298a7f915SMatthew Dillon } 49398a7f915SMatthew Dillon 4949d7a637eSAggelos Economopoulos /* 4959d7a637eSAggelos Economopoulos * Insert a duplicate of ve in vss. Does not do any locking, 4969d7a637eSAggelos Economopoulos * so it is the callers responsibility to make sure nobody 4979d7a637eSAggelos Economopoulos * else can mess with the TAILQ in vss at the same time. 4989d7a637eSAggelos Economopoulos */ 49998a7f915SMatthew Dillon static void 50098a7f915SMatthew Dillon varsymdup(struct varsymset *vss, struct varsyment *ve) 50198a7f915SMatthew Dillon { 50298a7f915SMatthew Dillon struct varsyment *nve; 50398a7f915SMatthew Dillon 504efda3bd0SMatthew Dillon nve = kmalloc(sizeof(struct varsyment), M_VARSYM, M_WAITOK|M_ZERO); 50598a7f915SMatthew Dillon nve->ve_sym = ve->ve_sym; 5069d7a637eSAggelos Economopoulos ++nve->ve_sym->vs_refs; /* can't be reached, no need for atomic add */ 5079d7a637eSAggelos Economopoulos /* 5089d7a637eSAggelos Economopoulos * We're only called through varsymset_init() so vss is not yet reachable, 5099d7a637eSAggelos Economopoulos * no need to lock. 5109d7a637eSAggelos Economopoulos */ 51198a7f915SMatthew Dillon TAILQ_INSERT_TAIL(&vss->vx_queue, nve, ve_entry); 51298a7f915SMatthew Dillon } 51398a7f915SMatthew Dillon 51498a7f915SMatthew Dillon void 51598a7f915SMatthew Dillon varsymset_init(struct varsymset *vss, struct varsymset *copy) 51698a7f915SMatthew Dillon { 51798a7f915SMatthew Dillon struct varsyment *ve; 51898a7f915SMatthew Dillon 51998a7f915SMatthew Dillon TAILQ_INIT(&vss->vx_queue); 5209d7a637eSAggelos Economopoulos lockinit(&vss->vx_lock, "vx", 0, 0); 52198a7f915SMatthew Dillon if (copy) { 52298a7f915SMatthew Dillon TAILQ_FOREACH(ve, ©->vx_queue, ve_entry) { 52398a7f915SMatthew Dillon varsymdup(vss, ve); 52498a7f915SMatthew Dillon } 52598a7f915SMatthew Dillon vss->vx_setsize = copy->vx_setsize; 52698a7f915SMatthew Dillon } 52798a7f915SMatthew Dillon } 52898a7f915SMatthew Dillon 52998a7f915SMatthew Dillon void 53098a7f915SMatthew Dillon varsymset_clean(struct varsymset *vss) 53198a7f915SMatthew Dillon { 53298a7f915SMatthew Dillon struct varsyment *ve; 53398a7f915SMatthew Dillon 5349d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_EXCLUSIVE); 53598a7f915SMatthew Dillon while ((ve = TAILQ_FIRST(&vss->vx_queue)) != NULL) { 53698a7f915SMatthew Dillon TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry); 53798a7f915SMatthew Dillon varsymdrop(ve->ve_sym); 538efda3bd0SMatthew Dillon kfree(ve, M_VARSYM); 53998a7f915SMatthew Dillon } 54098a7f915SMatthew Dillon vss->vx_setsize = 0; 5419d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 54298a7f915SMatthew Dillon } 54398a7f915SMatthew Dillon 544