<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department, 
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.  
 * No use of the CONDOR Software Program Source Code is authorized 
 * without the express consent of the CONDOR Team.  For more information 
 * contact: CONDOR Team, Attention: Prof<NAME>, 
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685, 
 * (608) 262-0856 or <EMAIL>.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure 
 * by the U.S. Government is subject to restrictions as set forth in 
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer 
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and 
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR 
 * 52.227-19, as applicable, CONDOR Team, Attention: Prof<NAME> 
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison, 
 * WI 53706-1685, (608) 262-0856 or <EMAIL>.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/* 

  This file implements config(), the function all daemons call to
  configure themselves.  It takes up to two arguments: a pointer to a
  ClassAd to fill up with the expressions in the config_file, and a
  pointer to a string containing the name of the daemon calling config
  (mySubSystem).  

  In general, when looking for a given config file (either global,
  local, global-root or local-root), config() checks an environment
  variable to find the location of the global config files.  If that
  doesn't exist, it looks in /etc/condor.  If the files aren't there,
  it try's ~condor/.  If none of the above locations contain a config
  file, config() prints an error message and exits. 

*/

#include "condor_common.h"
#include "debug.h"
#include "clib.h"
#include "condor_sys.h"
#include "condor_config.h"
#include "condor_string.h"
#include "string_list.h"
#include "condor_attributes.h"
#include "my_hostname.h"
#include "condor_version.h"

#if defined(__cplusplus)
extern "C" {
#endif
	
// Function prototypes
void real_config(ClassAd *classAd, char *mySubsystem, char* host);
int Read_config(char*, ClassAd*, BUCKET**, int, int);
char* get_arch();
char* get_op_sys();
int SetSyscalls(int);
char* find_global();
char* find_local();
char* find_global_root();
char* find_local_root();
char* find_file( const char*, const char*);
void init_tilde();
void fill_attributes(ClassAd*);
void init_config();
void clear_config();
void reinsert_specials( char* );

// External variables
extern int	ConfigLineNo;

// Global variables
BUCKET	*ConfigTab[TABLESIZE];
static char* tilde = NULL;

// Function implementations

void
config_fill_ad(ClassAd* ad, char* mySubsys)
{
	char 		buffer[1024];
	char 		*tmp;
	char		*expr;
	StringList	reqdExprs;
	
	if (!mySubsys || !ad) return;

	sprintf (buffer, "%s_EXPRS", mySubsys);
	tmp = param (buffer);
	if( tmp ) {
		reqdExprs.initializeFromString (tmp);	
		free (tmp);

		reqdExprs.rewind();
		while ((tmp = reqdExprs.next())) {
			expr = param(tmp);
			if (expr == NULL) continue;
			sprintf (buffer, "%s = %s", tmp, expr);
			ad->Insert (buffer);
			free (expr);
		}	
	}
	
	/* Insert the version into the ClassAd */
	sprintf(buffer,"%s=\"%s\"", ATTR_VERSION, CondorVersion() );
	ad->Insert(buffer);
}


void
config( ClassAd* classAd, char* mySubsystem )
{
	real_config( classAd, mySubsystem, NULL );
}


void
config_host( ClassAd* classAd, char* mySubsystem, char* host )
{
	real_config( classAd, mySubsystem, host );
}

void
real_config(ClassAd *classAd, char *mySubsystem, char* host)
{
	char	*config_file;
	int		scm, rval;

	static int first_time = TRUE;
	if( first_time ) {
		first_time = FALSE;
		init_config();
	} else {
			// Clear out everything in our config hash table so we can
			// rebuild it from scratch.
		clear_config();
	}

		/*
		  N.B. if we are using the yellow pages, system calls which are
		  not supported by either remote system calls or file descriptor
 		  mapping will occur.  Thus we must be in LOCAL/UNRECORDED mode here.
		*/
	scm = SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );

		// Try to find user "condor" in the passwd file.
	init_tilde();

		// Insert an entry for "tilde", (~condor)
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	} else {
			// What about tilde if there's no ~condor? 
	}

		// Try to find the global config file
	if( ! (config_file = find_global()) ) {
		fprintf(stderr,"\nNeither the environment variable CONDOR_CONFIG,\n" );
		fprintf(stderr,"/etc/condor/, nor ~condor/ contain a condor_config "
				"file.\n" );
		fprintf( stderr,"Either set CONDOR_CONFIG to point to a valid config "
				"file,\n" );
		fprintf( stderr,"or put a \"condor_config\" file in %s or %s.\n", 
				 "/etc/condor", "~condor/" );
		fprintf( stderr, "Exiting.\n\n" );
		exit( 1 );
	}

		// Actually read in the global file
	rval = Read_config( config_file, classAd, ConfigTab, TABLESIZE,
						EXPAND_LAZY );
	if( rval < 0 ) {
		fprintf( stderr,
				 "Configuration Error Line %d while reading global config file %s\n",
				 ConfigLineNo, config_file );
		exit( 1 );
	}
	free( config_file );

		// Insert entries for "hostname" and "full_hostname".  We do
		// this here b/c we need these macros defined so that we can
		// find the local config file if that's defined in terms of
		// hostname or something.  However, we do this after reading
		// the global config file so people can put the
		// DEFAULT_DOMAIN_NAME parameter somewhere if they need it. 
		// -<NAME> <<EMAIL>> 5/11/98
	if( host ) {
		insert( "hostname", host, ConfigTab, TABLESIZE );
	} else {
		insert( "hostname", my_hostname(), ConfigTab, TABLESIZE );
	}
	insert( "full_hostname", my_full_hostname(), ConfigTab, TABLESIZE );

		// Also insert tilde since we don't want that over-written.
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	}

		// Try to find and read the local config file
	if( config_file = find_local() ) {
		if( access( config_file, R_OK ) != 0 ) {
			if( !host ) {
				fprintf( stderr, "ERROR: Can't read local config file %s\n", 
						 config_file );
				exit( 1 );
			} 
		} else {
			rval = Read_config( config_file, classAd, ConfigTab, 
								TABLESIZE, EXPAND_LAZY ); 
			if( rval < 0 ) {
				fprintf( stderr,
				  "Configuration Error Line %d while reading local config file %s\n",
						 ConfigLineNo, config_file );
				exit( 1 );
			}
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Try to find and read the global root config file
	if( config_file = find_global_root() ) {
		rval = Read_config( config_file, classAd, ConfigTab, 
							TABLESIZE, EXPAND_LAZY ); 
		if( rval < 0 ) {
			fprintf( stderr,
					 "Configuration Error Line %d while reading global root config file %s\n",
					 ConfigLineNo, config_file );
			exit( 1 );
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Try to find and read the local root config file
	if( config_file = find_local_root() ) {
		if( access( config_file, R_OK ) != 0 ) {
			if( !host ) {
				fprintf( stderr, "ERROR: Can't read local root config file %s\n", 
						 config_file );
				exit( 1 );
			} 
		} else {
			rval = Read_config( config_file, classAd, ConfigTab, 
								TABLESIZE, EXPAND_LAZY ); 
			if( rval < 0 ) {
				fprintf( stderr,
				 "Configuration Error Line %d while reading local root config file %s\n",
						 ConfigLineNo, config_file );
				exit( 1 );
			}
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Now that we've read all the config files, there are some
		// attributes we want to define with defaults if they're not
		// defined in the config files: ARCH, OPSYS,
		// FILESYSTEM_DOMAIN and UID_DOMAIN.
	fill_attributes( classAd );

		// If mySubSystem_EXPRS is set, insert those expressions into
		// the given classad.
	config_fill_ad( classAd, mySubsystem );

	(void)SetSyscalls( scm );
}


// Try to find the "condor" user's home directory
void
init_tilde()
{
	if( tilde ) {
		free( tilde );
		tilde = NULL;
	}
#if !defined(WIN32)
	struct passwd *pw;
	if( (pw=getpwnam( "condor" )) ) {
		tilde = strdup( pw->pw_dir );
	} 
#endif
}


char*
get_tilde()
{
	init_tilde();
	return tilde;
}


char*
find_global()
{
	return find_file( "CONDOR_CONFIG", "condor_config" );
}


char*
find_local()
{
	return param( "LOCAL_CONFIG_FILE" );
}


char*
find_global_root()
{
	return find_file( "CONDOR_CONFIG_ROOT", "condor_config.root" );
}

char*
find_local_root()
{
	return param( "LOCAL_ROOT_CONFIG_FILE" );
}


// Find location of specified file
char*
find_file(const char *env_name, const char *file_name)
{

	char	*config_file = NULL, *env;
	int		fd;

		// If we were given an environment variable name, try that first. 
	if( env_name && (env = getenv( env_name )) ) {
		config_file = strdup( env );
		if( (fd = open( config_file, O_RDONLY)) < 0 ) {
			fprintf( stderr, "File specified in %s environment ", env_name );
			fprintf( stderr, "variable:\n\"%s\" does not exist.", config_file ); 
			fprintf( stderr, "  Trying fall back options...\n" ); 
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	if( ! config_file ) {
			// try /etc/condor/file_name
		config_file = (char *)malloc( (strlen(file_name) + 14) * sizeof(char) ); 
		config_file[0] = '\0';
		strcat( config_file, "/etc/condor/" );
		strcat( config_file, file_name );
		if( (fd = open( config_file, O_RDONLY )) < 0 ) {
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	if( ! config_file && tilde ) {
			// try ~condor/file_name
		config_file = (char *)malloc( 
						 (strlen(tilde) + strlen(file_name) + 2) * sizeof(char) ); 
		config_file[0] = '\0';
		strcat( config_file, tilde );
		strcat( config_file, "/" );
		strcat( config_file, file_name );
		if( (fd = open( config_file, O_RDONLY)) < 0 ) {
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	return config_file;
}


void
fill_attributes(ClassAd* classAd)
{

		/* Now that we've read in the whole config file, there are a
		   few attributes that we want to insert values for even if 
		   they're not defined in the file.  These are: ARCH, OPSYS,
		   UID_DOMAIN and FILESYSTEM_DOMAIN.  ARCH and OPSYS we get
		   from uname().  If either UID_DOMAIN or FILESYSTEM_DOMAIN
		   are not defined, we use the fully qualified hostname of
		   this host.  In all cases, the value in the config file
		   overrides these defaults.  Arch and OpSys by <NAME>.  Uid
		   and FileSys by <NAME>, 1/12/98 */

	char *arch, *op_sys, *uid_domain, *filesys_domain;
	char line[1024];

  	arch = param("ARCH");
	if( !arch ) {
		if( (arch = get_arch()) != NULL ) {
			insert( "ARCH", arch, ConfigTab, TABLESIZE );
			if(classAd)	{
				sprintf( line, "%s=\"%s\"", ATTR_ARCH, arch );
				classAd->Insert(line);
			}
		}
	} else {
		free( arch );
	}

	op_sys = param("OPSYS");
	if( !op_sys ) {
		if( (op_sys = get_op_sys()) != NULL ) {
			insert( "OPSYS", op_sys, ConfigTab, TABLESIZE );
			if(classAd) {
				sprintf( line, "%s=\"%s\"", ATTR_OPSYS, op_sys );
				classAd->Insert(line);
			}
		}
	} else {
		free( op_sys );
	}

	filesys_domain = param("FILESYSTEM_DOMAIN");
	if( !filesys_domain ) {
		filesys_domain = my_full_hostname();
		insert( "FILESYSTEM_DOMAIN", filesys_domain, ConfigTab, TABLESIZE );
		if(classAd) {
			sprintf( line, "%s=\"%s\"", ATTR_FILE_SYSTEM_DOMAIN, filesys_domain );
			classAd->Insert(line);
		}
	} else {
		free( filesys_domain );
	}

	uid_domain = param("UID_DOMAIN");
	if( !uid_domain ) {
		uid_domain = my_full_hostname();
		insert( "UID_DOMAIN", uid_domain, ConfigTab, TABLESIZE );
		if(classAd) {
			sprintf( line, "%s=\"%s\"", ATTR_FILE_SYSTEM_DOMAIN, uid_domain );
			classAd->Insert(line);
		}
	} else {
		free( uid_domain );
	}

}


void
init_config()
{
	memset( (char *)ConfigTab, 0, (TABLESIZE * sizeof(BUCKET*)) ); 
}


void
clear_config()
{
	register 	int 	i;
	register 	BUCKET	*ptr;	
	register 	BUCKET	*tmp;	

	for( i=0; i<TABLESIZE; i++ ) {
		ptr = ConfigTab[i];
		while( ptr ) {
			tmp = ptr->next;
			FREE( ptr->value );
			FREE( ptr->name );
			FREE( ptr );
			ptr = tmp;
		}
		ConfigTab[i] = NULL;
	}
}


/*
** Return the value associated with the named parameter.  Return NULL
** if the given parameter is not defined.
*/
char *
param( char *name )
{
	char *val = lookup_macro( name, ConfigTab, TABLESIZE );

	if( val == NULL ) {
		return( NULL );
	}
	return( expand_macro(val, ConfigTab, TABLESIZE) );
}

char *
macro_expand( char *str )
{
	return( expand_macro(str, ConfigTab, TABLESIZE) );
}

/*
** Return non-zero iff the named configuration parameter contains the given
** pattern.  
*/
int
param_in_pattern( char *parameter, char *pattern )
{
	char	*argv[512];
	int		argc;
	char	*tmp;

		/* Look up the parameter and break its value into an argv */
	/* tmp = strdup( param(parameter) ); */
	tmp = param(parameter);
	mkargv( &argc, argv, tmp );

		/* Search for the given pattern */
	for( argc--; argc >= 0; argc-- ) {
		if( !strcmp(pattern,argv[argc]) ) {
			FREE( tmp );
			return 1;
		}
	}
	FREE( tmp );
	return 0;
}


#if defined(WIN32)

char *
get_arch()
{
	static char answer[1024];	
	SYSTEM_INFO info;
	GetSystemInfo(&info);
	switch(info.wProcessorArchitecture) {
	case PROCESSOR_ARCHITECTURE_INTEL:
		sprintf(answer, "INTEL");
		break;
	case PROCESSOR_ARCHITECTURE_MIPS:
		sprintf(answer, "MIPS");
		break;
	case PROCESSOR_ARCHITECTURE_ALPHA:
		sprintf(answer, "ALPHA");
		break;
	case PROCESSOR_ARCHITECTURE_PPC:
		sprintf(answer, "PPC");
		break;
	case PROCESSOR_ARCHITECTURE_UNKNOWN:
	default:
		sprintf(answer, "UNKNOWN");
		break;
	}

	return answer;
}

char *
get_op_sys()
{
	static char answer[1024];
	OSVERSIONINFO info;
	info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (GetVersionEx(&info) > 0) {
		switch(info.dwPlatformId) {
		case VER_PLATFORM_WIN32s:
			sprintf(answer, "WIN32s%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		case VER_PLATFORM_WIN32_WINDOWS:
			sprintf(answer, "WIN32%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		case VER_PLATFORM_WIN32_NT:
			sprintf(answer, "WINNT%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		default:
			sprintf(answer, "UNKNOWN");
			break;
		}
	} else {
		sprintf(answer, "ERROR");
	}

	return answer;
}

#else
/* uname() is POSIX, so this should work on all platforms.  -Jim */
#include <sys/utsname.h>

char *
get_arch()
{
	static struct utsname buf;

	if( uname(&buf) < 0 ) {
		return NULL;
	}

	return buf.machine;
}

char *
get_op_sys()
{
	static char	answer[1024];
	struct utsname buf;

	if( uname(&buf) < 0 ) {
		return NULL;
	}

	strcpy( answer, buf.sysname );
	strcat( answer, buf.release );
	return answer;
}

#endif

void
reinsert_specials( char* host )
{
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	}
	if( host ) {
		insert( "hostname", host, ConfigTab, TABLESIZE );
	} else {
		insert( "hostname", my_hostname(), ConfigTab, TABLESIZE );
	}
	insert( "full_hostname", my_full_hostname(), ConfigTab, TABLESIZE );
}



#if defined(__cplusplus)
}
#endif<commit_msg>Added support for config_insert, used to override settings in the config hashtable.<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department, 
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.  
 * No use of the CONDOR Software Program Source Code is authorized 
 * without the express consent of the CONDOR Team.  For more information 
 * contact: CONDOR Team, Attention: Professor <NAME>, 
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685, 
 * (608) 262-0856 or <EMAIL>.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure 
 * by the U.S. Government is subject to restrictions as set forth in 
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer 
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and 
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR 
 * 52.227-19, as applicable, CONDOR Team, Attention: <NAME> 
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison, 
 * WI 53706-1685, (608) 262-0856 or <EMAIL>.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/* 

  This file implements config(), the function all daemons call to
  configure themselves.  It takes up to two arguments: a pointer to a
  ClassAd to fill up with the expressions in the config_file, and a
  pointer to a string containing the name of the daemon calling config
  (mySubSystem).  

  In general, when looking for a given config file (either global,
  local, global-root or local-root), config() checks an environment
  variable to find the location of the global config files.  If that
  doesn't exist, it looks in /etc/condor.  If the files aren't there,
  it try's ~condor/.  If none of the above locations contain a config
  file, config() prints an error message and exits. 

*/

#include "condor_common.h"
#include "debug.h"
#include "clib.h"
#include "condor_sys.h"
#include "condor_config.h"
#include "condor_string.h"
#include "string_list.h"
#include "condor_attributes.h"
#include "my_hostname.h"
#include "condor_version.h"

#if defined(__cplusplus)
extern "C" {
#endif
	
// Function prototypes
void real_config(ClassAd *classAd, char *mySubsystem, char* host);
int Read_config(char*, ClassAd*, BUCKET**, int, int);
char* get_arch();
char* get_op_sys();
int SetSyscalls(int);
char* find_global();
char* find_local();
char* find_global_root();
char* find_local_root();
char* find_file( const char*, const char*);
void init_tilde();
void fill_attributes(ClassAd*);
void init_config();
void clear_config();
void reinsert_specials( char* );

// External variables
extern int	ConfigLineNo;

// Global variables
BUCKET	*ConfigTab[TABLESIZE];
static char* tilde = NULL;

// Function implementations

void
config_fill_ad(ClassAd* ad, char* mySubsys)
{
	char 		buffer[1024];
	char 		*tmp;
	char		*expr;
	StringList	reqdExprs;
	
	if (!mySubsys || !ad) return;

	sprintf (buffer, "%s_EXPRS", mySubsys);
	tmp = param (buffer);
	if( tmp ) {
		reqdExprs.initializeFromString (tmp);	
		free (tmp);

		reqdExprs.rewind();
		while ((tmp = reqdExprs.next())) {
			expr = param(tmp);
			if (expr == NULL) continue;
			sprintf (buffer, "%s = %s", tmp, expr);
			ad->Insert (buffer);
			free (expr);
		}	
	}
	
	/* Insert the version into the ClassAd */
	sprintf(buffer,"%s=\"%s\"", ATTR_VERSION, CondorVersion() );
	ad->Insert(buffer);
}


void
config( ClassAd* classAd, char* mySubsystem )
{
	real_config( classAd, mySubsystem, NULL );
}


void
config_host( ClassAd* classAd, char* mySubsystem, char* host )
{
	real_config( classAd, mySubsystem, host );
}

void
real_config(ClassAd *classAd, char *mySubsystem, char* host)
{
	char	*config_file;
	int		scm, rval;

	static int first_time = TRUE;
	if( first_time ) {
		first_time = FALSE;
		init_config();
	} else {
			// Clear out everything in our config hash table so we can
			// rebuild it from scratch.
		clear_config();
	}

		/*
		  N.B. if we are using the yellow pages, system calls which are
		  not supported by either remote system calls or file descriptor
 		  mapping will occur.  Thus we must be in LOCAL/UNRECORDED mode here.
		*/
	scm = SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );

		// Try to find user "condor" in the passwd file.
	init_tilde();

		// Insert an entry for "tilde", (~condor)
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	} else {
			// What about tilde if there's no ~condor? 
	}

		// Try to find the global config file
	if( ! (config_file = find_global()) ) {
		fprintf(stderr,"\nNeither the environment variable CONDOR_CONFIG,\n" );
		fprintf(stderr,"/etc/condor/, nor ~condor/ contain a condor_config "
				"file.\n" );
		fprintf( stderr,"Either set CONDOR_CONFIG to point to a valid config "
				"file,\n" );
		fprintf( stderr,"or put a \"condor_config\" file in %s or %s.\n", 
				 "/etc/condor", "~condor/" );
		fprintf( stderr, "Exiting.\n\n" );
		exit( 1 );
	}

		// Actually read in the global file
	rval = Read_config( config_file, classAd, ConfigTab, TABLESIZE,
						EXPAND_LAZY );
	if( rval < 0 ) {
		fprintf( stderr,
				 "Configuration Error Line %d while reading global config file %s\n",
				 ConfigLineNo, config_file );
		exit( 1 );
	}
	free( config_file );

		// Insert entries for "hostname" and "full_hostname".  We do
		// this here b/c we need these macros defined so that we can
		// find the local config file if that's defined in terms of
		// hostname or something.  However, we do this after reading
		// the global config file so people can put the
		// DEFAULT_DOMAIN_NAME parameter somewhere if they need it. 
		// -<NAME> <<EMAIL>> 5/11/98
	if( host ) {
		insert( "hostname", host, ConfigTab, TABLESIZE );
	} else {
		insert( "hostname", my_hostname(), ConfigTab, TABLESIZE );
	}
	insert( "full_hostname", my_full_hostname(), ConfigTab, TABLESIZE );

		// Also insert tilde since we don't want that over-written.
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	}

		// Try to find and read the local config file
	if( config_file = find_local() ) {
		if( access( config_file, R_OK ) != 0 ) {
			if( !host ) {
				fprintf( stderr, "ERROR: Can't read local config file %s\n", 
						 config_file );
				exit( 1 );
			} 
		} else {
			rval = Read_config( config_file, classAd, ConfigTab, 
								TABLESIZE, EXPAND_LAZY ); 
			if( rval < 0 ) {
				fprintf( stderr,
				  "Configuration Error Line %d while reading local config file %s\n",
						 ConfigLineNo, config_file );
				exit( 1 );
			}
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Try to find and read the global root config file
	if( config_file = find_global_root() ) {
		rval = Read_config( config_file, classAd, ConfigTab, 
							TABLESIZE, EXPAND_LAZY ); 
		if( rval < 0 ) {
			fprintf( stderr,
					 "Configuration Error Line %d while reading global root config file %s\n",
					 ConfigLineNo, config_file );
			exit( 1 );
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Try to find and read the local root config file
	if( config_file = find_local_root() ) {
		if( access( config_file, R_OK ) != 0 ) {
			if( !host ) {
				fprintf( stderr, "ERROR: Can't read local root config file %s\n", 
						 config_file );
				exit( 1 );
			} 
		} else {
			rval = Read_config( config_file, classAd, ConfigTab, 
								TABLESIZE, EXPAND_LAZY ); 
			if( rval < 0 ) {
				fprintf( stderr,
				 "Configuration Error Line %d while reading local root config file %s\n",
						 ConfigLineNo, config_file );
				exit( 1 );
			}
		}
		free( config_file );
	}

		// Re-insert the special macros.  We don't want the user to 
		// override them, since it's not going to work.
	reinsert_specials( host );

		// Now that we've read all the config files, there are some
		// attributes we want to define with defaults if they're not
		// defined in the config files: ARCH, OPSYS,
		// FILESYSTEM_DOMAIN and UID_DOMAIN.
	fill_attributes( classAd );

		// If mySubSystem_EXPRS is set, insert those expressions into
		// the given classad.
	config_fill_ad( classAd, mySubsystem );

	(void)SetSyscalls( scm );
}


// Try to find the "condor" user's home directory
void
init_tilde()
{
	if( tilde ) {
		free( tilde );
		tilde = NULL;
	}
#if !defined(WIN32)
	struct passwd *pw;
	if( (pw=getpwnam( "condor" )) ) {
		tilde = strdup( pw->pw_dir );
	} 
#endif
}


char*
get_tilde()
{
	init_tilde();
	return tilde;
}


char*
find_global()
{
	return find_file( "CONDOR_CONFIG", "condor_config" );
}


char*
find_local()
{
	return param( "LOCAL_CONFIG_FILE" );
}


char*
find_global_root()
{
	return find_file( "CONDOR_CONFIG_ROOT", "condor_config.root" );
}

char*
find_local_root()
{
	return param( "LOCAL_ROOT_CONFIG_FILE" );
}


// Find location of specified file
char*
find_file(const char *env_name, const char *file_name)
{

	char	*config_file = NULL, *env;
	int		fd;

		// If we were given an environment variable name, try that first. 
	if( env_name && (env = getenv( env_name )) ) {
		config_file = strdup( env );
		if( (fd = open( config_file, O_RDONLY)) < 0 ) {
			fprintf( stderr, "File specified in %s environment ", env_name );
			fprintf( stderr, "variable:\n\"%s\" does not exist.", config_file ); 
			fprintf( stderr, "  Trying fall back options...\n" ); 
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	if( ! config_file ) {
			// try /etc/condor/file_name
		config_file = (char *)malloc( (strlen(file_name) + 14) * sizeof(char) ); 
		config_file[0] = '\0';
		strcat( config_file, "/etc/condor/" );
		strcat( config_file, file_name );
		if( (fd = open( config_file, O_RDONLY )) < 0 ) {
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	if( ! config_file && tilde ) {
			// try ~condor/file_name
		config_file = (char *)malloc( 
						 (strlen(tilde) + strlen(file_name) + 2) * sizeof(char) ); 
		config_file[0] = '\0';
		strcat( config_file, tilde );
		strcat( config_file, "/" );
		strcat( config_file, file_name );
		if( (fd = open( config_file, O_RDONLY)) < 0 ) {
			free( config_file );
			config_file = NULL;
		} else {
			close( fd );
		}
	}
	return config_file;
}


void
fill_attributes(ClassAd* classAd)
{

		/* Now that we've read in the whole config file, there are a
		   few attributes that we want to insert values for even if 
		   they're not defined in the file.  These are: ARCH, OPSYS,
		   UID_DOMAIN and FILESYSTEM_DOMAIN.  ARCH and OPSYS we get
		   from uname().  If either UID_DOMAIN or FILESYSTEM_DOMAIN
		   are not defined, we use the fully qualified hostname of
		   this host.  In all cases, the value in the config file
		   overrides these defaults.  Arch and OpSys by <NAME>.  Uid
		   and FileSys by <NAME>, 1/12/98 */

	char *arch, *op_sys, *uid_domain, *filesys_domain;
	char line[1024];

  	arch = param("ARCH");
	if( !arch ) {
		if( (arch = get_arch()) != NULL ) {
			insert( "ARCH", arch, ConfigTab, TABLESIZE );
			if(classAd)	{
				sprintf( line, "%s=\"%s\"", ATTR_ARCH, arch );
				classAd->Insert(line);
			}
		}
	} else {
		free( arch );
	}

	op_sys = param("OPSYS");
	if( !op_sys ) {
		if( (op_sys = get_op_sys()) != NULL ) {
			insert( "OPSYS", op_sys, ConfigTab, TABLESIZE );
			if(classAd) {
				sprintf( line, "%s=\"%s\"", ATTR_OPSYS, op_sys );
				classAd->Insert(line);
			}
		}
	} else {
		free( op_sys );
	}

	filesys_domain = param("FILESYSTEM_DOMAIN");
	if( !filesys_domain ) {
		filesys_domain = my_full_hostname();
		insert( "FILESYSTEM_DOMAIN", filesys_domain, ConfigTab, TABLESIZE );
		if(classAd) {
			sprintf( line, "%s=\"%s\"", ATTR_FILE_SYSTEM_DOMAIN, filesys_domain );
			classAd->Insert(line);
		}
	} else {
		free( filesys_domain );
	}

	uid_domain = param("UID_DOMAIN");
	if( !uid_domain ) {
		uid_domain = my_full_hostname();
		insert( "UID_DOMAIN", uid_domain, ConfigTab, TABLESIZE );
		if(classAd) {
			sprintf( line, "%s=\"%s\"", ATTR_FILE_SYSTEM_DOMAIN, uid_domain );
			classAd->Insert(line);
		}
	} else {
		free( uid_domain );
	}

}


void
init_config()
{
	memset( (char *)ConfigTab, 0, (TABLESIZE * sizeof(BUCKET*)) ); 
}


void
clear_config()
{
	register 	int 	i;
	register 	BUCKET	*ptr;	
	register 	BUCKET	*tmp;	

	for( i=0; i<TABLESIZE; i++ ) {
		ptr = ConfigTab[i];
		while( ptr ) {
			tmp = ptr->next;
			FREE( ptr->value );
			FREE( ptr->name );
			FREE( ptr );
			ptr = tmp;
		}
		ConfigTab[i] = NULL;
	}
}


/*
** Return the value associated with the named parameter.  Return NULL
** if the given parameter is not defined.
*/
char *
param( char *name )
{
	char *val = lookup_macro( name, ConfigTab, TABLESIZE );

	if( val == NULL ) {
		return( NULL );
	}
	return( expand_macro(val, ConfigTab, TABLESIZE) );
}

char *
macro_expand( char *str )
{
	return( expand_macro(str, ConfigTab, TABLESIZE) );
}

/*
** Return non-zero iff the named configuration parameter contains the given
** pattern.  
*/
int
param_in_pattern( char *parameter, char *pattern )
{
	char	*argv[512];
	int		argc;
	char	*tmp;

		/* Look up the parameter and break its value into an argv */
	/* tmp = strdup( param(parameter) ); */
	tmp = param(parameter);
	mkargv( &argc, argv, tmp );

		/* Search for the given pattern */
	for( argc--; argc >= 0; argc-- ) {
		if( !strcmp(pattern,argv[argc]) ) {
			FREE( tmp );
			return 1;
		}
	}
	FREE( tmp );
	return 0;
}


#if defined(WIN32)

char *
get_arch()
{
	static char answer[1024];	
	SYSTEM_INFO info;
	GetSystemInfo(&info);
	switch(info.wProcessorArchitecture) {
	case PROCESSOR_ARCHITECTURE_INTEL:
		sprintf(answer, "INTEL");
		break;
	case PROCESSOR_ARCHITECTURE_MIPS:
		sprintf(answer, "MIPS");
		break;
	case PROCESSOR_ARCHITECTURE_ALPHA:
		sprintf(answer, "ALPHA");
		break;
	case PROCESSOR_ARCHITECTURE_PPC:
		sprintf(answer, "PPC");
		break;
	case PROCESSOR_ARCHITECTURE_UNKNOWN:
	default:
		sprintf(answer, "UNKNOWN");
		break;
	}

	return answer;
}

char *
get_op_sys()
{
	static char answer[1024];
	OSVERSIONINFO info;
	info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (GetVersionEx(&info) > 0) {
		switch(info.dwPlatformId) {
		case VER_PLATFORM_WIN32s:
			sprintf(answer, "WIN32s%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		case VER_PLATFORM_WIN32_WINDOWS:
			sprintf(answer, "WIN32%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		case VER_PLATFORM_WIN32_NT:
			sprintf(answer, "WINNT%d%d", info.dwMajorVersion, info.dwMinorVersion);
			break;
		default:
			sprintf(answer, "UNKNOWN");
			break;
		}
	} else {
		sprintf(answer, "ERROR");
	}

	return answer;
}

#else
/* uname() is POSIX, so this should work on all platforms.  -Jim */
#include <sys/utsname.h>

char *
get_arch()
{
	static struct utsname buf;

	if( uname(&buf) < 0 ) {
		return NULL;
	}

	return buf.machine;
}

char *
get_op_sys()
{
	static char	answer[1024];
	struct utsname buf;

	if( uname(&buf) < 0 ) {
		return NULL;
	}

	strcpy( answer, buf.sysname );
	strcat( answer, buf.release );
	return answer;
}

#endif

void
reinsert_specials( char* host )
{
	if( tilde ) {
		insert( "tilde", tilde, ConfigTab, TABLESIZE );
	}
	if( host ) {
		insert( "hostname", host, ConfigTab, TABLESIZE );
	} else {
		insert( "hostname", my_hostname(), ConfigTab, TABLESIZE );
	}
	insert( "full_hostname", my_full_hostname(), ConfigTab, TABLESIZE );
}


void
config_insert( char* attrName, char* attrValue ) {

	if( ! (attrName && attrValue) ) {
		return;
	}
	insert( attrName, attrValue, ConfigTab, TABLESIZE );
}


#if defined(__cplusplus)
}
#endif
{'fraction_non_alphanumeric': 0.13323324602312656, 'fraction_numerical': 0.01034945377882834, 'mean_word_length': 3.516952820660799, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6522190', 'n_tokens_mistral': 12272, 'n_tokens_neox': 11119, 'n_words': 3338}