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 (0 != opts
.setenv (ACE_TEXT ("A"), ACE_TEXT ("%") ACE_TEXT_PRIs
, bigval
))
40 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("setenv")));
44 size_t env_len
= ACE_OS::strlen (opts
.env_buf ());
49 ACE_TEXT ("setenv result should be 5002 chars, not %B\n"),
59 check_temp_file (const ACE_TString
&tmpfilename
)
64 char filename
[MAXPATHLEN
+ 1];
66 ACE_OS::memset (&stat
, 0, sizeof (stat
));
67 ACE_OS::memset (&entr
, 0, sizeof (entr
));
69 // Loop through /proc/self/fs/
70 if (entr
.open (ACE_TEXT_CHAR_TO_TCHAR(proc_self_fd
)) == -1)
71 ACE_ERROR_RETURN ((LM_ERROR
,
72 ACE_TEXT ("Could not open dir %C\n"),
76 while ((dir
= entr
.read ()))
78 ACE_CString fullp
= proc_self_fd
;
79 #if defined (ACE_HAS_TCHAR_DIRENT)
80 fullp
+= ACE_TEXT_ALWAYS_CHAR(dir
->d_name
);
85 if ((ACE_OS::lstat (fullp
.c_str (), &stat
)) == -1)
86 ACE_ERROR_RETURN ((LM_ERROR
,
87 ACE_TEXT ("Stat failed for %C\n"),
91 if (S_ISLNK (stat
.st_mode
))
94 if ((size
= ACE_OS::readlink (fullp
.c_str (),
96 MAXPATHLEN
+ 1)) == -1)
97 ACE_ERROR_RETURN ((LM_ERROR
,
98 ACE_TEXT ("Readlink failed for %C\n"),
101 filename
[size
] = '\0';
102 if (tmpfilename
== ACE_TString (ACE_TEXT_CHAR_TO_TCHAR (filename
)))
111 run_parent (bool inherit_files
)
115 ACE_TCHAR t
[] = ACE_TEXT ("ace_testXXXXXX");
117 // Create tempfile. This will be tested for inheritance.
118 ACE_TCHAR tempfile
[MAXPATHLEN
+ 1];
120 if (ACE::get_temp_dir (tempfile
, MAXPATHLEN
- sizeof (t
)) == -1)
121 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could not get temp dir\n")));
123 ACE_OS::strcat (tempfile
, t
);
125 ACE_HANDLE file_handle
= ACE_OS::mkstemp (tempfile
);
126 if (file_handle
== ACE_INVALID_HANDLE
)
128 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could not get temp filename\n")));
132 // Build child options
133 ACE_TString exe_sub_dir
;
134 const char *subdir_env
= ACE_OS::getenv ("ACE_EXE_SUB_DIR");
137 exe_sub_dir
= ACE_TEXT_CHAR_TO_TCHAR (subdir_env
);
138 exe_sub_dir
+= ACE_DIRECTORY_SEPARATOR_STR
;
141 ACE_Process_Options options
;
142 #ifndef ACE_LACKS_VA_FUNCTIONS
143 options
.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
144 ACE_TEXT ("%sProcess_Test")
145 ACE_PLATFORM_EXE_SUFFIX
146 ACE_TEXT (" -c -h %d -f %s"),
151 options
.handle_inheritance (inherit_files
); /* ! */
156 pid_t result
= child
.spawn (options
);
160 ACE_ERROR ((LM_ERROR
,
161 ACE_TEXT ("Parent could NOT spawn child process\n")));
164 ACE_DEBUG ((LM_DEBUG
,
165 ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
168 ACE_exitcode child_status
;
169 result
= child
.wait (&child_status
);
173 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Could NOT wait on child process\n")));
175 else if (child_status
== 0)
176 ACE_DEBUG ((LM_DEBUG
,
177 ACE_TEXT ("Child %d finished ok\n"),
181 status
= child_status
;
182 ACE_ERROR ((LM_ERROR
,
183 ACE_TEXT ("Child %d finished with status %d\n"),
184 child
.getpid (), child_status
));
191 run_main (int argc
, ACE_TCHAR
*argv
[])
194 int handle_inherit
= 0; /* Disable inheritance by default */
195 bool ischild
= false;
196 ACE_TString temp_file_name
;
198 ACE_Get_Opt
getopt (argc
, argv
, ACE_TEXT ("ch:f:"));
200 while ((c
= getopt ()) != -1)
207 handle_inherit
= ACE_OS::atoi (getopt
.opt_arg ());
210 temp_file_name
= getopt
.opt_arg ();
213 // Don't forgive bad options
214 ACE_ERROR_RETURN ((LM_ERROR
,
215 ACE_TEXT ("Bad option\n")),
222 ACE_TCHAR lognm
[MAXPATHLEN
];
223 int const mypid (ACE_OS::getpid ());
224 ACE_OS::snprintf (lognm
, MAXPATHLEN
,
225 ACE_TEXT ("Process_Test-child-%d"), mypid
);
226 ACE_START_TEST (lognm
);
228 int result
= check_temp_file (temp_file_name
);
229 // Check descriptor inheritance
231 ACE_ERROR_RETURN ((LM_ERROR
,
232 ACE_TEXT ("Could not retrieve open files\n")),
234 else if (result
== handle_inherit
)
237 ACE_ERROR ((LM_ERROR
,
238 ACE_TEXT ("Handle inheritance test failed with ")
239 ACE_TEXT ("%d, expected %d\n"), result
, handle_inherit
));
245 ACE_START_TEST (ACE_TEXT ("Process_Test"));
247 int status
= test_setenv ();
249 // The rest of this test relies on the ability to get a list of open
250 // files for a process and examine each file descriptor to see which
251 // file is open, matching against an expected opened file name.
252 // Although most systems provide some mechanism to do this, the code
253 // in this test uses Linux-specific techniques. Thus, although it
254 // is possible to add the code for the checks on, for example,
255 // HP-UX (pstat_getproc, pstat_getpathname)
256 #if defined (ACE_LACKS_FORK) || defined (ACE_LACKS_READLINK) || !defined(ACE_LINUX)
258 ACE_TEXT ("The remainder of this test is not supported on this platform\n")));
260 // Test handle inheritance set to true
262 status
= run_parent (true);
264 // ... and set to false
267 #endif /* ! ACE_LACKS_FORK */