feisty meow concerns codebase 2.140
application_configuration.cpp
Go to the documentation of this file.
1/*
2* Name : application_configuration
3* Author : Chris Koeritz
4
5* Copyright (c) 1994-$now By Author. This program is free software; you can
6* redistribute it and/or modify it under the terms of the GNU General Public
7* License as published by the Free Software Foundation; either version 2 of
8* the License or (at your option) any later version. This is online at:
9* http://www.fsf.org/copyleft/gpl.html
10* Please send any updates to: fred@gruntose.com
11*/
12
14#include "ini_configurator.h"
15
17#include <basis/environment.h>
18//#include <basis/enhance_cpp.h>
19#include <basis/functions.h>
20#include <basis/guards.h>
21#include <basis/mutex.h>
24#include <filesystem/filename.h>
25#include <mathematics/chaos.h>
27#include <textual/parser_bits.h>
28#include <system_helper.h>
29
30#ifdef __APPLE__
31 #include <mach-o/dyld.h>
32 #include <limits.h>
33#endif
34//#ifdef _MSC_VER
35// #include <direct.h>
36// #include <process.h>
37//#else
38 #include <dirent.h>
39 #include <sys/utsname.h>
40 #include <unistd.h>
41//#endif
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <sys/stat.h>
46
47using namespace basis;
48using namespace filesystem;
49using namespace mathematics;
50using namespace structures;
51using namespace textual;
52
53#undef LOG
54#define LOG(to_print) printf("%s\n", astring(to_print).s())
55
56namespace configuration {
57
59 // maximum command line that we'll deal with here.
60
61#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
63{
64 FUNCDEF("get_cmdline_from_proc");
65 static astring __check_once_app_path;
66//hmmm: we want to use a single per app static synch here!
67 if (__check_once_app_path.length()) return __check_once_app_path;
68
69#ifdef __APPLE__
70 __check_once_app_path = query_for_process_info();
71 return __check_once_app_path;
72#endif
73
74 // we have not looked this app's name up in the path yet.
75 a_sprintf cmds_filename("/proc/%d/cmdline", process_id());
76 FILE *cmds_file = fopen(cmds_filename.s(), "r");
77 if (!cmds_file) {
78 LOG("failed to open our process's command line file.\n");
79 return "unknown";
80 }
81//hmmm: this would be a lot nicer using a byte filer.
82 size_t size = 2000;
83 char *filebuff = new char[size + 1];
84 ssize_t chars_read = getline((char **)&filebuff, &size, cmds_file);
85 // read the first line, giving ample space for how long it might be.
86 fclose(cmds_file); // drop the file again.
87 if (!chars_read || negative(chars_read)) {
88 LOG("failed to get any characters from our process's cmdline file.\n");
89 return "unknown";
90 }
91 // copy the buffer into a string, which works great since the entries in the
92 // command line are all separated by zero characters.
93 __check_once_app_path = filebuff;
94 delete [] filebuff;
95//printf("got an app name before chewing: %s\n", __check_once_app_path.s());
96 // clean out quote characters from the name.
97 for (int i = __check_once_app_path.length() - 1; i >= 0; i--) {
98 if (__check_once_app_path[i] == '"') __check_once_app_path.zap(i, i);
99 }
100 // check if the thing has a path attached to it. if it doesn't, we need to accentuate
101 // our knowledge about the file.
102 filename testing(__check_once_app_path);
103 if (testing.had_directory()) return __check_once_app_path; // all set.
104
105//printf("no dir part found, app name after chewing: %s\n", __check_once_app_path.s());
106
107//hmmm: the below might be better off as a find app in path method, which relies on which.
108 // there was no directory component, so we'll try to guess one.
109 astring temp_filename(environment::TMP()
110 + a_sprintf("/zz_cmdfind.%d", chaos().inclusive(0, 999999999)));
111 system((astring("which ") + __check_once_app_path + " >" + temp_filename).s());
112 FILE *which_file = fopen(temp_filename.s(), "r");
113 if (!which_file) {
114 LOG("failed to open the temporary output from which.\n");
115 return "unknown";
116 }
117 // reallocate the file buffer.
118 size = 2000;
119 filebuff = new char[size + 1];
120 chars_read = getline((char **)&filebuff, &size, which_file);
121 fclose(which_file);
122 unlink(temp_filename.s());
123 if (!chars_read || negative(chars_read)) {
124 LOG("failed to get any characters from the which cmd output.\n");
125 return "unknown";
126 } else {
127 // we had some luck using 'which' to locate the file, so we'll use this version.
128 __check_once_app_path = filebuff;
129 while (parser_bits::is_eol(__check_once_app_path[__check_once_app_path.end()])) {
130 __check_once_app_path.zap(__check_once_app_path.end(), __check_once_app_path.end());
131 }
132 }
133 delete [] filebuff;
134 return __check_once_app_path; // return whatever which told us.
135}
136
137// deprecated; better to use the /proc/pid/cmdline file.
139{
140 FUNCDEF("query_for_process_info");
141 astring to_return = "unknown";
142 // we ask the operating system about our process identifier and store
143 // the results in a temporary file.
144 chaos rando;
145 a_sprintf tmpfile("/tmp/proc_name_check_%d_%d.txt", process_id(),
146 rando.inclusive(0, 128000));
147#ifdef __APPLE__
148 a_sprintf cmd("ps -o args=\"\" %d >%s", process_id(),
149 tmpfile.s());
150#else
151 a_sprintf cmd("ps h -O \"args\" %d >%s", process_id(),
152 tmpfile.s());
153#endif
154 // run the command to locate our process info.
155 int sysret = system(cmd.s());
156 if (negative(sysret)) {
157 LOG("failed to run ps command to get process info");
158 return to_return;
159 }
160 // open the output file for reading.
161 FILE *output = fopen(tmpfile.s(), "r");
162 if (!output) {
163 LOG("failed to open the ps output file");
164 return to_return;
165 }
166 // read the file's contents into a string buffer.
167 char buff[MAXIMUM_COMMAND_LINE];
168 size_t size_read = fread(buff, 1, MAXIMUM_COMMAND_LINE, output);
169 if (size_read > 0) {
170 // success at finding some text in the file at least.
171 while (size_read > 0) {
172 const char to_check = buff[size_read - 1];
173 if ( !to_check || (to_check == '\r') || (to_check == '\n')
174 || (to_check == '\t') )
175 size_read--;
176 else break;
177 }
178 to_return.reset(astring::UNTERMINATED, buff, size_read);
179 } else {
180 // couldn't read anything.
181 LOG("could not read output of process list");
182 }
183 unlink(tmpfile.s());
184 return to_return;
185}
186#endif
187
188// used as a return value when the name cannot be determined.
189#define SET_BOGUS_NAME(error) { \
190 LOG(error); \
191 if (output) { \
192 fclose(output); \
193 unlink(tmpfile.s()); \
194 } \
195 astring home_dir = environment::get("HOME"); \
196 to_return = home_dir + "/failed_to_determine.exe"; \
197}
198
200{
201 FUNCDEF("application_name");
202 astring to_return;
203#ifdef __APPLE__
204 char buffer[MAX_ABS_PATH] = { '\0' };
205 uint32_t buffsize = MAX_ABS_PATH - 1;
206 _NSGetExecutablePath(buffer, &buffsize);
207 to_return = (char *)buffer;
208#elif defined(__UNIX__) || defined(__GNU_WINDOWS__)
209 to_return = get_cmdline_from_proc();
210/*
211#elif defined(_MSC_VER)
212 flexichar low_buff[MAX_ABS_PATH + 1];
213 GetModuleFileName(NULL_POINTER, low_buff, MAX_ABS_PATH - 1);
214 astring buff = from_unicode_temp(low_buff);
215 buff.to_lower(); // we lower-case the name since windows seems to UC it.
216 to_return = buff;
217*/
218#else
219 #pragma error("hmmm: no means of finding app name is implemented.")
220 SET_BOGUS_NAME("not_implemented_for_this_OS");
221#endif
222 return to_return;
223}
224
225#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
226//defined(_MSC_VER) ||
228#else
229 #pragma error("hmmm: need process id implementation for this OS!")
231#endif
232
234{
235 astring to_return;
236#ifdef __UNIX__
237 char buff[MAX_ABS_PATH];
238 getcwd(buff, MAX_ABS_PATH - 1);
239 to_return = buff;
240//#elif defined(_MSC_VER)
241// flexichar low_buff[MAX_ABS_PATH + 1];
242// GetCurrentDirectory(MAX_ABS_PATH, low_buff);
243// to_return = from_unicode_temp(low_buff);
244#else
245 #pragma error("hmmm: need support for current directory on this OS.")
246 to_return = ".";
247#endif
248 return to_return;
249}
250
251// implement the software product function.
253{
254#ifdef GLOBAL_PRODUCT_NAME
255 return GLOBAL_PRODUCT_NAME;
256#else
257 return "hoople";
258#endif
259}
260
263
265{
266 version to_return;
267#ifdef __UNIX__
268 utsname kernel_parms;
269 uname(&kernel_parms);
270 to_return = version(kernel_parms.release);
271//#elif defined(_MSC_VER)
272// OSVERSIONINFO info;
273// info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
274// ::GetVersionEx(&info);
275// to_return = version(a_sprintf("%u.%u.%u.%u", basis::un_short(info.dwMajorVersion),
276// basis::un_short(info.dwMinorVersion), basis::un_short(info.dwPlatformId),
277// basis::un_short(info.dwBuildNumber)));
278#else
279 #pragma error("hmmm: need version info for this OS!")
280#endif
281 return to_return;
282}
283
285
286const char *PATH_CONFIGURATION_FILENAME() { return "paths.ini"; }
287
293
295
297
298//const astring &application_configuration::WINDOZE_VIRTUAL_ROOT_NAME()
299//{ STATIC_STRING("VirtualUnixRoot"); }
300
303
305
306// static storage for virtual unix root, if it's used.
307// we don't expect it to change during runtime, right? that would be fubar.
308// so we cache it once we retrieve it.
309SAFE_STATIC(astring, static_root_holder, )
310
311const astring &application_configuration::virtual_unix_root()
312{
313 // see if we already cached the root. it shouldn't change during runtime.
314 if (static_root_holder().length()) {
315 return static_root_holder();
316 }
317#ifdef __UNIX__
318 // simple implementation for unix/linux; just tell the truth about the real root.
319 static_root_holder() = astring("/");
320 return static_root_holder();
321#endif
322#ifdef __WIN32__
323 /*
324 use the path in our system helpers header, which should have been set during the
325 build process if this is really windows.
326 */
327 astring virtual_root = FEISTY_MEOW_VIRTUAL_UNIX_ROOT;
328 if (!virtual_root) {
329 // if it has no length, we didn't get our setting! we'll limp along with a guess.
330 return DEFAULT_VIRTUAL_UNIX_ROOT();
331 } else {
332 static_root_holder() = virtual_root;
333 return static_root_holder();
334 }
335
336#endif
337}
338
340
342 // the maximum length of the entry stored for the log path.
343
345{
346 // new scheme is to just use the temporary directory, which can vary per user
347 // and which hopefully is always set to something usable.
348 astring def_log = environment::TMP();
349 // add logs directory underneath that.
350 def_log += "/logs";
351 // add the subdirectory for logs.
352
353 // now grab the current value for the name, if any.
355 // get the entry for the logging path.
356 if (!log_dir) {
357 // if the entry was absent, we set it.
358//printf("did not find log dir in config file\n");
363 } else {
364 // they gave us something. let's replace the environment variables
365 // in their string so we resolve paths and such.
366 log_dir = parser_bits::substitute_env_vars(log_dir);
367//printf("%s", (char *)a_sprintf("got log dir with %s value\n", log_dir.s()).s());
368 }
369
370 // now we make sure the directory exists.
371 filename testing(log_dir);
372 if (!testing.exists()) {
373 bool okay = directory::recursive_create(log_dir);
374 if (!okay) {
375 LOG(astring("failed to create logging directory: ") + log_dir);
376 // return a directory almost guaranteed to exist; best we can do in this case.
377#ifdef __UNIX__
378 return "/tmp";
379#endif
380#ifdef __WIN32__
381 return "c:/";
382#endif
383 }
384 }
385
386 return log_dir;
387}
388
391
393{
397 astring to_return = ini.load(GLOBAL_SECTION_NAME(), key_name, "");
398 if (!!to_return) {
399 // if the string has any length, then we process any environment
400 // variables found encoded in the value.
401 to_return = parser_bits::substitute_env_vars(to_return);
402 }
403 return to_return;
404}
405
406} // namespace.
407
#define unlink
Definition Xos2defs.h:45
#define getcwd
Definition Xos2defs.h:29
#define getpid
Definition Xos2defs.h:30
#define SET_BOGUS_NAME(error)
#define LOG(s)
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition astring.cpp:524
void reset()
clears out the contents string.
Definition astring.h:202
int end() const
returns the index of the last (non-null) character in the string.
Definition astring.h:86
int length() const
Returns the current length of the string.
Definition astring.cpp:132
static astring TMP()
provides a single place to get the temporary directory.
Defines installation-specific locations in the file system.
static const basis::astring & LOGGING_FOLDER_NAME()
the tag used for finding our logging path in the paths config file.
static basis::astring get_logging_directory()
< retrieves the core binary directory location from paths.ini.
static basis::astring make_logfile_name(const basis::astring &base_name)
generates an installation appropriate log file name from "base_name".
static basis::astring query_for_process_info()
seeks out process info for a particular process.
static basis::astring application_name()
returns the full name of the current application.
static basis::un_int process_id()
returns the process id for this task, if that's relevant on the OS.
static const basis::astring & GLOBAL_SECTION_NAME()
the root section name for our configuration items in the main ini file.
static basis::astring current_directory()
returns the current directory as reported by the operating system.
static const basis::astring & DEFAULT_VIRTUAL_UNIX_ROOT()
default value if we don't find our setting for virtual root.
static basis::astring application_configuration_file()
the fully specified path to the main path configuration file.
static basis::astring application_directory()
returns the directory name where this application is running from.
static basis::astring get_cmdline_from_proc()
retrieves the command line from the /proc hierarchy on linux.
static const char * software_product_name()
This global function is available to the system at large for branding info.
static structures::version get_OS_version()
returns the operating system's version information.
static basis::astring read_item(const basis::astring &key_name)
returns the entry listed under the "key_name".
bool store(const basis::astring &section, const basis::astring &entry, const basis::astring &to_store)
a synonym for put.
basis::astring load(const basis::astring &section, const basis::astring &entry, const basis::astring &default_value)
a synonym for get that implements the auto-store behavior.
Supports a configurator-based interface on text initialization files.
@ APPLICATION_DIRECTORY
config files live with application.
static bool recursive_create(const basis::astring &directory_name)
returns true if the "directory_name" can be created or already exists.
Provides operations commonly needed on file names.
Definition filename.h:64
bool exists() const
returns true if the file exists.
Definition filename.cpp:426
bool had_directory() const
returns true if the name that we were given had a non-empty directory.
Definition filename.h:139
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition filename.cpp:97
filename dirname() const
returns the directory for the filename.
Definition filename.cpp:393
a platform-independent way to acquire random numbers in a specific range.
Definition chaos.h:51
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
Definition chaos.h:88
Holds a file's version identifier.
static basis::astring substitute_env_vars(const basis::astring &text, bool leave_unknown=true)
resolves embedded environment variables in "text".
static bool is_eol(char to_check)
returns true if "to_check" is part of an end-of-line sequence.
char * base_name(char *file)
Definition makedep.cpp:653
char * getline(filepointer *filep)
Definition makedep.cpp:576
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
#define MAX_ABS_PATH
Definition filename.h:37
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
unsigned int un_int
Abbreviated name for unsigned integers.
Definition definitions.h:62
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition functions.h:43
const int KILOBYTE
Number of bytes in a kilobyte.
const char * PATH_CONFIGURATION_FILENAME()
A platform independent way to obtain the timestamp of a file.
An extension to floating point primitives providing approximate equality.
Definition averager.h:21
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#define STATIC_STRING(str)
Statically defines a string for the rest of the program's life.
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
chaos rando
Support for unicode builds.
Aids in achievement of platform independence.