Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / ACE / tests / Process_Test.cpp
blob328702994b54b85478a359f3535fef4de3ff254d
2 //=============================================================================
3 /**
4 * @file Process_Test.cpp
6 * Tests ACE_Process file handle inheritance for UNIX-like systems
8 * @author Christian Fromme <kaner@strace.org>
9 */
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/";
27 int
28 test_setenv (void)
30 int status = 0;
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");
39 # else
40 const ACE_TCHAR *fmt = ACE_TEXT ("%s");
41 # endif
43 if (0 != opts.setenv (ACE_TEXT ("A"), fmt, bigval))
45 status = errno;
46 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("setenv")));
48 else
50 size_t env_len = ACE_OS::strlen (opts.env_buf ());
51 if (env_len != 5002)
53 status = 1;
54 ACE_ERROR ((LM_ERROR,
55 ACE_TEXT ("setenv result should be 5002 chars, not %B\n"),
56 env_len));
59 #endif
60 return status;
64 int
65 check_temp_file (const ACE_TString &tmpfilename)
67 ACE_DIRENT *dir = 0;
68 ACE_Dirent entr;
69 ACE_stat stat;
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"),
79 proc_self_fd),
80 -1);
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);
87 #else
88 fullp += dir->d_name;
89 #endif
91 if ((ACE_OS::lstat (fullp.c_str (), &stat)) == -1)
92 ACE_ERROR_RETURN ((LM_ERROR,
93 ACE_TEXT ("Stat failed for %C\n"),
94 fullp.c_str ()),
95 -1);
97 if (S_ISLNK (stat.st_mode))
99 ssize_t size = 0;
100 if ((size= ACE_OS::readlink (fullp.c_str (),
101 filename,
102 MAXPATHLEN + 1)) == -1)
103 ACE_ERROR_RETURN ((LM_ERROR,
104 ACE_TEXT ("Readlink failed for %C\n"),
105 fullp.c_str ()),
106 -1);
107 filename[size] = '\0';
108 if (tmpfilename == ACE_TString (ACE_TEXT_CHAR_TO_TCHAR (filename)))
109 return 1;
113 return 0;
117 run_parent (bool inherit_files)
119 int status = 0;
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")));
135 status = 1;
138 // Build child options
139 ACE_TString exe_sub_dir;
140 const char *subdir_env = ACE_OS::getenv ("ACE_EXE_SUB_DIR");
141 if (subdir_env)
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"),
153 exe_sub_dir.c_str(),
154 (int)inherit_files,
155 tempfile);
156 #endif
157 options.handle_inheritance (inherit_files); /* ! */
159 // Spawn child
160 ACE_Process child;
162 pid_t result = child.spawn (options);
163 if (result == -1)
165 status = errno;
166 ACE_ERROR ((LM_ERROR,
167 ACE_TEXT ("Parent could NOT spawn child process\n")));
169 else
170 ACE_DEBUG ((LM_DEBUG,
171 ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
172 child.getpid ()));
174 ACE_exitcode child_status;
175 result = child.wait (&child_status);
176 if (result == -1)
178 status = errno;
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"),
184 child.getpid ()));
185 else
187 status = child_status;
188 ACE_ERROR ((LM_ERROR,
189 ACE_TEXT ("Child %d finished with status %d\n"),
190 child.getpid (), child_status));
193 return status;
197 run_main (int argc, ACE_TCHAR *argv[])
199 int c = 0;
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)
207 switch ((char) c)
209 case 'c':
210 ischild = true;
211 break;
212 case 'h':
213 handle_inherit = ACE_OS::atoi (getopt.opt_arg ());
214 break;
215 case 'f':
216 temp_file_name = getopt.opt_arg ();
217 break;
218 default:
219 // Don't forgive bad options
220 ACE_ERROR_RETURN ((LM_ERROR,
221 ACE_TEXT ("Bad option\n")),
222 -1);
223 break;
226 if (ischild)
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
236 if (result == -1)
237 ACE_ERROR_RETURN ((LM_ERROR,
238 ACE_TEXT ("Could not retrieve open files\n")),
239 -1);
240 else if (result == handle_inherit)
241 result = 0;
242 else
243 ACE_ERROR ((LM_ERROR,
244 ACE_TEXT ("Handle inheritance test failed with ")
245 ACE_TEXT ("%d, expected %d\n"), result, handle_inherit));
246 ACE_END_LOG;
247 return result;
249 else
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)
265 ACE_ERROR ((LM_INFO,
266 ACE_TEXT ("The remainder of this test is not supported on this platform\n")));
267 #else
268 // Test handle inheritance set to true
269 if (!status)
270 status = run_parent (true);
272 // ... and set to false
273 if (!status)
274 run_parent (false);
275 #endif /* ! ACE_LACKS_FORK */
277 ACE_END_TEST;
278 return status;