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 * 34ba39e2e0SMatthew Dillon * $DragonFly: src/sys/kern/kern_varsym.c,v 1.9 2007/04/30 07:18:54 dillon Exp $ 3598a7f915SMatthew Dillon */ 3698a7f915SMatthew Dillon 3798a7f915SMatthew Dillon /* 3898a7f915SMatthew Dillon * This module implements variable storage and management for variant 3998a7f915SMatthew Dillon * symlinks. These variables may also be used for general purposes. 4098a7f915SMatthew Dillon */ 4198a7f915SMatthew Dillon 4298a7f915SMatthew Dillon #include <sys/param.h> 4398a7f915SMatthew Dillon #include <sys/systm.h> 4498a7f915SMatthew Dillon #include <sys/kernel.h> 4598a7f915SMatthew Dillon #include <sys/ucred.h> 4698a7f915SMatthew Dillon #include <sys/resourcevar.h> 4798a7f915SMatthew Dillon #include <sys/proc.h> 48895c1f85SMichael Neumann #include <sys/priv.h> 49dbc282dfSJoerg Sonnenberger #include <sys/jail.h> 5098a7f915SMatthew Dillon #include <sys/queue.h> 5198a7f915SMatthew Dillon #include <sys/sysctl.h> 5298a7f915SMatthew Dillon #include <sys/malloc.h> 5398a7f915SMatthew Dillon #include <sys/varsym.h> 5498a7f915SMatthew Dillon #include <sys/sysproto.h> 5598a7f915SMatthew Dillon 56684a93c4SMatthew Dillon #include <sys/mplock2.h> 57684a93c4SMatthew Dillon 5898a7f915SMatthew Dillon MALLOC_DEFINE(M_VARSYM, "varsym", "variable sets for variant symlinks"); 5998a7f915SMatthew Dillon 6098a7f915SMatthew Dillon struct varsymset varsymset_sys; 6198a7f915SMatthew Dillon 6298a7f915SMatthew Dillon /* 6398a7f915SMatthew Dillon * Initialize the variant symlink subsystem 6498a7f915SMatthew Dillon */ 6598a7f915SMatthew Dillon static void 6698a7f915SMatthew Dillon varsym_sysinit(void *dummy) 6798a7f915SMatthew Dillon { 6898a7f915SMatthew Dillon varsymset_init(&varsymset_sys, NULL); 6998a7f915SMatthew Dillon } 70ba39e2e0SMatthew Dillon SYSINIT(announce, SI_BOOT2_MACHDEP, SI_ORDER_FIRST, varsym_sysinit, NULL); 7198a7f915SMatthew Dillon 7298a7f915SMatthew Dillon /* 73063147e5SMatthew Dillon * varsymreplace() - called from namei 74063147e5SMatthew Dillon * 75063147e5SMatthew Dillon * Do variant symlink variable substitution 76063147e5SMatthew Dillon */ 77063147e5SMatthew Dillon int 78063147e5SMatthew Dillon varsymreplace(char *cp, int linklen, int maxlen) 79063147e5SMatthew Dillon { 80063147e5SMatthew Dillon int rlen; 81063147e5SMatthew Dillon int xlen; 82063147e5SMatthew Dillon int nlen; 83063147e5SMatthew Dillon int i; 84063147e5SMatthew Dillon varsym_t var; 85063147e5SMatthew Dillon 86063147e5SMatthew Dillon rlen = linklen; 87063147e5SMatthew Dillon while (linklen > 1) { 88063147e5SMatthew Dillon if (cp[0] == '$' && cp[1] == '{') { 89063147e5SMatthew Dillon for (i = 2; i < linklen; ++i) { 90063147e5SMatthew Dillon if (cp[i] == '}') 91063147e5SMatthew Dillon break; 92063147e5SMatthew Dillon } 93063147e5SMatthew Dillon if (i < linklen && 94063147e5SMatthew Dillon (var = varsymfind(VARSYM_ALL_MASK, cp + 2, i - 2)) != NULL 95063147e5SMatthew Dillon ) { 96063147e5SMatthew Dillon xlen = i + 1; /* bytes to strike */ 97063147e5SMatthew Dillon nlen = strlen(var->vs_data); /* bytes to add */ 98063147e5SMatthew Dillon if (linklen + nlen - xlen >= maxlen) { 99063147e5SMatthew Dillon varsymdrop(var); 100063147e5SMatthew Dillon return(-1); 101063147e5SMatthew Dillon } 102063147e5SMatthew Dillon KKASSERT(linklen >= xlen); 103063147e5SMatthew Dillon if (linklen != xlen) 104063147e5SMatthew Dillon bcopy(cp + xlen, cp + nlen, linklen - xlen); 105063147e5SMatthew Dillon bcopy(var->vs_data, cp, nlen); 106063147e5SMatthew Dillon linklen += nlen - xlen; /* new relative length */ 107063147e5SMatthew Dillon rlen += nlen - xlen; /* returned total length */ 108063147e5SMatthew Dillon cp += nlen; /* adjust past replacement */ 109063147e5SMatthew Dillon linklen -= nlen; /* adjust past replacement */ 110063147e5SMatthew Dillon maxlen -= nlen; /* adjust past replacement */ 111063147e5SMatthew Dillon } else { 112063147e5SMatthew Dillon /* 113063147e5SMatthew Dillon * It's ok if i points to the '}', it will simply be 114063147e5SMatthew Dillon * skipped. i could also have hit linklen. 115063147e5SMatthew Dillon */ 116063147e5SMatthew Dillon cp += i; 117063147e5SMatthew Dillon linklen -= i; 118063147e5SMatthew Dillon maxlen -= i; 119063147e5SMatthew Dillon } 120063147e5SMatthew Dillon } else { 121063147e5SMatthew Dillon ++cp; 122063147e5SMatthew Dillon --linklen; 123063147e5SMatthew Dillon --maxlen; 124063147e5SMatthew Dillon } 125063147e5SMatthew Dillon } 126063147e5SMatthew Dillon return(rlen); 127063147e5SMatthew Dillon } 128063147e5SMatthew Dillon 129063147e5SMatthew Dillon /* 13098a7f915SMatthew Dillon * varsym_set() system call 13198a7f915SMatthew Dillon * 13298a7f915SMatthew Dillon * (int level, const char *name, const char *data) 1333919ced0SMatthew Dillon * 1343919ced0SMatthew Dillon * MPALMOSTSAFE 13598a7f915SMatthew Dillon */ 13698a7f915SMatthew Dillon int 137753fd850SMatthew Dillon sys_varsym_set(struct varsym_set_args *uap) 13898a7f915SMatthew Dillon { 13998a7f915SMatthew Dillon char name[MAXVARSYM_NAME]; 14098a7f915SMatthew Dillon char *buf; 1419910d07bSMatthew Dillon struct thread *td; 142*e61b3df7SMichael Neumann struct proc *p; 1439910d07bSMatthew Dillon struct lwp *lp; 14498a7f915SMatthew Dillon int error; 14598a7f915SMatthew Dillon 1469910d07bSMatthew Dillon td = curthread; 1479910d07bSMatthew Dillon lp = td->td_lwp; 1489910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 149*e61b3df7SMichael Neumann 15098a7f915SMatthew Dillon if ((error = copyinstr(uap->name, name, sizeof(name), NULL)) != 0) 15198a7f915SMatthew Dillon goto done2; 152efda3bd0SMatthew Dillon buf = kmalloc(MAXVARSYM_DATA, M_TEMP, M_WAITOK); 15398a7f915SMatthew Dillon if (uap->data && 15498a7f915SMatthew Dillon (error = copyinstr(uap->data, buf, MAXVARSYM_DATA, NULL)) != 0) 15598a7f915SMatthew Dillon { 15698a7f915SMatthew Dillon goto done1; 15798a7f915SMatthew Dillon } 1583919ced0SMatthew Dillon 1593919ced0SMatthew Dillon get_mplock(); 1603919ced0SMatthew Dillon 16198a7f915SMatthew Dillon switch(uap->level) { 16298a7f915SMatthew Dillon case VARSYM_SYS: 1639910d07bSMatthew Dillon if (lp != NULL && td->td_ucred->cr_prison != NULL) 164dbc282dfSJoerg Sonnenberger uap->level = VARSYM_PRISON; 165dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 1669910d07bSMatthew Dillon if (lp != NULL && 1679910d07bSMatthew Dillon (error = priv_check_cred(td->td_ucred, PRIV_VARSYM_SYS, 0)) != 0) 16898a7f915SMatthew Dillon break; 16998a7f915SMatthew Dillon /* fall through */ 17098a7f915SMatthew Dillon case VARSYM_USER: 17198a7f915SMatthew Dillon /* XXX check jail / implement per-jail user */ 17298a7f915SMatthew Dillon /* fall through */ 17398a7f915SMatthew Dillon case VARSYM_PROC: 17498a7f915SMatthew Dillon if (uap->data) { 17598a7f915SMatthew Dillon (void)varsymmake(uap->level, name, NULL); 17698a7f915SMatthew Dillon error = varsymmake(uap->level, name, buf); 17798a7f915SMatthew Dillon } else { 17898a7f915SMatthew Dillon error = varsymmake(uap->level, name, NULL); 17998a7f915SMatthew Dillon } 18098a7f915SMatthew Dillon break; 18198a7f915SMatthew Dillon } 1823919ced0SMatthew Dillon rel_mplock(); 18398a7f915SMatthew Dillon done1: 184efda3bd0SMatthew Dillon kfree(buf, M_TEMP); 18598a7f915SMatthew Dillon done2: 18698a7f915SMatthew Dillon return(error); 18798a7f915SMatthew Dillon } 18898a7f915SMatthew Dillon 18998a7f915SMatthew Dillon /* 19098a7f915SMatthew Dillon * varsym_get() system call 19198a7f915SMatthew Dillon * 19298a7f915SMatthew Dillon * (int mask, const char *wild, char *buf, int bufsize) 1933919ced0SMatthew Dillon * 1943919ced0SMatthew Dillon * MPALMOSTSAFE 19598a7f915SMatthew Dillon */ 19698a7f915SMatthew Dillon int 197753fd850SMatthew Dillon sys_varsym_get(struct varsym_get_args *uap) 19898a7f915SMatthew Dillon { 19998a7f915SMatthew Dillon char wild[MAXVARSYM_NAME]; 20098a7f915SMatthew Dillon varsym_t sym; 20198a7f915SMatthew Dillon int error; 20298a7f915SMatthew Dillon int dlen; 20398a7f915SMatthew Dillon 2043919ced0SMatthew Dillon get_mplock(); 20598a7f915SMatthew Dillon if ((error = copyinstr(uap->wild, wild, sizeof(wild), NULL)) != 0) 20698a7f915SMatthew Dillon goto done; 20798a7f915SMatthew Dillon sym = varsymfind(uap->mask, wild, strlen(wild)); 20898a7f915SMatthew Dillon if (sym == NULL) { 20998a7f915SMatthew Dillon error = ENOENT; 21098a7f915SMatthew Dillon goto done; 21198a7f915SMatthew Dillon } 21298a7f915SMatthew Dillon dlen = strlen(sym->vs_data); 21398a7f915SMatthew Dillon if (dlen < uap->bufsize) { 21498a7f915SMatthew Dillon copyout(sym->vs_data, uap->buf, dlen + 1); 21598a7f915SMatthew Dillon } else if (uap->bufsize) { 21698a7f915SMatthew Dillon copyout("", uap->buf, 1); 21798a7f915SMatthew Dillon } 21898a7f915SMatthew Dillon uap->sysmsg_result = dlen + 1; 21998a7f915SMatthew Dillon varsymdrop(sym); 22098a7f915SMatthew Dillon done: 2213919ced0SMatthew Dillon rel_mplock(); 22298a7f915SMatthew Dillon return(error); 22398a7f915SMatthew Dillon } 22498a7f915SMatthew Dillon 22598a7f915SMatthew Dillon /* 2260a004aa2SMatthew Dillon * varsym_list() system call 2270a004aa2SMatthew Dillon * 2280a004aa2SMatthew Dillon * (int level, char *buf, int maxsize, int *marker) 2293919ced0SMatthew Dillon * 2303919ced0SMatthew Dillon * MPALMOSTSAFE 2310a004aa2SMatthew Dillon */ 2320a004aa2SMatthew Dillon int 233753fd850SMatthew Dillon sys_varsym_list(struct varsym_list_args *uap) 2340a004aa2SMatthew Dillon { 2350a004aa2SMatthew Dillon struct varsymset *vss; 2360a004aa2SMatthew Dillon struct varsyment *ve; 2379910d07bSMatthew Dillon struct thread *td; 2380a004aa2SMatthew Dillon struct proc *p; 2399910d07bSMatthew Dillon struct lwp *lp; 2400a004aa2SMatthew Dillon int i; 2410a004aa2SMatthew Dillon int error; 2420a004aa2SMatthew Dillon int bytes; 2430a004aa2SMatthew Dillon int earlyterm; 2440a004aa2SMatthew Dillon int marker; 2450a004aa2SMatthew Dillon 2460a004aa2SMatthew Dillon /* 2470a004aa2SMatthew Dillon * Get the marker from userspace. 2480a004aa2SMatthew Dillon */ 2493919ced0SMatthew Dillon get_mplock(); 2500a004aa2SMatthew Dillon if ((error = copyin(uap->marker, &marker, sizeof(marker))) != 0) 2510a004aa2SMatthew Dillon goto done; 2520a004aa2SMatthew Dillon 2530a004aa2SMatthew Dillon /* 2540a004aa2SMatthew Dillon * Figure out the varsym set. 2550a004aa2SMatthew Dillon */ 2569910d07bSMatthew Dillon td = curthread; 2579910d07bSMatthew Dillon lp = td->td_lwp; 2589910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 2599910d07bSMatthew Dillon 2600a004aa2SMatthew Dillon vss = NULL; 2610a004aa2SMatthew Dillon 2620a004aa2SMatthew Dillon switch (uap->level) { 2630a004aa2SMatthew Dillon case VARSYM_PROC: 2640a004aa2SMatthew Dillon if (p) 2650a004aa2SMatthew Dillon vss = &p->p_varsymset; 2660a004aa2SMatthew Dillon break; 2670a004aa2SMatthew Dillon case VARSYM_USER: 2689910d07bSMatthew Dillon if (lp) 2699910d07bSMatthew Dillon vss = &td->td_ucred->cr_uidinfo->ui_varsymset; 2700a004aa2SMatthew Dillon break; 2710a004aa2SMatthew Dillon case VARSYM_SYS: 2720a004aa2SMatthew Dillon vss = &varsymset_sys; 2730a004aa2SMatthew Dillon break; 274dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 2759910d07bSMatthew Dillon if (lp && td->td_ucred->cr_prison) 2769910d07bSMatthew Dillon vss = &td->td_ucred->cr_prison->pr_varsymset; 277dbc282dfSJoerg Sonnenberger break; 2780a004aa2SMatthew Dillon } 2790a004aa2SMatthew Dillon if (vss == NULL) { 2800a004aa2SMatthew Dillon error = EINVAL; 2810a004aa2SMatthew Dillon goto done; 2820a004aa2SMatthew Dillon } 2830a004aa2SMatthew Dillon 2840a004aa2SMatthew Dillon /* 2850a004aa2SMatthew Dillon * Loop through the variables and dump them to uap->buf 2860a004aa2SMatthew Dillon */ 2870a004aa2SMatthew Dillon i = 0; 2880a004aa2SMatthew Dillon bytes = 0; 2890a004aa2SMatthew Dillon earlyterm = 0; 2900a004aa2SMatthew Dillon 2919d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_SHARED); 2920a004aa2SMatthew Dillon TAILQ_FOREACH(ve, &vss->vx_queue, ve_entry) { 2930a004aa2SMatthew Dillon varsym_t sym = ve->ve_sym; 2940a004aa2SMatthew Dillon int namelen = strlen(sym->vs_name); 2950a004aa2SMatthew Dillon int datalen = strlen(sym->vs_data); 2960a004aa2SMatthew Dillon int totlen = namelen + datalen + 2; 2970a004aa2SMatthew Dillon 2980a004aa2SMatthew Dillon /* 2990a004aa2SMatthew Dillon * Skip to our index point 3000a004aa2SMatthew Dillon */ 3010a004aa2SMatthew Dillon if (i < marker) { 3020a004aa2SMatthew Dillon ++i; 3030a004aa2SMatthew Dillon continue; 3040a004aa2SMatthew Dillon } 3050a004aa2SMatthew Dillon 3060a004aa2SMatthew Dillon /* 3070a004aa2SMatthew Dillon * Stop if there is insufficient space in the user buffer. 3080a004aa2SMatthew Dillon * If we haven't stored anything yet return EOVERFLOW. 3090a004aa2SMatthew Dillon * Note that the marker index (i) does not change. 3100a004aa2SMatthew Dillon */ 3110a004aa2SMatthew Dillon if (bytes + totlen > uap->maxsize) { 3120a004aa2SMatthew Dillon if (bytes == 0) 3130a004aa2SMatthew Dillon error = EOVERFLOW; 3140a004aa2SMatthew Dillon earlyterm = 1; 3150a004aa2SMatthew Dillon break; 3160a004aa2SMatthew Dillon } 3170a004aa2SMatthew Dillon 3180a004aa2SMatthew Dillon error = copyout(sym->vs_name, uap->buf + bytes, namelen + 1); 3190a004aa2SMatthew Dillon if (error == 0) { 3200a004aa2SMatthew Dillon bytes += namelen + 1; 3210a004aa2SMatthew Dillon error = copyout(sym->vs_data, uap->buf + bytes, datalen + 1); 3220a004aa2SMatthew Dillon if (error == 0) 3230a004aa2SMatthew Dillon bytes += datalen + 1; 3240a004aa2SMatthew Dillon else 3250a004aa2SMatthew Dillon bytes -= namelen + 1; /* revert if error */ 3260a004aa2SMatthew Dillon } 3270a004aa2SMatthew Dillon if (error) { 3280a004aa2SMatthew Dillon earlyterm = 1; 3290a004aa2SMatthew Dillon break; 3300a004aa2SMatthew Dillon } 3310a004aa2SMatthew Dillon ++i; 3320a004aa2SMatthew Dillon } 3339d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 3340a004aa2SMatthew Dillon 3350a004aa2SMatthew Dillon /* 3360a004aa2SMatthew Dillon * Save the marker back. If no error occured and earlyterm is clear 3370a004aa2SMatthew Dillon * the marker is set to -1 indicating that the variable list has been 3380a004aa2SMatthew Dillon * exhausted. If no error occured the number of bytes loaded into 3390a004aa2SMatthew Dillon * the buffer will be returned, otherwise the syscall code returns -1. 3400a004aa2SMatthew Dillon */ 3410a004aa2SMatthew Dillon if (error == 0 && earlyterm == 0) 3420a004aa2SMatthew Dillon marker = -1; 3430a004aa2SMatthew Dillon else 3440a004aa2SMatthew Dillon marker = i; 3450a004aa2SMatthew Dillon if (error == 0) 3460a004aa2SMatthew Dillon error = copyout(&marker, uap->marker, sizeof(marker)); 3470a004aa2SMatthew Dillon uap->sysmsg_result = bytes; 3480a004aa2SMatthew Dillon done: 3493919ced0SMatthew Dillon rel_mplock(); 3500a004aa2SMatthew Dillon return(error); 3510a004aa2SMatthew Dillon } 3520a004aa2SMatthew Dillon 3530a004aa2SMatthew Dillon /* 35498a7f915SMatthew Dillon * Lookup a variant symlink. XXX use a hash table. 35598a7f915SMatthew Dillon */ 35698a7f915SMatthew Dillon static 35798a7f915SMatthew Dillon struct varsyment * 35898a7f915SMatthew Dillon varsymlookup(struct varsymset *vss, const char *name, int namelen) 35998a7f915SMatthew Dillon { 36098a7f915SMatthew Dillon struct varsyment *ve; 36198a7f915SMatthew Dillon 3629d7a637eSAggelos Economopoulos KKASSERT(lockstatus(&vss->vx_lock, curthread) != 0); 36398a7f915SMatthew Dillon TAILQ_FOREACH(ve, &vss->vx_queue, ve_entry) { 36498a7f915SMatthew Dillon varsym_t var = ve->ve_sym; 36598a7f915SMatthew Dillon if (var->vs_namelen == namelen && 36698a7f915SMatthew Dillon bcmp(name, var->vs_name, namelen) == 0 36798a7f915SMatthew Dillon ) { 36898a7f915SMatthew Dillon return(ve); 36998a7f915SMatthew Dillon } 37098a7f915SMatthew Dillon } 37198a7f915SMatthew Dillon return(NULL); 37298a7f915SMatthew Dillon } 37398a7f915SMatthew Dillon 3749d7a637eSAggelos Economopoulos static 3759d7a637eSAggelos Economopoulos void 3769d7a637eSAggelos Economopoulos vsslock(struct varsymset **vss, struct varsymset *n) 3779d7a637eSAggelos Economopoulos { 3789d7a637eSAggelos Economopoulos if (*vss) { 3799d7a637eSAggelos Economopoulos lockmgr(&(*vss)->vx_lock, LK_RELEASE); 3809d7a637eSAggelos Economopoulos } 3819d7a637eSAggelos Economopoulos lockmgr(&n->vx_lock, LK_SHARED); 3829d7a637eSAggelos Economopoulos *vss = n; 3839d7a637eSAggelos Economopoulos } 3849d7a637eSAggelos Economopoulos 38598a7f915SMatthew Dillon varsym_t 38698a7f915SMatthew Dillon varsymfind(int mask, const char *name, int namelen) 38798a7f915SMatthew Dillon { 38898a7f915SMatthew Dillon struct varsyment *ve = NULL; 3899d7a637eSAggelos Economopoulos struct varsymset *vss = NULL; 3909910d07bSMatthew Dillon struct thread *td; 3919910d07bSMatthew Dillon struct lwp *lp; 3929910d07bSMatthew Dillon struct proc *p; 39398a7f915SMatthew Dillon varsym_t sym; 39498a7f915SMatthew Dillon 3959910d07bSMatthew Dillon td = curthread; 3969910d07bSMatthew Dillon lp = td->td_lwp; 3979910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 3989910d07bSMatthew Dillon 3999910d07bSMatthew Dillon if ((mask & (VARSYM_PROC_MASK|VARSYM_USER_MASK)) && lp != NULL) { 4009d7a637eSAggelos Economopoulos if (mask & VARSYM_PROC_MASK) { 4019d7a637eSAggelos Economopoulos vsslock(&vss, &p->p_varsymset); 4029d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4039d7a637eSAggelos Economopoulos } 4049d7a637eSAggelos Economopoulos if (ve == NULL && (mask & VARSYM_USER_MASK)) { 4059910d07bSMatthew Dillon vsslock(&vss, &td->td_ucred->cr_uidinfo->ui_varsymset); 4069d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4079d7a637eSAggelos Economopoulos } 40898a7f915SMatthew Dillon } 409dbc282dfSJoerg Sonnenberger if (ve == NULL && (mask & VARSYM_SYS_MASK)) { 4109910d07bSMatthew Dillon if (lp != NULL && td->td_ucred->cr_prison) { 4119910d07bSMatthew Dillon vsslock(&vss, &td->td_ucred->cr_prison->pr_varsymset); 4129d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4139d7a637eSAggelos Economopoulos } else { 4149d7a637eSAggelos Economopoulos vsslock(&vss, &varsymset_sys); 4159d7a637eSAggelos Economopoulos ve = varsymlookup(vss, name, namelen); 4169d7a637eSAggelos Economopoulos } 417dbc282dfSJoerg Sonnenberger } 41898a7f915SMatthew Dillon if (ve) { 41998a7f915SMatthew Dillon sym = ve->ve_sym; 4209d7a637eSAggelos Economopoulos atomic_add_int(&sym->vs_refs, 1); 42198a7f915SMatthew Dillon } else { 4229d7a637eSAggelos Economopoulos sym = NULL; 42398a7f915SMatthew Dillon } 424548d73efSSascha Wildner if (vss) 4259d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 4269d7a637eSAggelos Economopoulos return sym; 42798a7f915SMatthew Dillon } 42898a7f915SMatthew Dillon 42998a7f915SMatthew Dillon int 43098a7f915SMatthew Dillon varsymmake(int level, const char *name, const char *data) 43198a7f915SMatthew Dillon { 43298a7f915SMatthew Dillon struct varsymset *vss = NULL; 43398a7f915SMatthew Dillon struct varsyment *ve; 4349910d07bSMatthew Dillon struct thread *td; 4359910d07bSMatthew Dillon struct proc *p; 4369910d07bSMatthew Dillon struct lwp *lp; 43798a7f915SMatthew Dillon varsym_t sym; 43898a7f915SMatthew Dillon int namelen = strlen(name); 43998a7f915SMatthew Dillon int datalen; 44098a7f915SMatthew Dillon int error; 44198a7f915SMatthew Dillon 4429910d07bSMatthew Dillon td = curthread; 4439910d07bSMatthew Dillon lp = td->td_lwp; 4449910d07bSMatthew Dillon p = lp ? lp->lwp_proc : NULL; 4459910d07bSMatthew Dillon 44698a7f915SMatthew Dillon switch(level) { 44798a7f915SMatthew Dillon case VARSYM_PROC: 44898a7f915SMatthew Dillon if (p) 44998a7f915SMatthew Dillon vss = &p->p_varsymset; 45098a7f915SMatthew Dillon break; 45198a7f915SMatthew Dillon case VARSYM_USER: 4529910d07bSMatthew Dillon if (lp) 4539910d07bSMatthew Dillon vss = &td->td_ucred->cr_uidinfo->ui_varsymset; 45498a7f915SMatthew Dillon break; 45598a7f915SMatthew Dillon case VARSYM_SYS: 45698a7f915SMatthew Dillon vss = &varsymset_sys; 45798a7f915SMatthew Dillon break; 458dbc282dfSJoerg Sonnenberger case VARSYM_PRISON: 4599910d07bSMatthew Dillon if (lp && td->td_ucred->cr_prison) 4609910d07bSMatthew Dillon vss = &td->td_ucred->cr_prison->pr_varsymset; 461dbc282dfSJoerg Sonnenberger break; 46298a7f915SMatthew Dillon } 46398a7f915SMatthew Dillon if (vss == NULL) { 4649d7a637eSAggelos Economopoulos return EINVAL; 4659d7a637eSAggelos Economopoulos } 4669d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_EXCLUSIVE); 4679d7a637eSAggelos Economopoulos if (data && vss->vx_setsize >= MAXVARSYM_SET) { 46898a7f915SMatthew Dillon error = E2BIG; 46998a7f915SMatthew Dillon } else if (data) { 47098a7f915SMatthew Dillon datalen = strlen(data); 471efda3bd0SMatthew Dillon ve = kmalloc(sizeof(struct varsyment), M_VARSYM, M_WAITOK|M_ZERO); 472efda3bd0SMatthew Dillon sym = kmalloc(sizeof(struct varsym) + namelen + datalen + 2, M_VARSYM, M_WAITOK); 47398a7f915SMatthew Dillon ve->ve_sym = sym; 47498a7f915SMatthew Dillon sym->vs_refs = 1; 47598a7f915SMatthew Dillon sym->vs_namelen = namelen; 47698a7f915SMatthew Dillon sym->vs_name = (char *)(sym + 1); 47798a7f915SMatthew Dillon sym->vs_data = sym->vs_name + namelen + 1; 47898a7f915SMatthew Dillon strcpy(sym->vs_name, name); 47998a7f915SMatthew Dillon strcpy(sym->vs_data, data); 48098a7f915SMatthew Dillon TAILQ_INSERT_TAIL(&vss->vx_queue, ve, ve_entry); 48198a7f915SMatthew Dillon vss->vx_setsize += sizeof(struct varsyment) + sizeof(struct varsym) + namelen + datalen + 8; 48298a7f915SMatthew Dillon error = 0; 48398a7f915SMatthew Dillon } else { 48498a7f915SMatthew Dillon if ((ve = varsymlookup(vss, name, namelen)) != NULL) { 48598a7f915SMatthew Dillon TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry); 48698a7f915SMatthew Dillon vss->vx_setsize -= sizeof(struct varsyment) + sizeof(struct varsym) + namelen + strlen(ve->ve_sym->vs_data) + 8; 48798a7f915SMatthew Dillon varsymdrop(ve->ve_sym); 488efda3bd0SMatthew Dillon kfree(ve, M_VARSYM); 48998a7f915SMatthew Dillon error = 0; 49098a7f915SMatthew Dillon } else { 49198a7f915SMatthew Dillon error = ENOENT; 49298a7f915SMatthew Dillon } 49398a7f915SMatthew Dillon } 4949d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 49598a7f915SMatthew Dillon return(error); 49698a7f915SMatthew Dillon } 49798a7f915SMatthew Dillon 49898a7f915SMatthew Dillon void 49998a7f915SMatthew Dillon varsymdrop(varsym_t sym) 50098a7f915SMatthew Dillon { 50198a7f915SMatthew Dillon KKASSERT(sym->vs_refs > 0); 5029d7a637eSAggelos Economopoulos if (atomic_fetchadd_int(&sym->vs_refs, -1) == 1) { 503efda3bd0SMatthew Dillon kfree(sym, M_VARSYM); 50498a7f915SMatthew Dillon } 50598a7f915SMatthew Dillon } 50698a7f915SMatthew Dillon 5079d7a637eSAggelos Economopoulos /* 5089d7a637eSAggelos Economopoulos * Insert a duplicate of ve in vss. Does not do any locking, 5099d7a637eSAggelos Economopoulos * so it is the callers responsibility to make sure nobody 5109d7a637eSAggelos Economopoulos * else can mess with the TAILQ in vss at the same time. 5119d7a637eSAggelos Economopoulos */ 51298a7f915SMatthew Dillon static void 51398a7f915SMatthew Dillon varsymdup(struct varsymset *vss, struct varsyment *ve) 51498a7f915SMatthew Dillon { 51598a7f915SMatthew Dillon struct varsyment *nve; 51698a7f915SMatthew Dillon 517efda3bd0SMatthew Dillon nve = kmalloc(sizeof(struct varsyment), M_VARSYM, M_WAITOK|M_ZERO); 51898a7f915SMatthew Dillon nve->ve_sym = ve->ve_sym; 5199d7a637eSAggelos Economopoulos ++nve->ve_sym->vs_refs; /* can't be reached, no need for atomic add */ 5209d7a637eSAggelos Economopoulos /* 5219d7a637eSAggelos Economopoulos * We're only called through varsymset_init() so vss is not yet reachable, 5229d7a637eSAggelos Economopoulos * no need to lock. 5239d7a637eSAggelos Economopoulos */ 52498a7f915SMatthew Dillon TAILQ_INSERT_TAIL(&vss->vx_queue, nve, ve_entry); 52598a7f915SMatthew Dillon } 52698a7f915SMatthew Dillon 52798a7f915SMatthew Dillon void 52898a7f915SMatthew Dillon varsymset_init(struct varsymset *vss, struct varsymset *copy) 52998a7f915SMatthew Dillon { 53098a7f915SMatthew Dillon struct varsyment *ve; 53198a7f915SMatthew Dillon 53298a7f915SMatthew Dillon TAILQ_INIT(&vss->vx_queue); 5339d7a637eSAggelos Economopoulos lockinit(&vss->vx_lock, "vx", 0, 0); 53498a7f915SMatthew Dillon if (copy) { 53598a7f915SMatthew Dillon TAILQ_FOREACH(ve, ©->vx_queue, ve_entry) { 53698a7f915SMatthew Dillon varsymdup(vss, ve); 53798a7f915SMatthew Dillon } 53898a7f915SMatthew Dillon vss->vx_setsize = copy->vx_setsize; 53998a7f915SMatthew Dillon } 54098a7f915SMatthew Dillon } 54198a7f915SMatthew Dillon 54298a7f915SMatthew Dillon void 54398a7f915SMatthew Dillon varsymset_clean(struct varsymset *vss) 54498a7f915SMatthew Dillon { 54598a7f915SMatthew Dillon struct varsyment *ve; 54698a7f915SMatthew Dillon 5479d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_EXCLUSIVE); 54898a7f915SMatthew Dillon while ((ve = TAILQ_FIRST(&vss->vx_queue)) != NULL) { 54998a7f915SMatthew Dillon TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry); 55098a7f915SMatthew Dillon varsymdrop(ve->ve_sym); 551efda3bd0SMatthew Dillon kfree(ve, M_VARSYM); 55298a7f915SMatthew Dillon } 55398a7f915SMatthew Dillon vss->vx_setsize = 0; 5549d7a637eSAggelos Economopoulos lockmgr(&vss->vx_lock, LK_RELEASE); 55598a7f915SMatthew Dillon } 55698a7f915SMatthew Dillon 557