2 //=============================================================================
4 * @file Process_Test.cpp
6 * Tests ACE_Process file handle inheritance for UNIX-like systems
8 * @author Christian Fromme <kaner@strace.org>
10 //=============================================================================
12 #include "test_config.h"
13 #include "ace/Process.h"
14 #include "ace/Get_Opt.h"
15 #include "ace/Lib_Find.h"
16 #include "ace/OS_NS_string.h"
17 #include "ace/OS_NS_sys_stat.h"
18 #include "ace/OS_NS_unistd.h"
19 #include "ace/Dirent.h"
20 #include "ace/SString.h"
21 #include "ace/OS_NS_stdlib.h"
23 // This will only work on Linux. Even UNIX-ish with /proc filesys lacks the
24 // 'self' level and link to the opened file name.
25 static const char *proc_self_fd
= "/proc/self/fd/";
31 ACE_Process_Options opts
;
32 ACE_TCHAR bigval
[5010] = ACE_TEXT ("");
33 for (int i
= 0; i
< 100; ++i
)
34 ACE_OS::strcat (bigval
,
35 ACE_TEXT ("01234567890123456789012345678901234567890123456789"));
36 #ifndef ACE_LACKS_VA_FUNCTIONS
37 # if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
38 const ACE_TCHAR
*fmt
= ACE_TEXT ("%ls");
40 const ACE_TCHAR
*fmt
= ACE_TEXT ("%s");
43 if (0 != opts
.setenv (ACE_TEXT ("A"), fmt
, bigval
))
46 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("setenv")));
50 size_t env_len
= ACE_OS::strlen (opts
.env_buf ());
55 ACE_TEXT ("setenv result should be 5002 chars, not %B\n"),
65 check_temp_file (const ACE_TString
&tmpfilename
)
70 char filename
[MAXPATHLEN
+ 1];
72 ACE_OS::memset (&stat
, 0, sizeof (stat
));
73 ACE_OS::memset (&entr
, 0, sizeof (entr
));
75 // Loop through /proc/self/fs/
76 if (entr
.open (ACE_TEXT_CHAR_TO_TCHAR(proc_self_fd
)) == -1)
77 ACE_ERROR_RETURN ((LM_ERROR
,
78 ACE_TEXT ("Could not open dir %C\n"),
82 while ((dir
= entr
.read ()))
84 ACE_CString fullp
= proc_self_fd
;
85 #if defined (ACE_HAS_TCHAR_DIRENT)
86 fullp
+= ACE_TEXT_ALWAYS_CHAR(dir
->d_name
);
91 if ((ACE_OS::lstat (fullp
.c_str (), &stat
)) == -1)
92 ACE_ERROR_RETURN ((LM_ERROR
,
93 ACE_TEXT ("Stat failed for %C\n"),
97 if (S_ISLNK (stat
.st_mode
))
100 if ((size
= ACE_OS::readlink (fullp
.c_str (),
102 MAXPATHLEN
+ 1)) == -1)
103 ACE_ERROR_RETURN ((LM_ERROR
,
104 ACE_TEXT ("Readlink failed for %C\n"),
107 filename
[size
] = '\0';
108 if (tmpfilename
== ACE_TString (ACE_TEXT_CHAR_TO_TCHAR (filename
)))
117 run_parent (bool inherit_files
)
121 ACE_TCHAR t
[] = ACE_TEXT ("ace_testXXXXXX");
123 // Create tempfile. This will be tested for inheritance.
124 ACE_TCHAR tempfile
[MAXPATHLEN
+ 1];
126 if (ACE::get_temp_dir (tempfile
, MAXPATHLEN
- sizeof (t
)) == -1)
127 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could not get temp dir\n")));
129 ACE_OS::strcat (tempfile
, t
);
131 ACE_HANDLE file_handle
= ACE_OS::mkstemp (tempfile
);
132 if (file_handle
== ACE_INVALID_HANDLE
)
134 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could not get temp filename\n")));
138 // Build child options
139 ACE_TString exe_sub_dir
;
140 const char *subdir_env
= ACE_OS::getenv ("ACE_EXE_SUB_DIR");
143 exe_sub_dir
= ACE_TEXT_CHAR_TO_TCHAR (subdir_env
);
144 exe_sub_dir
+= ACE_DIRECTORY_SEPARATOR_STR
;
147 ACE_Process_Options options
;
148 #ifndef ACE_LACKS_VA_FUNCTIONS
149 options
.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
150 ACE_TEXT ("%sProcess_Test")
151 ACE_PLATFORM_EXE_SUFFIX
152 ACE_TEXT (" -c -h %d -f %s"),
157 options
.handle_inheritance (inherit_files
); /* ! */
162 pid_t result
= child
.spawn (options
);
166 ACE_ERROR ((LM_ERROR
,
167 ACE_TEXT ("Parent could NOT spawn child process\n")));
170 ACE_DEBUG ((LM_DEBUG
,
171 ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
174 ACE_exitcode child_status
;
175 result
= child
.wait (&child_status
);
179 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could NOT wait on child process\n")));
181 else if (child_status
== 0)
182 ACE_DEBUG ((LM_DEBUG
,
183 ACE_TEXT ("Child %d finished ok\n"),
187 status
= child_status
;
188 ACE_ERROR ((LM_ERROR
,
189 ACE_TEXT ("Child %d finished with status %d\n"),
190 child
.getpid (), child_status
));
197 run_main (int argc
, ACE_TCHAR
*argv
[])
200 int handle_inherit
= 0; /* Disable inheritance by default */
201 bool ischild
= false;
202 ACE_TString temp_file_name
;
204 ACE_Get_Opt
getopt (argc
, argv
, ACE_TEXT ("ch:f:"));
206 while ((c
= getopt ()) != -1)
213 handle_inherit
= ACE_OS::atoi (getopt
.opt_arg ());
216 temp_file_name
= getopt
.opt_arg ();
219 // Don't forgive bad options
220 ACE_ERROR_RETURN ((LM_ERROR
,
221 ACE_TEXT ("Bad option\n")),
228 ACE_TCHAR lognm
[MAXPATHLEN
];
229 int const mypid (ACE_OS::getpid ());
230 ACE_OS::snprintf (lognm
, MAXPATHLEN
,
231 ACE_TEXT ("Process_Test-child-%d"), mypid
);
232 ACE_START_TEST (lognm
);
234 int result
= check_temp_file (temp_file_name
);
235 // Check descriptor inheritance
237 ACE_ERROR_RETURN ((LM_ERROR
,
238 ACE_TEXT ("Could not retrieve open files\n")),
240 else if (result
== handle_inherit
)
243 ACE_ERROR ((LM_ERROR
,
244 ACE_TEXT ("Handle inheritance test failed with ")
245 ACE_TEXT ("%d, expected %d\n"), result
, handle_inherit
));
251 ACE_START_TEST (ACE_TEXT ("Process_Test"));
253 int status
= test_setenv ();
255 // The rest of this test relies on the ability to get a list of open
256 // files for a process and examine each file descriptor to see which
257 // file is open, matching against an expected opened file name.
258 // Although most systems provide some mechanism to do this, the code
259 // in this test uses Linux-specific techniques. Thus, although it
260 // is possible to add the code for the checks on, for example,
261 // HP-UX (pstat_getproc, pstat_getpathname) and
262 // AIX (/proc is available, but there's no self and the fds are not links
263 // to the opened file names), the code isn't here at present.
264 #if defined (ACE_LACKS_FORK) || defined (ACE_LACKS_READLINK) || !defined(ACE_LINUX)
266 ACE_TEXT ("The remainder of this test is not supported on this platform\n")));
268 // Test handle inheritance set to true
270 status
= run_parent (true);
272 // ... and set to false
275 #endif /* ! ACE_LACKS_FORK */