12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /*
- * (c) Copyright 1993, 1994 Hewlett-Packard Company *
- * (c) Copyright 1993, 1994 International Business Machines Corp. *
- * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
- * (c) Copyright 1993, 1994 Novell, Inc. *
- */
- /******************************************************************************
- ******************************************************************************
- **
- ** DtEnvMap.c
- **
- ** $TOG: DtEnvMap.c /main/7 1998/07/30 12:11:59 mgreess $
- **
- ** Map the path elements of environment strings as specified by yet
- ** another environment string from the local host to a remote host.
- ** When possible, cache the results since filename mapping is expensive.
- **
- ** DTENVMAPFORREMOTE="NAME1[:NAME2[...]]"
- **
- ** NAME1=path1:path2
- ** NAME2=path3:path4:...
- **
- ******************************************************************************
- *****************************************************************************/
- #define X_INCLUDE_STRING_H
- #define XOS_USE_XT_LOCKING
- #include <X11/Xos_r.h>
- #include <DtNlUtils.h>
- #include <Tt/tt_c.h>
- #include "DtSvcLock.h"
- /******************************************************************************
- ******************************************************************************
- **
- ** Data Structures and Defines.
- **
- **/
- /**********************************************************
- *
- * What to map...
- *
- * ... is specified by either an environment variable or
- * a global X resource. If present, the X resource acts
- * globally, and is referred to on every attempt to map.
- * If an environment variable is set, it overrides the X
- * resource setting, thereby allowing for local control
- * of individual process threads (by way of propagated
- * environments).
- */
- #define _DTENV_MAP_RESOURCE_NAME "dtEnvMapForRemote"
- #define _DTENV_MAP_RESOURCE_CLASS "DtEnvMapForRemote"
- #define _DTENV_MAP_ENV_VAR "DTENVMAPFORREMOTE"
- /**********************************************************
- *
- * The primary caching/mapping data structures.
- */
- typedef struct {
- char *localEnvVarPtr; /* original ptr, used for restoring */
- char *localEnvVarCopy; /* eg, /users/foo:/usr/bar */
- char *mappedEnvVarPtr; /* eg, PATH=/nfs/.../foo:/nfs/.../bar */
- } cachedEnvVar;
- typedef struct {
- char *remoteHost; /* host to map env vars to */
- int cacheHit; /* usage rate for this mapping info */
- char *mapListStr; /* copy of DTENVMAPFORREMOTE=... */
- int mapListCnt; /* how many _real_ env vars to map */
- char **mapList; /* simple list of env var names to map*/
- cachedEnvVar *mapListDetails; /* list of map info per env var name */
- } cacheForTargetHost;
- /*
- * Cache information. Keep mapping information for MAX_HOSTS_CACHED
- * targetHosts.
- */
- #define MAX_HOSTS_CACHED 8
- static cacheForTargetHost cachePoolG[MAX_HOSTS_CACHED];
- /*
- * Track the most recent targetHost.
- */
- static char *mostRecentRemoteHostG;
- /**********************************************************
- *
- * Misc defines.
- *
- * To reduce malloc calls when creating lists, malloc
- * "list" in blocks:
- *
- * char *list[0..15 , 16..31, 32..63, ...]
- */
- #define MALLOC_BUMP_SIZE 16
- #define freeAndNull(ptr) if (ptr) free(ptr); ptr = NULL;
- #define ttfreeAndNull(ptr) if (ptr) tt_free(ptr); ptr = NULL;
- /**********************************************************
- *
- * Functionality hooks.
- *
- * - _DTENV_SUPPORT_COMMA_SEPARATED - turn on code that
- * special cases some environment variables and
- * treats them as comma separated and possibly
- * host qualified.
- *
- * - _DTENV_SUPPORT_MAPERROR_CACHING - turn on code that
- * would cache error codes when mapping files in
- * addition to caching successfully mapped files.
- * In configurations where mapping errors are
- * common, this could be a big help, but on the
- * downside, a mapping error that is the result
- * of a temporary network error (for example)
- * could get locked into a cache.
- *
- * - _DTENV_OPTIMIZATION_LOCALHOST - turn on code that
- * would prevent even trying to map/cache environment
- * variables if the targetHost was the localhost.
- */
- #define _DTENV_SUPPORT_COMMA_SEPARATED 1
- #undef _DTENV_SUPPORT_MAPERROR_CACHING
- #undef _DTENV_OPTIMIZATION_LOCALHOST
- /**********************************************************
- *
- * Performance hooks.
- *
- * - DTENV_PERF_HOOK - instrunment file mapping code for
- * performance measuring.
- */
- #undef DTENV_PERF_HOOK
- #ifdef DTENV_PERF_HOOK
- #include <time.h>
- int stopwatch_repeat_rate = 10;
- unsigned long stopwatch_tt_file_netfile;
- unsigned long stopwatch_tt_netfile_file;
- #endif /* DTENV_PERF_HOOK */
- /******************************************************************************
- ******************************************************************************
- **
- ** _DtEnv_tt_file_netfile()
- ** _DtEnv_tt_netfile_file()
- **
- ** Both are caching versions built on the non-caching Tooltalk versions.
- **
- ** The one flaw in both is that if the filesystem topology changes
- ** (eg, NFS mounts, symlinks, etc), old and incorrect mapping information
- ** may be returned. To minimize this, a cached mapping will only be used
- ** so many times before being recomputed. An alternative (not implemented
- ** here) would be to recompute based on age of the mapping via
- ** gettimeofday().
- **
- ** ******************* XXX Alert **************************
- **
- ** Tooltalk currently allocates a range of char*'s
- ** and then associates them with a range of error
- ** messages (ala tt_ptr_error()). In effect, the
- ** allocated char*'s become constants within Tooltalk.
- **
- ** This code takes this into account when returning
- ** values. Non-reserved char*'s are strdup()ed
- ** often, while reserved char*'s are not to preserve
- ** their ptr value.
- **
- ** tjg: Other than differing cache repositories, all the onion-skin
- ** routines below look the same. Probably better to have one
- ** core routine to minimize code size.
- **/
- /*
- * Per cache setup (ie, one for _DtEnv_tt_file_netfile(), one for
- * _DtEnv_tt_netfile_file()), start off by caching SIZE_START
- * mappings, growing by SIZE_BUMP as needed, while limiting the
- * total cache growth to SIZE_MAX mappings.
- */
- #define CACHE_FILEFRAG_SIZE_START 15
- #define CACHE_FILEFRAG_SIZE_BUMP 15
- #define CACHE_FILEFRAG_SIZE_MAX 45
- /*
- * After a cached mapping is used REMAP_AFTER times, age it out
- * and force a recomputation of the mapping from scratch.
- */
- #define CACHE_FILEFRAG_REMAP_AFTER 25
- /*
- * After RESET_PRI hits on a cache of size SIZE_MAX, reset all
- * cacheHit counters. This will allow new mappings to work into
- * the cache against mappings that might have been popular long
- * ago.
- */
- #define CACHE_FILEFRAG_RESET_PRI 200
- /******************************************************************************
- *
- * _DtEnv_tt_file_netfile()
- *
- * A caching version of tt_file_netfile().
- */
- typedef struct {
- char *pathFragOrig; /* eg, /usr/dt */
- char *pathFragMapped; /* eg, <from tt_file_netfile> */
- int cacheHit; /* usage of */
- } cachedFileFrag;
- char *_DtEnv_tt_file_netfile(
- const char *filename)
- {
- static int first_time = 1;
- static int fragListAvail = CACHE_FILEFRAG_SIZE_START;
- static int fragListCnt = 0;
- static cachedFileFrag *fragList;
- static int cacheGen = 0;
- static int hitIdxStart = 0;
- char *netpath;
- int hitval, hitIdx, i;
- cachedFileFrag *tmpCffP;
- char *tmpStr;
- int newCount = fragListCnt;
- _DtSvcProcessLock();
- if (first_time) {
- fragList = (cachedFileFrag *) calloc( fragListAvail,
- sizeof(cachedFileFrag) );
- first_time = 0;
- }
- /*
- * Take care of the obvious.
- */
- if (!filename) {
- _DtSvcProcessUnlock();
- return( (char *) NULL );
- }
- /*
- * Look for existing answer in cache.
- *
- * While at it, also look for least used entry just in case.
- */
- if (fragListCnt)
- hitIdxStart = (hitIdxStart + 7) % fragListCnt;
- else
- hitIdxStart = 0;
- hitIdx = hitIdxStart;
- hitval = fragList[hitIdx].cacheHit;
- tmpCffP = fragList; /* walk rather than index */
- for ( i = 0; i < fragListCnt; i++ ) {
- if (tmpCffP->cacheHit && !strcmp( filename, tmpCffP->pathFragOrig ) ) {
- break;
- }
- if (tmpCffP->cacheHit < hitval) {
- hitIdx = i;
- hitval = tmpCffP->cacheHit;
- }
- tmpCffP++;
- }
- /*
- * Decide what was found.
- */
- if ( i != fragListCnt ) {
- /*
- * Found a cached entry.
- */
- hitIdx = i;
- if ( fragList[hitIdx].cacheHit++ > CACHE_FILEFRAG_REMAP_AFTER ) {
- /*
- * This looks like an old entry, so re-compute it.
- */
- freeAndNull( fragList[hitIdx].pathFragOrig );
- ttfreeAndNull( fragList[hitIdx].pathFragMapped );
- fragList[hitIdx].cacheHit = 0; /* 0 means remap below */
- }
- }
- else {
- /*
- * Did not find a cache entry, so scrounge around for
- * a new entry.
- */
- if ( fragListCnt < fragListAvail ) {
- /*
- * Use next already-malloc'ed cacheEntry.
- */
- hitIdx = fragListCnt;
- newCount = fragListCnt + 1;
- }
- else if ( fragListCnt < CACHE_FILEFRAG_SIZE_MAX ) {
- /*
- * Can grow fragList[]
- */
- fragListAvail += CACHE_FILEFRAG_SIZE_BUMP;
- fragList = (cachedFileFrag *) realloc( (char *) fragList,
- sizeof(cachedFileFrag) * fragListAvail);
- /*
- * Zero out new memory.
- */
- memset( fragList + (fragListAvail-CACHE_FILEFRAG_SIZE_BUMP),
- 0, CACHE_FILEFRAG_SIZE_BUMP*sizeof(cachedFileFrag) );
- hitIdx = fragListCnt;
- newCount = fragListCnt + 1;
- }
- else {
- /*
- * Last resort - bump out the least used entry.
- */
- freeAndNull( fragList[hitIdx].pathFragOrig );
- ttfreeAndNull( fragList[hitIdx].pathFragMapped );
- /*
- * Since the cache is 100% full, occasionally reset
- * everyone's cacheHit rate so entries that were only
- * popular long ago don't get locked in.
- */
- if ( cacheGen++ > CACHE_FILEFRAG_RESET_PRI ) {
- cacheGen = 0;
- tmpCffP = fragList;
- for ( i = 0; i < fragListCnt; i++ ) {
- tmpCffP->cacheHit = 1;
- tmpCffP++;
- }
- }
- }
- fragList[hitIdx].cacheHit = 0; /* 0 means remap below */
- }
- if ( ! fragList[hitIdx].cacheHit ) {
- /*
- * Need to perform mapping.
- */
- netpath = tt_file_netfile( filename );
- #ifdef _DTENV_SUPPORT_MAPERROR_CACHING
- fragList[hitIdx].pathFragOrig = strdup( filename );
- fragList[hitIdx].cacheHit = 1;
- fragList[hitIdx].pathFragMapped = netpath;
- fragListCnt = newCount;
- #else
- if ( tt_ptr_error(netpath) == TT_OK ) {
- fragList[hitIdx].pathFragOrig = strdup( filename );
- fragList[hitIdx].cacheHit = 1;
- fragList[hitIdx].pathFragMapped = netpath;
-
- /*
- * Only change the count if we are successful in adding
- * a new entry.
- */
- fragListCnt = newCount;
- }
- else {
- /*
- * Don't cache errors. Leave this cache slot empty
- * and it will be rediscovered and used in the future.
- */
- fragList[hitIdx].cacheHit = 0;
- /*
- * Do not change the fragListCount since we don't want to
- * add in error entries.
- */
- }
- #endif /* _DTENV_SUPPORT_MAPERROR_CACHING */
- }
- /*
- * Dig out answer and return it.
- */
- #ifdef _DTENV_SUPPORT_MAPERROR_CACHING
- if ( tt_ptr_error(netpath) == TT_OK )
- #else
- if ( fragList[hitIdx].cacheHit )
- #endif /* _DTENV_SUPPORT_MAPERROR_CACHING */
- {
- /*
- * Return a tt_free-able copy of the answer.
- */
- tmpStr = tt_malloc( strlen(fragList[hitIdx].pathFragMapped) + 1 );
- strcpy( tmpStr, fragList[hitIdx].pathFragMapped );
- _DtSvcProcessUnlock();
- return(tmpStr);
- }
- else {
- /*
- * See XXX comment.
- *
- * Since netpath is an error code, return as is.
- */
- _DtSvcProcessUnlock();
- return(netpath);
- }
- }
- /******************************************************************************
- *
- * _DtEnv_tt_netfile_file()
- *
- * A caching version of tt_netfile_file().
- */
- typedef struct {
- char *targetHost;
- char *pathFragOrig; /* eg, <from tt_file_netfile> */
- char *pathFragMapped; /* eg, /nfs/hostb/usr/dt */
- int cacheHit; /* usage of */
- } cachedNetfileFrag;
- char *_DtEnv_tt_host_netfile_file(
- const char *host,
- const char *filename)
- {
- static int first_time = 1;
- static int fragListAvail = CACHE_FILEFRAG_SIZE_START;
- static int fragListCnt = 0;
- static cachedNetfileFrag *fragList;
- static int cacheGen = 0;
- static int hitIdxStart = 0;
- char *newfile;
- int hitval, hitIdx, i;
- cachedNetfileFrag *tmpCffP;
- char *tmpStr;
- int newCount = fragListCnt;
- _DtSvcProcessLock();
- if (first_time) {
- fragList = (cachedNetfileFrag *) calloc( fragListAvail,
- sizeof(cachedNetfileFrag) );
- first_time = 0;
- }
- /*
- * Take care of the obvious.
- */
- if (!filename) {
- _DtSvcProcessUnlock();
- return( (char *) NULL );
- }
- if (!host) {
- /*
- * Return a tt_free-able un-mapped copy.
- */
- tmpStr = tt_malloc( strlen(filename) + 1 );
- strcpy( tmpStr, filename );
- _DtSvcProcessUnlock();
- return(tmpStr);
- }
- /*
- * Look for existing answer in cache.
- *
- * While at it, also look for least used entry just in case.
- */
- if (fragListCnt)
- hitIdxStart = (hitIdxStart + 7) % fragListCnt;
- else
- hitIdxStart = 0;
- hitIdx = hitIdxStart;
- hitval = fragList[hitIdx].cacheHit;
- tmpCffP = fragList; /* walk rather than index */
- for ( i = 0; i < fragListCnt; i++ ) {
- if (tmpCffP->cacheHit && !strcmp( filename, tmpCffP->pathFragOrig ) ) {
- if (!strcmp( host, tmpCffP->targetHost ) ) {
- break;
- }
- }
- /*
- * Save index of least used entry
- */
- if (tmpCffP->cacheHit < hitval) {
- hitIdx = i;
- hitval = tmpCffP->cacheHit;
- }
- tmpCffP++;
- }
- /*
- * Decide what was found.
- */
- if ( i != fragListCnt ) {
- /*
- * Found a cached entry.
- */
- hitIdx = i;
- if ( fragList[hitIdx].cacheHit++ > CACHE_FILEFRAG_REMAP_AFTER ) {
- /*
- * This looks like an old entry, so re-compute it.
- */
- freeAndNull( fragList[hitIdx].targetHost );
- freeAndNull( fragList[hitIdx].pathFragOrig );
- ttfreeAndNull( fragList[hitIdx].pathFragMapped );
- fragList[hitIdx].cacheHit = 0; /* 0 means remap below */
- }
- }
- else {
- /*
- * Did not find a cache entry, so scrounge around for
- * a new entry.
- */
- if ( fragListCnt < fragListAvail ) {
- /*
- * Use next already-malloc'ed cacheEntry.
- */
- hitIdx = fragListCnt;
- newCount = fragListCnt + 1;
- }
- else if ( fragListCnt < CACHE_FILEFRAG_SIZE_MAX ) {
- /*
- * Can grow fragList[]
- */
- fragListAvail += CACHE_FILEFRAG_SIZE_BUMP;
- fragList = (cachedNetfileFrag *) realloc( (char *) fragList,
- sizeof(cachedNetfileFrag) * fragListAvail);
- /*
- * Zero out new memory.
- */
- memset( fragList + (fragListAvail-CACHE_FILEFRAG_SIZE_BUMP),
- 0, CACHE_FILEFRAG_SIZE_BUMP*sizeof(cachedNetfileFrag) );
- hitIdx = fragListCnt;
- newCount = fragListCnt + 1;
- }
- else {
- /*
- * Last resort - bump out the least used entry.
- */
- freeAndNull( fragList[hitIdx].targetHost );
- freeAndNull( fragList[hitIdx].pathFragOrig );
- ttfreeAndNull( fragList[hitIdx].pathFragMapped );
- /*
- * Since the cache is 100% full, occasionally reset
- * everyone's cacheHit rate so entries that were only
- * popular long ago don't get locked in.
- */
- if ( cacheGen++ > CACHE_FILEFRAG_RESET_PRI ) {
- cacheGen = 0;
- tmpCffP = fragList;
- for ( i = 0; i < fragListCnt; i++ ) {
- tmpCffP->cacheHit = 1;
- tmpCffP++;
- }
- }
- }
- fragList[hitIdx].cacheHit = 0; /* 0 means remap below */
- }
- if ( ! fragList[hitIdx].cacheHit ) {
- /*
- * Need to perform mapping.
- */
- newfile = tt_host_netfile_file( host, filename );
- #ifdef _DTENV_SUPPORT_MAPERROR_CACHING
- fragList[hitIdx].targetHost = strdup ( host );
- fragList[hitIdx].pathFragOrig = strdup( filename );
- fragList[hitIdx].cacheHit = 1;
- fragList[hitIdx].pathFragMapped = newfile;
- fragListCnt = newCount;
- #else
- if ( tt_ptr_error(newfile) == TT_OK ) {
- fragList[hitIdx].targetHost = strdup ( host );
- fragList[hitIdx].pathFragOrig = strdup( filename );
- fragList[hitIdx].cacheHit = 1;
- fragList[hitIdx].pathFragMapped = newfile;
- /*
- * Only change the count if we are successful in adding
- * a new entry.
- */
- fragListCnt = newCount;
- }
- else {
- /*
- * Don't cache errors. Leave this cache slot empty
- * and it will be rediscovered and used in the future.
- */
- fragList[hitIdx].cacheHit = 0;
- /*
- * Do not change the fragListCount since we are not saving
- * error entries.
- */
- }
- #endif /* _DTENV_SUPPORT_MAPERROR_CACHING */
- }
- /*
- * Dig out answer and return it.
- */
- #ifdef _DTENV_SUPPORT_MAPERROR_CACHING
- if ( tt_ptr_error(newfile) == TT_OK )
- #else
- if ( fragList[hitIdx].cacheHit )
- #endif /* _DTENV_SUPPORT_MAPERROR_CACHING */
- {
- /*
- * Return a tt_free-able copy of the answer.
- */
- tmpStr = tt_malloc( strlen(fragList[hitIdx].pathFragMapped) + 1 );
- strcpy( tmpStr, fragList[hitIdx].pathFragMapped );
- _DtSvcProcessUnlock();
- return(tmpStr);
- }
- else {
- /*
- * See XXX comment.
- *
- * Since newfile is an error code, return as is.
- */
- _DtSvcProcessUnlock();
- return(newfile);
- }
- }
- /******************************************************************************
- ******************************************************************************
- **
- ** Environment variable mapping code.
- **
- */
- /******************************************************************************
- *
- * _DtEnvGetMapList()
- *
- * Fetch the environment variable who's value is a colon separated list
- * of environment variable names who's values need to be mapped. Then
- * break down the list into an indexable array.
- */
- static char **_DtEnvGetMapList(
- char *mapListStr,
- int *mapListCount)
- {
- char **mapList; /* decomposition of above */
- char *tmpPtr, *tmpPtr2;
- int availListSize;
- int firstTime;
- _Xstrtokparams strtok_buf;
- /*
- * Handle NULL mapListStr.
- */
- *mapListCount = 0;
- if ( !mapListStr ) {
- return( (char **) NULL );
- }
- /*
- * Create a block of string pointers - remalloc() as needed.
- */
- availListSize = MALLOC_BUMP_SIZE;
- mapList = (char **) malloc( sizeof(char *) * (availListSize) );
- /*
- * Break up the colon separated string into an indexable array.
- */
- tmpPtr = strdup(mapListStr); /* work copy for strtok */
- firstTime = 1;
- while (1) {
- if (firstTime) {
- tmpPtr2 = _XStrtok( tmpPtr, ":", strtok_buf );
- firstTime = 0;
- }
- else
- tmpPtr2 = _XStrtok( (char *) NULL, ":", strtok_buf );
- if (tmpPtr2) {
- /*
- * Have possible env var name to map - make sure it exists.
- */
- if ( getenv(tmpPtr2) ) {
- (*mapListCount)++;
- if (*mapListCount > availListSize) {
- availListSize += MALLOC_BUMP_SIZE;
- mapList = (char **) realloc( (char *) mapList,
- sizeof(char *) * (availListSize) );
- }
- mapList[*mapListCount-1] = strdup(tmpPtr2);
- }
- }
- else {
- break;
- }
- }
- free(tmpPtr);
- return( (char **) mapList );
- }
- /******************************************************************************
- *
- * _DtEnvCleanCacheSlot()
- *
- * Free up all memory associated with a cache slot for a targetHost.
- */
- static void _DtEnvCleanCacheSlot( cacheForTargetHost *targetCache )
- {
- int i;
- freeAndNull( targetCache->remoteHost );
- targetCache->cacheHit = 1;
- freeAndNull( targetCache->mapListStr );
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- freeAndNull( targetCache->mapList[i] );
- freeAndNull( targetCache->mapListDetails[i].localEnvVarCopy );
- freeAndNull( targetCache->mapListDetails[i].mappedEnvVarPtr );
- /* do not free .localEnvVarPtr - belongs to environ */
- }
- freeAndNull( targetCache->mapList );
- targetCache->mapListCnt = 0;
- }
- /******************************************************************************
- *
- * _DtEnvGetTargetCache()
- *
- * For a specified targetHost, find existing cache information and
- * optionally create a cache for a targetHost if one doesn't exist.
- *
- * The define MAX_HOSTS_CACHED controls how many targetHosts can
- * be cached.
- */
- static cacheForTargetHost *_DtEnvGetTargetCache(
- char *targetHost,
- int createIfNeeded)
- {
- static int cacheHitGen = 0;
- static int hitIdxStart;
- int i, hitidx, hitval;
- /*
- * Handle obvious.
- */
- if (!targetHost) {
- return( (cacheForTargetHost *) NULL );
- }
- _DtSvcProcessLock();
- /*
- * Look for targetHost in current cache pool.
- */
- for ( i = 0; i < MAX_HOSTS_CACHED; i++ ) {
- if ( cachePoolG[i].remoteHost ) {
- if ( !strcmp( targetHost, cachePoolG[i].remoteHost ) ) {
- cachePoolG[i].cacheHit++;
- break;
- }
- }
- }
- if ( i != MAX_HOSTS_CACHED ) {
- /*
- * targetHost is in a cache slot already.
- */
- _DtSvcProcessUnlock();
- return( &cachePoolG[i] );
- }
- else if ( !createIfNeeded ) {
- /*
- * No cache slot for, and we shouldn't create one either.
- */
- _DtSvcProcessUnlock();
- return( (cacheForTargetHost *) NULL );
- }
- else {
- /*
- * Find an empty cache slot or take over a rarely used slot.
- */
- hitIdxStart = (hitIdxStart + 7) % MAX_HOSTS_CACHED;
- hitidx = hitIdxStart;
- hitval = cachePoolG[hitidx].cacheHit;
- for ( i = 0; i < MAX_HOSTS_CACHED; i++ ) {
- if ( ! cachePoolG[i].remoteHost ) {
- /*
- * Empty slot - take it.
- */
- hitidx = i;
- break;
- }
- else if ( cachePoolG[i].cacheHit < hitval ) {
- hitidx = i;
- hitval = cachePoolG[i].cacheHit;
- }
- }
- if ( cachePoolG[hitidx].remoteHost ) {
- /*
- * Cache was in use, clean first.
- */
- _DtEnvCleanCacheSlot( &cachePoolG[hitidx] );
- cachePoolG[hitidx].remoteHost = strdup( targetHost );
- /*
- * Since all the slots are full, occasionally reset everyones
- * cacheHit counters. This gives new targetHosts a chance
- * to compete with targetHosts that were popular long ago.
- */
- if ( cacheHitGen++ > 50 ) {
- for ( i = 0; i < MAX_HOSTS_CACHED; i++ ) {
- cachePoolG[i].cacheHit = 1;
- }
- cacheHitGen = 1;
- }
- }
- _DtSvcProcessUnlock();
- return( &cachePoolG[hitidx] );
- }
- }
- /******************************************************************************
- *
- * _DtEnvMapIt()
- *
- * Fill out a map cache for a single environment variable.
- */
- static void _DtEnvMapIt(
- char *envVar,
- cachedEnvVar *envVarCache,
- char *targetHost)
- {
- char *separator, *tmpPtr, *tmpPtr2, swapout, *netpath;
- char *prePend, *postPend, *newPrePend;
- char **pathList;
- int availPathListSize, pathListCount, availEnvStrSize, len, tmpi, i;
- int considerMapping;
- _Xstrtokparams strtok_buf;
- /*
- * Information Layout:
- *
- * localEnvVarPtr = ptr to original "PATH=/users/foo:/users/bar"
- * localEnvVarCopy = copy of original "/users/foo:/users/bar"
- * mappedEnvVarPtr = mapped "PATH=/nfs/.../users/foo:/nfs/.../users/bar"
- */
- if ( (envVarCache->localEnvVarPtr = getenv( envVar )) ) {
- envVarCache->localEnvVarCopy = strdup( envVarCache->localEnvVarPtr );
- /* sneak back past "NAME=" portion. */
- envVarCache->localEnvVarPtr -= strlen( envVar ) + 1;
- }
- else {
- /*
- * Nothing to map. Punt.
- */
- envVarCache->localEnvVarCopy = (char *) NULL;
- envVarCache->localEnvVarPtr = (char *) NULL;
- return;
- }
- #ifdef _DTENV_SUPPORT_COMMA_SEPARATED
- /*
- * Pick between colon-separated and comma-separated host-qualified
- * mapping code.
- */
- if ( !strcmp(envVar, "DTDATABASESEARCHPATH") ) {
- /*
- * comma-separated and host-qualified mapping.
- */
- separator = ",";
- }
- else {
- /*
- * colon-separated mapping.
- */
- separator = ":";
- }
- #else
- separator = ":";
- #endif /* _DTENV_SUPPORT_COMMA_SEPARATED */
- /*
- * Break path list into elements
- */
- availPathListSize = MALLOC_BUMP_SIZE;
- pathListCount = 0;
- pathList = (char **) malloc( sizeof(char *) * availPathListSize );
- /*
- * Break up path list into an array of path elements.
- */
- tmpPtr = strdup( envVarCache->localEnvVarCopy ); /* work copy */
- while (1) {
- if (!pathListCount)
- tmpPtr2 = _XStrtok( tmpPtr, separator, strtok_buf );
- else
- tmpPtr2 = _XStrtok( (char *) NULL, separator, strtok_buf );
- if (tmpPtr2) {
- pathListCount++;
- if (pathListCount > availPathListSize) {
- availPathListSize += MALLOC_BUMP_SIZE;
- pathList = (char **) realloc( (char *) pathList,
- sizeof(char *) * availPathListSize );
- }
- pathList[pathListCount-1] = strdup( tmpPtr2 );
- }
- else {
- break;
- }
- }
- free( tmpPtr );
- /*
- * Setup new "NAME=....." string.
- */
- availEnvStrSize = strlen( envVar ) + 64;
- envVarCache->mappedEnvVarPtr = (char *) calloc( availEnvStrSize, sizeof(char) );
- strcpy( envVarCache->mappedEnvVarPtr, envVar );
- strcat( envVarCache->mappedEnvVarPtr, "=" );
- /*
- * Start mapping each path element.
- */
- for ( i = 0; i < pathListCount; i++ ) {
- prePend = pathList[i];
- postPend = (char *) NULL;
- newPrePend = (char *) NULL;
- /*
- * Assume we need to map this path element.
- */
- considerMapping = 1;
- #ifdef _DTENV_SUPPORT_COMMA_SEPARATED
- if ( !strcmp( separator, "," ) ) {
- if ( DtStrchr(prePend, ':' ) ) {
- /*
- * Host qualified elements in a comma separated list
- * will NOT be mapped.
- */
- considerMapping = 0;
- }
- }
- #endif /* _DTENV_SUPPORT_COMMA_SEPARATED */
- if (considerMapping) {
- /*
- * Tear apart and check for so called substitution characters.
- */
- if (( tmpPtr = DtStrchr(prePend, '%') )) {
- /*
- * Temporarly shorten path up to substitution character.
- */
- swapout = *tmpPtr;
- *tmpPtr = '\0';
- /*
- * Move the dividing point back to a directory element.
- */
- tmpPtr2 = DtStrrchr( prePend, '/' );
- /*
- * Restore the send half of the string.
- */
- *tmpPtr = swapout;
- if (tmpPtr2) {
- /*
- * Can do a split around the "/".
- *
- * Will have "<prePath>/" and "/<postPath>".
- */
- postPend = strdup( tmpPtr2 );
- *(tmpPtr2 + mblen(tmpPtr2, MB_CUR_MAX)) = '\0';
- }
- }
- #ifdef DTENV_PERF_HOOK
- {
- int tpi;
- extern unsigned long stopwatch_tt_file_netfile;
- extern int stopwatch_repeat_rate;
- struct timeval start, stop;
- struct timezone junk;
- gettimeofday( &start, &junk );
- for ( tpi = 0; tpi < stopwatch_repeat_rate-1; tpi++ ) {
- netpath = _DtEnv_tt_file_netfile( prePend );
- if ( tt_ptr_error(netpath) == TT_OK )
- ttfreeAndNull( netpath );
- }
- netpath = _DtEnv_tt_file_netfile( prePend );
- gettimeofday( &stop, &junk );
- if (start.tv_usec > stop.tv_usec) {
- stop.tv_usec += 1000000;
- stop.tv_sec--;
- }
- stopwatch_tt_file_netfile += (stop.tv_usec - start.tv_usec);
- stopwatch_tt_file_netfile += (stop.tv_sec - start.tv_sec) * 1000000;
- }
- #else
- netpath = _DtEnv_tt_file_netfile( prePend );
- #endif /* DTENV_PERF_HOOK */
- if ( tt_ptr_error(netpath) != TT_OK ) {
- newPrePend = (char *) NULL;
- }
- else {
- #ifdef DTENV_PERF_HOOK
- {
- int tpi;
- extern unsigned long stopwatch_tt_netfile_file;
- extern int stopwatch_repeat_rate;
- struct timeval start, stop;
- struct timezone junk;
- gettimeofday( &start, &junk );
- for ( tpi = 0; tpi < stopwatch_repeat_rate-1; tpi++ ) {
- newPrePend = _DtEnv_tt_host_netfile_file (targetHost, netpath);
- if ( tt_ptr_error(newPrePend) == TT_OK )
- ttfreeAndNull( newPrePend );
- }
- newPrePend = _DtEnv_tt_host_netfile_file (targetHost, netpath);
- gettimeofday( &stop, &junk );
- if (start.tv_usec > stop.tv_usec) {
- stop.tv_usec += 1000000;
- stop.tv_sec--;
- }
- stopwatch_tt_netfile_file += (stop.tv_usec - start.tv_usec);
- stopwatch_tt_netfile_file += (stop.tv_sec - start.tv_sec) * 1000000;
- }
- #else
- newPrePend = _DtEnv_tt_host_netfile_file (targetHost, netpath);
- #endif /* DTENV_PERF_HOOK */
- if ( tt_ptr_error(newPrePend) != TT_OK ) {
- newPrePend = (char *) NULL;
- }
- ttfreeAndNull( netpath );
- }
- }
- /*
- * Calculate length of the new path element to the new path list.
- */
- tmpi = strlen(envVarCache->mappedEnvVarPtr)+1; /* current list + ... */
- if ( i != 0 )
- tmpi += 1; /* separator */
- if (newPrePend)
- tmpi += strlen(newPrePend); /* new prePend or ... */
- else
- tmpi += strlen(prePend); /* ... old prePend */
- if (postPend)
- tmpi += strlen(postPend); /* new postPend */
- if ( tmpi > availEnvStrSize ) {
- /*
- * Grow new mappedEnvVar space.
- */
- availEnvStrSize = tmpi + 64;
- envVarCache->mappedEnvVarPtr = (char *) realloc(
- (char *) envVarCache->mappedEnvVarPtr,
- availEnvStrSize );
- }
- /*
- * Add the new path element.
- */
- if ( i != 0 )
- strcat( envVarCache->mappedEnvVarPtr, separator );
- if (newPrePend)
- strcat( envVarCache->mappedEnvVarPtr, newPrePend );
- else
- strcat( envVarCache->mappedEnvVarPtr, prePend );
- if (postPend)
- strcat( envVarCache->mappedEnvVarPtr, postPend );
- freeAndNull( prePend ); /* aka pathList[i] */
- ttfreeAndNull( newPrePend );
- freeAndNull( postPend );
- }
- freeAndNull( pathList );
- }
- /******************************************************************************
- *
- * _DtEnvGetMapInformation()
- */
- #define _DtEnv_MAX_BUF_SIZE 1024
- #define _DtEnv_NULL_GUARD(s) ((s) ? (s) : "")
- static char *_DtEnvGetMapInformation( void )
- {
- char *mapInfo;
- char nameBuf[_DtEnv_MAX_BUF_SIZE];
- char classBuf[_DtEnv_MAX_BUF_SIZE];
- XrmValue resource_value;
- XrmDatabase db;
- char *rep_type;
- int bytesNeeded;
- char *name;
- char *class;
- extern char *_DtApplicationName; /* set in DtUtil.c */
- extern char *_DtApplicationClass;
- extern Display *_DtDisplay;
- /*
- * See if an environment variable has been set. If so, get
- * the map info from there.
- */
- mapInfo = getenv( _DTENV_MAP_ENV_VAR );
- if (mapInfo)
- return( XtNewString( mapInfo ) );
- /*
- * Try to get map info from the resource database.
- */
- bytesNeeded = strlen(_DTENV_MAP_RESOURCE_NAME)
- + strlen(_DtApplicationName) + 4;
- if ( bytesNeeded > _DtEnv_MAX_BUF_SIZE )
- name = XtMalloc(bytesNeeded);
- else
- name = nameBuf;
- sprintf (name, "%s*%s",
- _DtEnv_NULL_GUARD( _DtApplicationName) , _DTENV_MAP_RESOURCE_NAME);
- bytesNeeded = strlen(_DTENV_MAP_RESOURCE_CLASS)
- + strlen(_DtApplicationClass) + 4;
- if ( bytesNeeded > _DtEnv_MAX_BUF_SIZE )
- class = XtMalloc(bytesNeeded);
- else
- class = classBuf;
- sprintf (class, "%s*%s",
- _DtEnv_NULL_GUARD(_DtApplicationClass) , _DTENV_MAP_RESOURCE_CLASS);
- db = XtDatabase (_DtDisplay);
- if (XrmGetResource (db, nameBuf, classBuf, &rep_type, &resource_value))
- mapInfo = (char *) resource_value.addr;
- else
- mapInfo = (char *) NULL;
- if ( name != nameBuf )
- XtFree(name);
- if ( class != classBuf )
- XtFree(class);
- if (mapInfo)
- return( XtNewString( mapInfo ) );
- else
- return( (char *) NULL );
- }
- /******************************************************************************
- *
- * _DtEnvMapForRemote()
- *
- * Perform filename mapping on the current environment so it makes
- * sense on the target host. The original environment is saved
- * for later restoring, and caching is used to minimize mapping
- * computations.
- */
- void _DtEnvMapForRemote (char *targetHost)
- {
- int i, cacheRegen;
- char *mapListStr, *tmpPtr;
- char **mapList;
- cacheForTargetHost *targetCache;
- int ttMark = 0;
- extern char *mostRecentRemoteHostG;
- _DtSvcProcessLock();
- if (mostRecentRemoteHostG) {
- /*
- * Warning - a _DtEnvRestoreLocal() was not called for
- * the most recent _DtEnvMapForRemote(). Tossing.
- */
- freeAndNull(mostRecentRemoteHostG);
- }
- if (!targetHost) {
- /*
- * No target host to cache.
- */
- _DtSvcProcessUnlock();
- return;
- }
- /*
- * Performance enhancement: Check if we can map our $HOME directory
- * to the remote host. If we fail because the host cannot be accessed
- * then give up the attempt to map the environment now because we'll
- * run into a lot of timeouts on remote mapping failures otherwise.
- */
- ttMark = tt_mark();
- switch ( tt_ptr_error(
- _DtEnv_tt_host_netfile_file(targetHost,
- _DtEnv_tt_file_netfile(getenv("HOME")) ) ) )
- {
- case TT_ERR_DBEXIST: /* cannot contact remote host */
- case TT_ERR_DBAVAIL: /* timeouts occur trying to make contact */
- case TT_ERR_UNIMP: /* remote server doesn't support file naming */
- /*
- * It will do no good to attempt to map filenames to this remote host
- * So forget it -- the user may try again later.
- */
- tt_release(ttMark); /* free up tooltalk memory used for test */
- _DtSvcProcessUnlock();
- return;
- break;
- default:
- tt_release(ttMark); /* free up tooltalk memory used for test */
- break;
- }
- #ifdef _DTENV_OPTIMIZATION_LOCALHOST
- /*
- * _DtEnvMapForRemote() is normally called from the remote execution
- * code within libDtSvc. If by chance it gets called when spawning
- * local processes, then a test should be done here to bypass mapping
- * environment variables for a local fork/exec.
- */
- if ( <unimplemented - targetHost is local test> ) {
- mostRecentRemoteHostG = "localhost";
- _DtSvcProcessUnlock();
- return;
- }
- #endif /* _DTENV_OPTIMIZATION_LOCALHOST */
- /*
- * Get list of env vars to be mapped.
- */
- mapListStr = _DtEnvGetMapInformation();
- if (!mapListStr) {
- /*
- * Nothing to map.
- */
- _DtSvcProcessUnlock();
- return;
- }
- /*
- * We have a targetHost that needs some mapping done. Start
- * stashing data away.
- */
- mostRecentRemoteHostG = strdup( targetHost );
- _DtSvcProcessUnlock();
- /*
- * Find or allocate a cache entry.
- */
- targetCache = _DtEnvGetTargetCache( targetHost, 1 );
- /*
- * See if cache information for targetHost is available, and
- * if so, if it still looks valid.
- *
- * To maximize performance, an all-or-nothing regeneration of
- * the cache will be done rather than incremental regeneration
- * of some portions of the cache. One would expect that the
- * list of variables to map and their contents would remain
- * fairly static.
- */
- if (targetCache->mapListStr) {
- if ( !strcmp( targetCache->mapListStr, mapListStr ) ) {
- /*
- * Atleast the list of environment variables that need
- * to be mapped is the same as previous.
- */
- cacheRegen = 0;
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- if (( tmpPtr = getenv(targetCache->mapList[i]) )) {
- if ( strcmp( tmpPtr,
- targetCache->mapListDetails[i].localEnvVarCopy) ) {
- cacheRegen = 1; /* one map entry is no longer valid */
- break;
- }
- }
- else {
- /*
- * Env Var does not exist, but maybe it never did.
- */
- if (targetCache->mapListDetails[i].localEnvVarCopy) {
- /*
- * Was in cache, but now no longer exists.
- */
- cacheRegen = 1; /* env var no longer exists */
- break;
- }
- }
- }
- }
- else {
- cacheRegen = 1; /* map list changed - need to regen cache */
- }
- }
- else {
- cacheRegen = 1; /* need to create cache */
- }
- if (cacheRegen) {
- /*
- * Toss out the old.
- */
- _DtEnvCleanCacheSlot(targetCache);
- /*
- * Bring in the new.
- */
- targetCache->remoteHost = strdup( targetHost );
- targetCache->mapListStr = strdup( mapListStr );
- targetCache->mapList = _DtEnvGetMapList( mapListStr,
- &(targetCache->mapListCnt) );
- targetCache->mapListDetails = (cachedEnvVar *)
- malloc( sizeof(cachedEnvVar) *
- targetCache->mapListCnt );
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- _DtEnvMapIt( targetCache->mapList[i],
- &(targetCache->mapListDetails[i]),
- targetHost );
- }
- }
- else {
- /*
- * We can use cached information. Even though all the
- * environment variable "strings" match, the users
- * (environ **) pointers may be different, so re-cache
- * the restoration pointers.
- */
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- if (( targetCache->mapListDetails[i].localEnvVarPtr =
- getenv( targetCache->mapList[i] ) )) {
- targetCache->mapListDetails[i].localEnvVarPtr -=
- strlen( targetCache->mapList[i] ) + 1;
- }
- }
- }
- /*
- * Install the mapped environment variables.
- */
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- putenv( targetCache->mapListDetails[i].mappedEnvVarPtr );
- }
- XtFree(mapListStr);
- }
- /******************************************************************************
- *
- * _DtEnvRestoreLocal()
- *
- * Presuming a _DtEnvMapForRemote() was called, _DtEnvRestoreLocal()
- * restores the original envirnment settings for a number of
- * environment variables.
- */
- void _DtEnvRestoreLocal (void)
- {
- extern char *mostRecentRemoteHostG;
- cacheForTargetHost *targetCache;
- char *tmpP;
- int i;
- _DtSvcProcessLock();
- if (mostRecentRemoteHostG) {
- #ifdef _DTENV_OPTIMIZATION_LOCALHOST
- /*
- * See comment with the other ifdef'ed block.
- *
- * If localhost, then nothing to restore.
- */
- if ( !strcmp(mostRecentRemoteHostG, "localhost") ) {
- mostRecentRemoteHostG = (char *) NULL;
- _DtSvcProcessUnlock();
- return;
- }
- #endif /* _DTENV_OPTIMIZATION_LOCALHOST */
- targetCache = _DtEnvGetTargetCache( mostRecentRemoteHostG, 0 );
- if (targetCache) {
- /*
- * Install the mapped environment variables.
- */
- for ( i = 0; i < targetCache->mapListCnt; i++ ) {
- tmpP = targetCache->mapListDetails[i].localEnvVarPtr;
- if ( tmpP ) {
- putenv( targetCache->mapListDetails[i].localEnvVarPtr );
- }
- }
- }
- freeAndNull( mostRecentRemoteHostG );
- }
- _DtSvcProcessUnlock();
- }
|