OSDN Git Service

* dcrt0.cc (dll_crt0_1): Move internal locale setting prior to potential
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / external.cc
1 /* external.cc: Interface to Cygwin internals from external programs.
2
3    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4    2006, 2007, 2008, 2009 Red Hat, Inc.
5
6    Written by Christopher Faylor <cgf@cygnus.com>
7
8 This file is part of Cygwin.
9
10 This software is a copyrighted work licensed under the terms of the
11 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
12 details. */
13
14 #include "winsup.h"
15 #include "sigproc.h"
16 #include "pinfo.h"
17 #include "shared_info.h"
18 #include "cygwin_version.h"
19 #include "cygerrno.h"
20 #include "path.h"
21 #include "fhandler.h"
22 #include "dtable.h"
23 #include "cygheap.h"
24 #include "heap.h"
25 #include "cygtls.h"
26 #include "child_info.h"
27 #include "environ.h"
28 #include "cygserver_setpwd.h"
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <wchar.h>
32 #include <iptypes.h>
33
34 child_info *get_cygwin_startup_info ();
35 static void exit_process (UINT, bool) __attribute__((noreturn));
36
37 static winpids pids;
38
39 static external_pinfo *
40 fillout_pinfo (pid_t pid, int winpid)
41 {
42   BOOL nextpid;
43   static external_pinfo ep;
44   static char ep_progname_long_buf[NT_MAX_PATH];
45
46   if ((nextpid = !!(pid & CW_NEXTPID)))
47     pid ^= CW_NEXTPID;
48
49
50   static unsigned int i;
51   if (!pids.npids || !nextpid)
52     {
53       pids.set (winpid);
54       i = 0;
55     }
56
57   if (!pid)
58     i = 0;
59
60   memset (&ep, 0, sizeof ep);
61   while (i < pids.npids)
62     {
63       DWORD thispid = pids.winpid (i);
64       _pinfo *p = pids[i];
65       i++;
66
67       if (!p)
68         {
69           if (!nextpid && thispid != (DWORD) pid)
70             continue;
71           ep.pid = cygwin_pid (thispid);
72           ep.dwProcessId = thispid;
73           ep.process_state = PID_IN_USE;
74           ep.ctty = -1;
75           break;
76         }
77       else if (nextpid || p->pid == pid || (winpid && thispid == (DWORD) pid))
78         {
79           ep.ctty = p->ctty;
80           ep.pid = p->pid;
81           ep.ppid = p->ppid;
82           ep.dwProcessId = p->dwProcessId;
83           ep.uid = p->uid;
84           ep.gid = p->gid;
85           ep.pgid = p->pgid;
86           ep.sid = p->sid;
87           ep.umask = 0;
88           ep.start_time = p->start_time;
89           ep.rusage_self = p->rusage_self;
90           ep.rusage_children = p->rusage_children;
91           ep.progname[0] = '\0';
92           strncat (ep.progname, p->progname, MAX_PATH - 1);
93           ep.strace_mask = 0;
94           ep.version = EXTERNAL_PINFO_VERSION;
95
96           ep.process_state = p->process_state;
97
98           ep.uid32 = p->uid;
99           ep.gid32 = p->gid;
100
101           ep.progname_long = ep_progname_long_buf;
102           strcpy (ep.progname_long, p->progname);
103           break;
104         }
105     }
106
107   if (!ep.pid)
108     {
109       i = 0;
110       pids.reset ();
111       return 0;
112     }
113   return &ep;
114 }
115
116 static inline DWORD
117 get_cygdrive_info (char *user, char *system, char *user_flags,
118                    char *system_flags)
119 {
120   int res = mount_table->get_cygdrive_info (user, system, user_flags,
121                                             system_flags);
122   return (res == ERROR_SUCCESS) ? 1 : 0;
123 }
124
125 static DWORD
126 check_ntsec (const char *filename)
127 {
128   if (!filename)
129     return true;
130   path_conv pc (filename);
131   return pc.has_acls ();
132 }
133
134 /* Copy cygwin environment variables to the Windows environment. */
135 static void
136 sync_winenv ()
137 {
138   int unused_envc;
139   PWCHAR envblock = NULL;
140   char **envp = build_env (cur_environ (), envblock, unused_envc, false);
141   PWCHAR p = envblock;
142
143   if (envp)
144     {
145       for (char **e = envp; *e; e++)
146         cfree (*e);
147       cfree (envp);
148     }
149   if (!p)
150     return;
151   while (*p)
152     {
153       PWCHAR eq = wcschr (p, L'=');
154       if (eq)
155         {
156           *eq = L'\0';
157           SetEnvironmentVariableW (p, ++eq);
158           p = eq;
159         }
160       p = wcschr (p, L'\0') + 1;
161     }
162   free (envblock);
163 }
164
165 /*
166  * Cygwin-specific wrapper for win32 ExitProcess and TerminateProcess.
167  * It ensures that the correct exit code, derived from the specified
168  * status value, will be made available to this process's parent (if
169  * that parent is also a cygwin process). If useTerminateProcess is
170  * true, then TerminateProcess(GetCurrentProcess(),...) will be used;
171  * otherwise, ExitProcess(...) is called.
172  *
173  * Used by startup code for cygwin processes which is linked statically
174  * into applications, and is not part of the cygwin DLL -- which is why
175  * this interface is exposed. "Normal" programs should use ANSI exit(),
176  * ANSI abort(), or POSIX _exit(), rather than this function -- because
177  * calling ExitProcess or TerminateProcess, even through this wrapper,
178  * skips much of the cygwin process cleanup code.
179  */
180 static void
181 exit_process (UINT status, bool useTerminateProcess)
182 {
183   pid_t pid = getpid ();
184   external_pinfo * ep = fillout_pinfo (pid, 1);
185   DWORD dwpid = ep ? ep->dwProcessId : pid;
186   pinfo p (pid, PID_MAP_RW);
187   if ((dwpid == GetCurrentProcessId()) && (p->pid == ep->pid))
188     p.set_exit_code ((DWORD)status);
189   if (useTerminateProcess)
190     TerminateProcess (GetCurrentProcess(), status);
191   /* avoid 'else' clause to silence warning */
192   ExitProcess (status);
193 }
194
195
196 extern "C" unsigned long
197 cygwin_internal (cygwin_getinfo_types t, ...)
198 {
199   va_list arg;
200   unsigned long res = -1;
201   va_start (arg, t);
202
203   switch (t)
204     {
205       case CW_LOCK_PINFO:
206         res = 1;
207         break;
208
209       case CW_UNLOCK_PINFO:
210         res = 1;
211         break;
212
213       case CW_GETTHREADNAME:
214         res = (DWORD) cygthread::name (va_arg (arg, DWORD));
215         break;
216
217       case CW_SETTHREADNAME:
218         {
219           set_errno (ENOSYS);
220           res = 0;
221         }
222         break;
223
224       case CW_GETPINFO:
225         res = (DWORD) fillout_pinfo (va_arg (arg, DWORD), 0);
226         break;
227
228       case CW_GETVERSIONINFO:
229         res = (DWORD) cygwin_version_strings;
230         break;
231
232       case CW_READ_V1_MOUNT_TABLES:
233         set_errno (ENOSYS);
234         res = 1;
235         break;
236
237       case CW_USER_DATA:
238         /* This is a kludge to work around a version of _cygwin_common_crt0
239            which overwrote the cxx_malloc field with the local DLL copy.
240            Hilarity ensues if the DLL is not loaded like while the process
241            is forking. */
242         __cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc;
243         res = (DWORD) &__cygwin_user_data;
244         break;
245
246       case CW_PERFILE:
247         perfile_table = va_arg (arg, struct __cygwin_perfile *);
248         res = 0;
249         break;
250
251       case CW_GET_CYGDRIVE_PREFIXES:
252         {
253           char *user = va_arg (arg, char *);
254           char *system = va_arg (arg, char *);
255           res = get_cygdrive_info (user, system, NULL, NULL);
256         }
257         break;
258
259       case CW_GETPINFO_FULL:
260         res = (DWORD) fillout_pinfo (va_arg (arg, pid_t), 1);
261         break;
262
263       case CW_INIT_EXCEPTIONS:
264         /* noop */ /* init_exceptions (va_arg (arg, exception_list *)); */
265         res = 0;
266         break;
267
268       case CW_GET_CYGDRIVE_INFO:
269         {
270           char *user = va_arg (arg, char *);
271           char *system = va_arg (arg, char *);
272           char *user_flags = va_arg (arg, char *);
273           char *system_flags = va_arg (arg, char *);
274           res = get_cygdrive_info (user, system, user_flags, system_flags);
275         }
276         break;
277
278       case CW_SET_CYGWIN_REGISTRY_NAME:
279       case CW_GET_CYGWIN_REGISTRY_NAME:
280         res = 0;
281         break;
282
283       case CW_STRACE_TOGGLE:
284         {
285           pid_t pid = va_arg (arg, pid_t);
286           pinfo p (pid);
287           if (p)
288             {
289               sig_send (p, __SIGSTRACE);
290               res = 0;
291             }
292           else
293             {
294               set_errno (ESRCH);
295               res = (DWORD) -1;
296             }
297         }
298         break;
299
300       case CW_STRACE_ACTIVE:
301         {
302           res = strace.active ();
303         }
304         break;
305
306       case CW_CYGWIN_PID_TO_WINPID:
307         {
308           pinfo p (va_arg (arg, pid_t));
309           res = p ? p->dwProcessId : 0;
310         }
311         break;
312       case CW_EXTRACT_DOMAIN_AND_USER:
313         {
314           WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1];
315           WCHAR nt_user[UNLEN + 1];
316
317           struct passwd *pw = va_arg (arg, struct passwd *);
318           char *domain = va_arg (arg, char *);
319           char *user = va_arg (arg, char *);
320           extract_nt_dom_user (pw, nt_domain, nt_user);
321           if (domain)
322             sys_wcstombs (domain, MAX_DOMAIN_NAME_LEN + 1, nt_domain);
323           if (user)
324             sys_wcstombs (user, UNLEN + 1, nt_user);
325           res = 0;
326         }
327         break;
328       case CW_CMDLINE:
329         {
330           size_t n;
331           pid_t pid = va_arg (arg, pid_t);
332           pinfo p (pid);
333           res = (DWORD) p->cmdline (n);
334         }
335         break;
336       case CW_CHECK_NTSEC:
337         {
338           char *filename = va_arg (arg, char *);
339           res = check_ntsec (filename);
340         }
341         break;
342       case CW_GET_ERRNO_FROM_WINERROR:
343         {
344           int error = va_arg (arg, int);
345           int deferrno = va_arg (arg, int);
346           res = geterrno_from_win_error (error, deferrno);
347         }
348         break;
349       case CW_GET_POSIX_SECURITY_ATTRIBUTE:
350         {
351           path_conv dummy;
352           security_descriptor sd;
353           int attribute = va_arg (arg, int);
354           PSECURITY_ATTRIBUTES psa = va_arg (arg, PSECURITY_ATTRIBUTES);
355           void *sd_buf = va_arg (arg, void *);
356           DWORD sd_buf_size = va_arg (arg, DWORD);
357           set_security_attribute (dummy, attribute, psa, sd);
358           if (!psa->lpSecurityDescriptor)
359             res = sd.size ();
360           else
361             {
362               psa->lpSecurityDescriptor = sd_buf;
363               res = sd.copy (sd_buf, sd_buf_size);
364             }
365         }
366         break;
367       case CW_GET_SHMLBA:
368         {
369           res = getpagesize ();
370         }
371         break;
372       case CW_GET_UID_FROM_SID:
373         {
374           cygpsid psid = va_arg (arg, PSID);
375           res = psid.get_id (false, NULL);
376         }
377         break;
378       case CW_GET_GID_FROM_SID:
379         {
380           cygpsid psid = va_arg (arg, PSID);
381           res = psid.get_id (true, NULL);
382         }
383         break;
384       case CW_GET_BINMODE:
385         {
386           const char *path = va_arg (arg, const char *);
387           path_conv p (path, PC_SYM_FOLLOW | PC_NULLEMPTY);
388           if (p.error)
389             {
390               set_errno (p.error);
391               res = (unsigned long) -1;
392             }
393           else
394             res = p.binmode ();
395         }
396         break;
397       case CW_HOOK:
398         {
399           const char *name = va_arg (arg, const char *);
400           const void *hookfn = va_arg (arg, const void *);
401           WORD subsys;
402           res = (unsigned long) hook_or_detect_cygwin (name, hookfn, subsys);
403         }
404         break;
405       case CW_ARGV:
406         {
407           child_info_spawn *ci = (child_info_spawn *) get_cygwin_startup_info ();
408           res = (unsigned long) (ci ? ci->moreinfo->argv : NULL);
409         }
410         break;
411       case CW_ENVP:
412         {
413           child_info_spawn *ci = (child_info_spawn *) get_cygwin_startup_info ();
414           res = (unsigned long) (ci ? ci->moreinfo->envp : NULL);
415         }
416         break;
417       case CW_DEBUG_SELF:
418         error_start_init (va_arg (arg, const char *));
419         try_to_debug ();
420         break;
421       case CW_SYNC_WINENV:
422         sync_winenv ();
423         res = 0;
424         break;
425       case CW_CYGTLS_PADSIZE:
426         res = CYGTLS_PADSIZE;
427         break;
428       case CW_SET_DOS_FILE_WARNING:
429         {
430           extern bool dos_file_warning;
431           dos_file_warning = va_arg (arg, int);
432           res = 0;
433         }
434         break;
435       case CW_SET_PRIV_KEY:
436         {
437           const char *passwd = va_arg (arg, const char *);
438           res = setlsapwd (passwd);
439         }
440         break;
441       case CW_SETERRNO:
442         {
443           const char *file = va_arg (arg, const char *);
444           int line = va_arg (arg, int);
445           seterrno(file, line);
446           res = 0;
447         }
448         break;
449       case CW_EXIT_PROCESS:
450         {
451           UINT status = va_arg (arg, UINT);
452           int useTerminateProcess = va_arg (arg, int);
453           exit_process (status, !!useTerminateProcess); /* no return */
454         }
455       case CW_SET_EXTERNAL_TOKEN:
456         {
457           HANDLE token = va_arg (arg, HANDLE);
458           int type = va_arg (arg, int);
459           set_imp_token (token, type);
460           res = 0;
461         }
462         break;
463       case CW_GET_INSTKEY:
464         {
465           extern WCHAR installation_key_buf[18];
466           PWCHAR dest = va_arg (arg, PWCHAR);
467           wcscpy (dest, installation_key_buf);
468           res = 0;
469         }
470         break;
471
472       default:
473         set_errno (ENOSYS);
474     }
475   va_end (arg);
476   return res;
477 }