newlib/winsup/cygwin/environ.cc
Robert Collins f449bfef40 2002-02-28 Robert Collins <rbtcollins@hotmail.com>
* Merged cygwin_daemon into head minus the new shm and ipc exports.

2002-02-28  Robert Collins  <rbtcollins@hotmail.com>

	* fhandler_tty.cc (fhandler_tty_slave::open): More debugging.
	(fhandler_tty_slave::read): Fix printf type for the handle.
	* tty.cc (tty::common_init): Add a FIXME for security.

2002-01-29  Robert Collins  <rbtcollins@hotmail.com>

	* Makefile.in (OBJS): Remove duplicate localtime.o.

2002-01-17  Robert Collins  <rbtcollins@hotmail.com>

	* cygserver.cc (check_and_dup_handle): Consolidate the two variants for
	simplicity.
	Add Some basic debug output.
	(client_request_attach_tty::serve): Use the new debug_printf for clarity.
	Mark the duplicated handles as inheritable - fixup_after_fork() doesn't reopen
	tty's.

2002-01-16  Robert Collins  <rbtcollins@hotmail.com>

	* cygserver.cc (transport): Correct scope.
	(client_request_attach_tty::serve): Add more debug information.
	Fix erroneous use of transport instead of conn.
	* cygserver_transport_pipes.cc (transport_layer_pipes::close): More debug.
	(transport_layer_pipes::read): Ditto.
	(transport_layer_pipes::write): Ditto.
	(transport_layer_pipes::impersonate_client): Ditto.

Mon Oct  8  7:41:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* cygserver.cc (server_request::process): Rename client_request_shm_get to
	client_request_shm.
	* cygserver_process.cc (process_cache::add): Rename to add_task.
	Use process_cleanup instead of process_request.
	(process_cache::remove_process): New method.
	(process::process): Initialize new members.
	(process::~process): New member.
	(process::cleanup): New method.
	(process::add_cleanup_routine): New method.
	(process_request::process): Rename to process_cleanup.
	Call the process object's cleanup method and then delete it.
	(process_process_param::request_loop): Remove the signalling process.
	* cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm.
	(client_request_shm_get::serve): Handle attach request counting.
	* cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm.
	(class shm_cleanup): New class.
	* shm.cc: Globally rename client_request_shm_get to client_request_shm.
	(client_request_shm::client_request_shm): New constructor for attach requests.
	(shmat): Use it.
	* include/cygwin/cygserver_process.h (class process_request): Rename to
	process_cleanup.
	(class cleanup_routine): New class.
	(class process): New members and methods to allow calling back when the process
	terminates.

Thu Oct  4 14:12:00 2001  Robert Collins <rbtcollins@hotmail.com>
	* cygserver.cc (request_loop): Make static.
	(main): Use new cache constructor syntax.
	Start cache worker threads.
	Cleanup the cache at shutdown.
	* cygserver_process.cc: Run indent.
	(process_cache::process_cache): Add a trigger to use when adding a process.
	(process_cache::process): Move process_entry to process.
	Insert at the end of the list.
	Trigger the request loop when new process's inserted.
	(process_cache::process_requests): Do it.
	(process_cache::add): New method.
	(process_cache::handle_snapshot): New method.
	(process::process): Merge in the process_entry fields.
	(process::handle): Make a stub function.
	(process::exit_code): New method.
	(process_request::process): New method.
	(process_process_param::request_loop): New method.
	* cygserver_shm.cc: New header dependency - threaded_queue.h.
	* threaded_queue.cc (threaded_queue::cleanup): Clearer messages.
	(queue_process_param::stop): Short spinlock on interruptible threads.
	* threaded_queue.h (class threaded_queue): New constructor.
	* include/cygwin/cygserver_process.h (process_request): New class.
	(process_entry): Remove.
	(process): Merge in process_entry.
	(process_cache): Inherit from threaded_queue.

Tue Oct  2 23:24:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* cygserver.cc (class server_process_param): Use new constructor syntax.
	* cygserver_process.cc (process_cache::~process_cache): New function.
	* threaded_queue.cc: Define condition debug_printf.
	Run indent.
	(threaded_queue::cleanup): Move queue_process_param guts to a method.
	(threaded_queue::process_requests): Ditto.
	(queue_process_param::queue_process_param): New method.
	(queue_process_param::~queue_process_param): Ditto.
	(queue_process_param::start): Ditto.
	(queue_process_param::stop): Ditto.
	* threaded_queue.h (class queue_process_param): Add support for
	interruptible request loops.
	* cygwin/include/cygwin/cygserver_process.h (class process_cache): Add
	destructor.

Tue Oct  2 23:24:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* cygserver_client.cc: New flag allow_daemon to disable the daemon completely.
	(cygserver_request): Check it.
	(cygserver_init): Ditto.
	* environ.cc (parse_thing): Add (no)daemon option.

Tue Oct  2 23:00:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* shm.cc: Update to handle include changes from HEAD.

Tue Oct  2 16:06:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* Makefile.in: Remove cygserver_shm.o from cygwin1.dll.
	Rename cygserver_shm_outside.o to cygserver_shm.o.
	* cygserver.cc (server_request::process): Use the new client_request
	constructor.
	* cygserver_client.cc: Remove the #ifdef's stubs for the server method
	within cygwin.
	(client_request_attach_tty::client_request_attach_tty): Use the new
	client_request constructor.
	(client_request_shutdown::client_request_shutdown): Ditto.
	(client_request::client_request): Ditto.
	* cygserver_shm.cc (client_request_shm_get::serve): Remove the
	#ifdef'd stub for in-cygwin builds.
	(client_request_shm_get::client_request_shm_get): Use the new
	client_request constructor, and remove the in-cygwin variants.
	* cygserver_shm.h (class client_request_shm_get): #ifndef test the
	serve method - it's only used in cygserver.
	* shm.cc (client_request_shm_get::client_request_shm_get): New function.
	* include/cygwin/cygserver.h (request_header): New constructor.
	(class client_request): Use it.
	New constructor accepting the header size.
	#ifndef test the server method - it's only used within cygserver.
	(client_request_get_version): #ifdef test the server method.
	(client_request_shutdown): Ditto.
	(client_request_attach_tty): Ditto.

Tue Oct  2  9:57:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* Makefile.in: add threaded_queue.o to cygserver.exe.
	* cygserver.cc: Include threaded_queue.h
	(class server_request): Inherit from queue_request.
	(class server_process_param): Inherit from queue_process_param.
	(class server_request_queue): Inherit from threaded_queue.
	(request_loop): Adjust for new types.
	(server_request_queue::process_requests): Remove guts to
	threaded_queue::process_requests.
	(server_request::server_request): Adjust for new types.
	(worker_function): Delete.
	(server_request_queue::create_workers): Delete.
	(server_request_queue::cleanup): Delete.
	(server_request_queue::add): Move guts to threaded_queue::add.
	* threaded_queue.cc: New file.
	* threaded_queue.h: New file.

Mon Oct  1 12:38:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* cygserver.cc (client_request::serve): New function.
	* cygserver_process.cc: Inlude <pthread.h> for pthread_once.
	(process_cache::process_cache): Initialise a crtiical section for write access.
	(process_cache::process): Use the critical section. Also add missing entries to
	the cache.
	(do_process_init): New function to initalise class process static variables.
	(process::process): Ensure that the process access critical section is
	initialised.
	(process::handle): Close the handle of old process's when they have terminated
	and we are returning the handle for a process with the same pid.
	* cygserver_shm.cc: Run indent.
	Include cygserver_process.h to allow process cache functionality.
	(client_request_shm_get::serve): New parameter for process cache support.
	Use the process cache, not OpenProcess to get a handle to the originating process.
	Fix a handle leak with token_handle.
	* cygserver_shm.h (class client_request_shm_get): Update ::serve for process
	cache support.
	* cygserver_transport_pipes.cc: Redefine debug_printf to be conditional on DEBUG.
	* include/cygwin/cygserver.h: Do not implement client_request::serve in the
	header.
	* include/cygwin/cygserver_process.h (class process_cache): Add a write access
	critical section to prevent races when requests from a  multithreaded
	application arrive.

Sun Sep 30 23:41:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* Makefile.in: Add cygserver_process.o to cygserver.exe.
	* cygserver.cc: Include signal.h and cygwin_version.h.
	Define debug_printf as a macro.
	Define DEBUG to a value.
	(client_request_attach_tty::serve): Add beginning of process cache support.
	Change from #ifdef DEBUG to work with new DEBUG style.
	(client_request_get_version::serve): Add beginning of process cache support.
	(class server_request): New prototype for support of process cache.
	(class queue_process_param): New class to allow request loop threading.
	(class server_request_queue): Add beginning of process cache support.
	Allow request loop threading.
	(request_loop): Thread function for request loops.
	(server_request_queue::process_requests): Initiator for threaded request loops.
	(client_request_shutdown::serve): Add beginning of process cache support.
	(server_request::server_request): Ditto.
	(server_request::process): Use debug_printf. Add beginning of process cache
	support.
	(server_request_queue::cleanup): Kill off any request loop threads.
	(server_request_queue::add): Add beginning of process cache support.
	(handle_signal): Trigger a shutdown.
	(main): Print out some useful info at startup - version, date time.
	Add process cache support.
	Spawn a separate thread for the transport request loop, thus allowing concurrent
	support for multiple transports.
	* cygserver_client.cc (client_request_get_version::serve): Add process cache
	support.
	(client_request_attach_tty::serve): Add process cache support.
	(client_request_shutdown::serve): Add process cache support.
	* cygsserver_process.cc: New file with the process cache support.
	* cygserver_shm.cc: Redefine debug_printf to allow conditional output.
	* cygwin.din: Export shmdt().
	* shm.cc: Run indent.
	Update FIXME's.
	(shmdt): New function.
	* include/cygwin/cygserver.h (class client_request): Add process cache support.
	(class client_request_get_version): Ditto.
	(class client_request_shutdown): Ditto.
	(class client_request_attach_tty): Ditto.
	* include/cygwin/cygserver_process.h: New header for process cache support.

Sun Sep 30  8:52:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* include/cygwin/cygserver_transport.h: Add copyright header.
	* include/cygwin/cygserver_transport_pipes.h: Ditto.
	* include/cygwin/cygserver_transport_sockets.h: Ditto.

Sat Sep 29 20:40:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* Makefile.in: Add cygserver_transport_sockets.o to DLL_OFILES.
	Add cygserver_transport_sockets_outside.o to cygserver.exe.
	* cygserver.cc: Include new include files.
	* cygserver_client.cc: Ditto.
	* cygserver_shm.h: No need to include <sys/socket.h> now.
	* cygerver_transport.cc: Include new include files.
	(transport_layer_base::transport_layer_base): Strip back to a stub.
	(transport_layer_base::listen): Ditto.
	(transport_layer_base::accept): Ditto.
	(transport_layer_base::close): Ditto.
	(transport_layer_base::read): Ditto.
	(transport_layer_base::write): Ditto.
	(transport_layer_base::connect): Ditto.
	* cygserver_transport_pipes.cc: Include new header
	"cygwin/cygserver_transport_pipes.h".
	* cygserver_transport_sockets.cc: New file.
	* dcrt0.cc: No need to include <sys/socket.h> now.
	* fhandler_tty.cc: Ditto.
	* tty.cc: Ditto.
	* include/cygwin/cygserver_transport.h: Strip the base class to a stub.
	Remove the cygserver_transport_pipes class.
	* include/cygwin/cygserver_transport_pipes.h: New file.
	* include/cygwin/cygserver_transport_sockets.h: New file.

Tue Sep 25 16:22:00 2001  Robert Collins <rbtcollins@hotmail.com>

	* autoload.cc: Add dynamic load statement for 'ImpersonateNamedPipeClient'.
	* Makefile.in: Add new object files, and build instructions for cygserver.exe.
	* cygwin.din: Export ftok, shmat, shmctl and shmget.
	* dcrt0.cc: Additional includes for cygserver support.
	(dll_crt0_1): Initialise the cygserver client.
	* fhandler.h (fhandler_tty): New method cygserver_attach_tty.
	* fhandler_tty.cc: Additional includes for cygserver support.
	(fhandler_tty_slave::open): Attempt to use the cygserver when obtaining
	handles from the parent process. On failure or 9x use the current method.
	(fhandler_tty_slave::cygserver_attach_tty): New function.
	* fork.cc (fork_child): Fixup shm memory mapped areas.
	* pinfo.h: Declare fixup_shms_after_fork().
	* security.h: Declare alloc_sd().
	* tty.cc: Additonal includes to support cygserver.
	(tty::common_init): Don't allow others to open us if the cygserver is running.
	* winsup.h: Declare cygserver_running.
	* cygserver.cc: New file.
	* cygserver_client.cc: New file.
	* cygserver_shm.cc: New file.
	* cygserver_shm.h: New file.
	* cygserver_transport.cc: New file.
	* cygserver_transport_pipes.cc: New file.
	* ipc.cc: New file.
	* shm.cc: New file.
	* include/cygwin/cygserver.h: New file.
	* include/cygwin/cygserver_transport.h: New file.
	* include/sys/ipc.h: New file.
	* include/sys/shm.h: New file.

2002-02-28  Robert Collins  <rbtcollins@hotmail.com>

	* thread.cc (semaphore::TryWait): Set errno as required by posix 1003.1.
	(__sem_wait): Ditto.
	(__sem_trywait): Ditto.
2002-02-28 14:30:38 +00:00

873 lines
23 KiB
C++

/* environ.cc: Cygwin-adopted functions from newlib to manipulate
process's environment.
Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/cygwin.h>
#include <cygwin/version.h>
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "cygerrno.h"
#include "dtable.h"
#include "cygheap.h"
#include "registry.h"
#include "environ.h"
extern BOOL allow_daemon;
extern BOOL allow_glob;
extern bool ignore_case_with_glob;
extern BOOL allow_ntea;
extern BOOL allow_smbntsec;
extern BOOL allow_winsymlinks;
extern BOOL strip_title_path;
extern int pcheck_case;
extern int subauth_id;
BOOL reset_com = FALSE;
static BOOL envcache = TRUE;
static char **lastenviron;
#define ENVMALLOC \
(CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
<= CYGWIN_VERSION_DLL_MALLOC_ENV)
/* List of names which are converted from dos to unix
on the way in and back again on the way out.
PATH needs to be here because CreateProcess uses it and gdb uses
CreateProcess. HOME is here because most shells use it and would be
confused by Windows style path names. */
static int return_MAX_PATH (const char *) {return MAX_PATH;}
static NO_COPY win_env conv_envvars[] =
{
{"PATH=", 5, NULL, NULL, cygwin_win32_to_posix_path_list,
cygwin_posix_to_win32_path_list,
cygwin_win32_to_posix_path_list_buf_size,
cygwin_posix_to_win32_path_list_buf_size},
{"HOME=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
return_MAX_PATH, return_MAX_PATH},
{"LD_LIBRARY_PATH=", 16, NULL, NULL, cygwin_conv_to_full_posix_path,
cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
{"TMPDIR=", 7, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
return_MAX_PATH, return_MAX_PATH},
{"TMP=", 4, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
return_MAX_PATH, return_MAX_PATH},
{"TEMP=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
return_MAX_PATH, return_MAX_PATH},
{NULL, 0, NULL, NULL, NULL, NULL, 0, 0}
};
static unsigned char conv_start_chars[256] = {0};
void
win_env::add_cache (const char *in_posix, const char *in_native)
{
MALLOC_CHECK;
posix = (char *) realloc (posix, strlen (in_posix) + 1);
strcpy (posix, in_posix);
if (in_native)
{
native = (char *) realloc (native, namelen + 1 + strlen (in_native));
(void) strcpy (native, name);
(void) strcpy (native + namelen, in_native);
}
else
{
native = (char *) realloc (native, namelen + 1 + win32_len (in_posix));
(void) strcpy (native, name);
towin32 (in_posix, native + namelen);
}
MALLOC_CHECK;
debug_printf ("posix %s", posix);
debug_printf ("native %s", native);
}
/* Check for a "special" environment variable name. *env is the pointer
* to the beginning of the environment variable name. n is the length
* of the name including a mandatory '='. Returns a pointer to the
* appropriate conversion structure.
*/
win_env * __stdcall
getwinenv (const char *env, const char *in_posix)
{
if (!conv_start_chars[(unsigned char)*env])
return NULL;
for (int i = 0; conv_envvars[i].name != NULL; i++)
if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
{
win_env * const we = conv_envvars + i;
const char *val;
if (!cur_environ () || !(val = in_posix ?: getenv(we->name)))
debug_printf ("can't set native for %s since no environ yet",
we->name);
else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
we->add_cache (val);
return we;
}
return NULL;
}
/* Convert windows path specs to POSIX, if appropriate.
*/
static void __stdcall
posify (char **here, const char *value)
{
char *src = *here;
win_env *conv;
if (!(conv = getwinenv (src)))
return;
int len = strcspn (src, "=") + 1;
/* Turn all the items from c:<foo>;<bar> into their
mounted equivalents - if there is one. */
char *outenv = (char *) malloc (1 + len + conv->posix_len (value));
memcpy (outenv, src, len);
conv->toposix (value, outenv + len);
conv->add_cache (outenv + len, *value != '/' ? value : NULL);
debug_printf ("env var converted to %s", outenv);
*here = outenv;
free (src);
MALLOC_CHECK;
}
/*
* my_findenv --
* Returns pointer to value associated with name, if any, else NULL.
* Sets offset to be the offset of the name/value combination in the
* environment array, for use by setenv(3) and unsetenv(3).
* Explicitly removes '=' in argument name.
*/
static char * __stdcall
my_findenv (const char *name, int *offset)
{
register int len;
register char **p;
const char *c;
c = name;
len = 0;
while (*c && *c != '=')
{
c++;
len++;
}
for (p = cur_environ (); *p; ++p)
if (!strncmp (*p, name, len))
if (*(c = *p + len) == '=')
{
*offset = p - cur_environ ();
return (char *) (++c);
}
MALLOC_CHECK;
return NULL;
}
/*
* getenv --
* Returns ptr to value associated with name, if any, else NULL.
*/
extern "C" char *
getenv (const char *name)
{
int offset;
return my_findenv (name, &offset);
}
extern int __stdcall
envsize (const char * const *in_envp, int debug_print)
{
const char * const *envp;
for (envp = in_envp; *envp; envp++)
if (debug_print)
debug_printf ("%s", *envp);
return (1 + envp - in_envp) * sizeof (const char *);
}
/* Takes similar arguments to setenv except that overwrite is
either -1, 0, or 1. 0 or 1 signify that the function should
perform similarly to setenv. Otherwise putenv is assumed. */
static int __stdcall
_addenv (const char *name, const char *value, int overwrite)
{
int issetenv = overwrite >= 0;
int offset;
char *p;
unsigned int valuelen = strlen (value);
if ((p = my_findenv (name, &offset)))
{ /* Already exists. */
if (!overwrite) /* Ok to overwrite? */
return 0; /* No. Wanted to add new value. FIXME: Right return value? */
/* We've found the offset into environ. If this is a setenv call and
there is room in the current environment entry then just overwrite it.
Otherwise handle this case below. */
if (issetenv && strlen (p) >= valuelen)
{
strcpy (p, value);
return 0;
}
}
else
{ /* Create new slot. */
int sz = envsize (cur_environ ());
int allocsz = sz + (2 * sizeof (char *));
offset = (sz - 1) / sizeof (char *);
/* Allocate space for additional element plus terminating NULL. */
if (cur_environ () == lastenviron)
lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
allocsz);
else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
__cygwin_environ = (char **) memcpy ((char **) lastenviron,
__cygwin_environ, sz);
if (!__cygwin_environ)
{
#ifdef DEBUGGING
try_to_debug ();
#endif
return -1; /* Oops. No more memory. */
}
__cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
update_envptrs (); /* Update any local copies of 'environ'. */
}
char *envhere;
if (!issetenv)
/* Not setenv. Just overwrite existing. */
envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
else
{ /* setenv */
/* Look for an '=' in the name and ignore anything after that if found. */
for (p = (char *) name; *p && *p != '='; p++)
continue;
int namelen = p - name; /* Length of name. */
/* Allocate enough space for name + '=' + value + '\0' */
envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
if (!envhere)
return -1; /* Oops. No more memory. */
/* Put name '=' value into current slot. */
strncpy (envhere, name, namelen);
envhere[namelen] = '=';
strcpy (envhere + namelen + 1, value);
}
/* Update cygwin's cache, if appropriate */
win_env *spenv;
if ((spenv = getwinenv (envhere)))
spenv->add_cache (value);
MALLOC_CHECK;
return 0;
}
/* putenv Sets an environment variable */
extern "C" int
putenv (const char *str)
{
int res;
if ((res = check_null_empty_str (str)))
{
if (res == ENOENT)
return 0;
set_errno (res);
return -1;
}
char *eq = strchr (str, '=');
if (eq)
return _addenv (str, eq + 1, -1);
/* Remove str from the environment. */
unsetenv (str);
return 0;
}
/* setenv -- Set the value of the environment variable "name" to be
"value". If overwrite is set, replace any current value. */
extern "C" int
setenv (const char *name, const char *value, int overwrite)
{
int res;
if ((res = check_null_empty_str (value)) == EFAULT)
{
set_errno (res);
return -1;
}
if ((res = check_null_empty_str (name)))
{
if (res == ENOENT)
return 0;
set_errno (res);
return -1;
}
if (*value == '=')
value++;
return _addenv (name, value, !!overwrite);
}
/* unsetenv(name) -- Delete environment variable "name". */
extern "C" void
unsetenv (const char *name)
{
register char **e;
int offset;
while (my_findenv (name, &offset)) /* if set multiple times */
/* Move up the rest of the array */
for (e = cur_environ () + offset; ; e++)
if (!(*e = *(e + 1)))
break;
}
/* Turn environment variable part of a=b string into uppercase. */
static __inline__ void
ucenv (char *p, char *eq)
{
/* Amazingly, NT has a case sensitive environment name list,
but only sometimes.
It's normal to have NT set your "Path" to something.
Later, you set "PATH" to something else. This alters "Path".
But if you try and do a naive getenv on "PATH" you'll get nothing.
So we upper case the labels here to prevent confusion later but
we only do it for the first process in a session group. */
for (; p < eq; p++)
if (islower (*p))
*p = cyg_toupper (*p);
}
/* Parse CYGWIN options */
static NO_COPY BOOL export_settings = FALSE;
enum settings
{
justset,
isfunc,
setbit,
set_process_state,
};
/* When BUF is:
null or empty: disables globbing
"ignorecase": enables case-insensitive globbing
anything else: enables case-sensitive globbing */
static void
glob_init (const char *buf)
{
if (!buf || !*buf)
{
allow_glob = FALSE;
ignore_case_with_glob = FALSE;
}
else if (strncasematch (buf, "ignorecase", 10))
{
allow_glob = TRUE;
ignore_case_with_glob = TRUE;
}
else
{
allow_glob = TRUE;
ignore_case_with_glob = FALSE;
}
}
static void
check_case_init (const char *buf)
{
if (!buf || !*buf)
return;
if (strncmp (buf, "relax", 5)== 0)
{
pcheck_case = PCHECK_RELAXED;
debug_printf ("File case checking set to RELAXED");
}
else if (strcmp (buf, "adjust")== 0)
{
pcheck_case = PCHECK_ADJUST;
debug_printf ("File case checking set to ADJUST");
}
else if (strcmp (buf, "strict")== 0)
{
pcheck_case = PCHECK_STRICT;
debug_printf ("File case checking set to STRICT");
}
else
{
debug_printf ("Wrong case checking name: %s", buf);
}
}
void
set_file_api_mode (codepage_type cp)
{
if (cp == oem_cp)
{
SetFileApisToOEM ();
debug_printf ("File APIs set to OEM");
}
else if (cp == ansi_cp)
{
SetFileApisToANSI ();
debug_printf ("File APIs set to ANSI");
}
}
static void
codepage_init (const char *buf)
{
if (!buf || !*buf)
return;
if (strcmp (buf, "oem")== 0)
{
current_codepage = oem_cp;
set_file_api_mode (current_codepage);
}
else if (strcmp (buf, "ansi")== 0)
{
current_codepage = ansi_cp;
set_file_api_mode (current_codepage);
}
else
{
debug_printf ("Wrong codepage name: %s", buf);
}
}
static void
subauth_id_init (const char *buf)
{
if (!buf || !*buf)
return;
int i = strtol (buf, NULL, 0);
/* 0..127 are reserved by Microsoft, 132 is IIS subauthentication. */
if (i > 127 && i != 132 && i <= 255)
subauth_id = i;
}
static void
set_chunksize (const char *buf)
{
wincap.set_chunksize (strtol (buf, NULL, 0));
}
/* The structure below is used to set up an array which is used to
parse the CYGWIN environment variable or, if enabled, options from
the registry. */
static struct parse_thing
{
const char *name;
union parse_setting
{
BOOL *b;
DWORD *x;
int *i;
void (*func)(const char *);
} setting;
enum settings disposition;
char *remember;
union parse_values
{
DWORD i;
const char *s;
} values[2];
} known[] NO_COPY =
{
{"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}},
{"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}},
{"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}},
{"daemon", {&allow_daemon}, justset, NULL, {{FALSE}, {TRUE}}},
{"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}},
{"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
{"export", {&export_settings}, justset, NULL, {{FALSE}, {TRUE}}},
{"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}},
{"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
{"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}},
{"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}},
{"smbntsec", {&allow_smbntsec}, justset, NULL, {{FALSE}, {TRUE}}},
{"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}},
{"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}},
{"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}},
{"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}},
{"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
{"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{FALSE}, {TRUE}}},
{NULL, {0}, justset, 0, {{0}, {0}}}
};
/* Parse a string of the form "something=stuff somethingelse=more-stuff",
silently ignoring unknown "somethings". */
static void __stdcall
parse_options (char *buf)
{
int istrue;
char *p, *lasts;
parse_thing *k;
if (buf == NULL)
{
char newbuf[MAX_PATH + 7] = "CYGWIN";
for (k = known; k->name != NULL; k++)
if (k->remember)
{
strcat (strcat (newbuf, " "), k->remember);
free (k->remember);
k->remember = NULL;
}
if (!export_settings)
return;
newbuf[sizeof ("CYGWIN") - 1] = '=';
debug_printf ("%s", newbuf);
putenv (newbuf);
return;
}
buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
for (p = strtok_r (buf, " \t", &lasts);
p != NULL;
p = strtok_r (NULL, " \t", &lasts))
{
if (!(istrue = !strncasematch (p, "no", 2)))
p += 2;
else if (!(istrue = *p != '-'))
p++;
char ch, *eq;
if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
ch = *eq, *eq++ = '\0';
else
ch = 0;
for (parse_thing *k = known; k->name != NULL; k++)
if (strcasematch (p, k->name))
{
switch (k->disposition)
{
case isfunc:
k->setting.func ((!eq || !istrue) ?
k->values[istrue].s : eq);
debug_printf ("%s (called func)", k->name);
break;
case justset:
if (!istrue || !eq)
*k->setting.x = k->values[istrue].i;
else
*k->setting.x = strtol (eq, NULL, 0);
debug_printf ("%s %d", k->name, *k->setting.x);
break;
case set_process_state:
k->setting.x = &myself->process_state;
/* fall through */
case setbit:
*k->setting.x &= ~k->values[istrue].i;
if (istrue || (eq && strtol (eq, NULL, 0)))
*k->setting.x |= k->values[istrue].i;
debug_printf ("%s %x", k->name, *k->setting.x);
break;
}
if (eq)
*--eq = ch;
int n = eq - p;
p = strdup (p);
if (n > 0)
p[n] = ':';
k->remember = p;
break;
}
}
debug_printf ("returning");
return;
}
/* Set options from the registry. */
static void __stdcall
regopt (const char *name)
{
/* FIXME: should not be under mount */
reg_key r (KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
char buf[MAX_PATH];
char lname[strlen(name) + 1];
strlwr (strcpy (lname, name));
if (r.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
parse_options (buf);
else
{
reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
if (r1.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
parse_options (buf);
}
MALLOC_CHECK;
}
/* Initialize the environ array. Look for the CYGWIN environment
environment variable and set appropriate options from it. */
void
environ_init (char **envp, int envc)
{
char *rawenv;
int i;
char *p;
char *newp;
int sawTERM = 0;
bool envp_passed_in;
static char NO_COPY cygterm[] = "TERM=cygwin";
static int initted;
if (!initted)
{
for (int i = 0; conv_envvars[i].name != NULL; i++)
{
conv_start_chars[cyg_tolower(conv_envvars[i].name[0])] = 1;
conv_start_chars[cyg_toupper(conv_envvars[i].name[0])] = 1;
}
initted = 1;
}
regopt ("default");
if (myself->progname[0])
regopt (myself->progname);
#ifdef NTSEC_ON_BY_DEFAULT
/* Set ntsec explicit as default, if NT is running */
if (wincap.has_security ())
allow_ntsec = TRUE;
#endif
if (!envp)
envp_passed_in = 0;
else
{
char **newenv = (char **) malloc (envc);
memcpy (newenv, envp, envc);
cfree (envp);
/* Older applications relied on the fact that cygwin malloced elements of the
environment list. */
envp = newenv;
if (ENVMALLOC)
for (char **e = newenv; *e; e++)
{
char *p = *e;
*e = strdup (p);
cfree (p);
}
envp_passed_in = 1;
goto out;
}
/* Allocate space for environment + trailing NULL + CYGWIN env. */
lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
rawenv = GetEnvironmentStrings ();
/* Current directory information is recorded as variables of the
form "=X:=X:\foo\bar; these must be changed into something legal
(we could just ignore them but maybe an application will
eventually want to use them). */
for (i = 0, p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1, i++)
{
newp = strdup (p);
if (i >= envc)
envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
envp[i] = newp;
if (*newp == '=')
*newp = '!';
char *eq;
if ((eq = strchr (newp, '=')) == NULL)
eq = strchr (newp, '\0');
if (!myself->ppid_handle)
ucenv (newp, eq);
if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
sawTERM = 1;
if (*newp == 'C' && strncmp (newp, "CYGWIN=", sizeof("CYGWIN=") - 1) == 0)
parse_options (newp + sizeof("CYGWIN=") - 1);
if (*eq && conv_start_chars[(unsigned char)envp[i][0]])
posify (envp + i, *++eq ? eq : --eq);
debug_printf ("%p: %s", envp[i], envp[i]);
}
if (!sawTERM)
envp[i++] = cygterm;
envp[i] = NULL;
FreeEnvironmentStrings (rawenv);
out:
__cygwin_environ = envp;
update_envptrs ();
if (envp_passed_in)
{
p = getenv ("CYGWIN");
if (p)
parse_options (p);
}
parse_options (NULL);
MALLOC_CHECK;
}
/* Function called by qsort to sort environment strings. */
static int
env_sort (const void *a, const void *b)
{
const char **p = (const char **) a;
const char **q = (const char **) b;
return strcmp (*p, *q);
}
/* Keep this list in upper case and sorted */
static const NO_COPY char* forced_winenv_vars [] =
{
"SYSTEMDRIVE",
"SYSTEMROOT",
NULL
};
#define FORCED_WINENV_SIZE (sizeof (forced_winenv_vars) / sizeof (forced_winenv_vars[0]))
/* Create a Windows-style environment block, i.e. a typical character buffer
filled with null terminated strings, terminated by double null characters.
Converts environment variables noted in conv_envvars into win32 form
prior to placing them in the string. */
char * __stdcall
winenv (const char * const *envp, int keep_posix)
{
int len, n, tl;
const char * const *srcp;
const char **dstp;
bool saw_forced_winenv[FORCED_WINENV_SIZE] = {0};
char *p;
debug_printf ("envp %p, keep_posix %d", envp, keep_posix);
tl = 0;
for (n = 0; envp[n]; n++)
continue;
const char *newenvp[n + 1 + FORCED_WINENV_SIZE];
for (srcp = envp, dstp = newenvp; *srcp; srcp++, dstp++)
{
len = strcspn (*srcp, "=");
win_env *conv;
if (keep_posix || !(conv = getwinenv (*srcp, *srcp + len + 1)))
*dstp = *srcp;
else
{
p = (char *) alloca (strlen (conv->native) + 1);
strcpy (p, conv->native);
*dstp = p;
}
tl += strlen (*dstp) + 1;
if ((*dstp)[0] == '!' && isdrive ((*dstp) + 1) && (*dstp)[3] == '=')
{
p = (char *) alloca (strlen (*dstp) + 1);
strcpy (p, *dstp);
*p = '=';
*dstp = p;
}
for (int i = 0; forced_winenv_vars[i]; i++)
if (!saw_forced_winenv[i])
saw_forced_winenv[i] = strncasematch (forced_winenv_vars[i], *srcp, len);
}
char dum[1];
for (int i = 0; forced_winenv_vars[i]; i++)
if (!saw_forced_winenv[i])
{
int vallen = GetEnvironmentVariable (forced_winenv_vars[i], dum, 0);
if (vallen > 0)
{
int namelen = strlen (forced_winenv_vars[i]) + 1;
p = (char *) alloca (namelen + ++vallen);
strcpy (p, forced_winenv_vars[i]);
strcat (p, "=");
if (!GetEnvironmentVariable (forced_winenv_vars[i], p + namelen,
vallen))
debug_printf ("warning: %s not present in environment", *srcp);
else
{
*dstp++ = p;
tl += strlen (p) + 1;
}
}
}
*dstp = NULL; /* Terminate */
int envlen = dstp - newenvp;
debug_printf ("env count %d, bytes %d", envlen, tl);
/* Windows programs expect the environment block to be sorted. */
qsort (newenvp, envlen, sizeof (char *), env_sort);
/* Create an environment block suitable for passing to CreateProcess. */
char *ptr, *envblock;
envblock = (char *) malloc (tl + 2);
for (srcp = newenvp, ptr = envblock; *srcp; srcp++)
{
len = strlen (*srcp);
memcpy (ptr, *srcp, len + 1);
ptr += len + 1;
}
*ptr = '\0'; /* Two null bytes at the end */
return envblock;
}
/* This idiocy is necessary because the early implementers of cygwin
did not seem to know about importing data variables from the DLL.
So, we have to synchronize cygwin's idea of the environment with the
main program's with each reference to the environment. */
extern "C" char ** __stdcall
cur_environ ()
{
if (*main_environ != __cygwin_environ)
{
__cygwin_environ = *main_environ;
update_envptrs ();
}
return __cygwin_environ;
}