1 /*****************************************************************************\
3 * Name : configured_applications
4 * Author : Chris Koeritz
6 *******************************************************************************
7 * Copyright (c) 2000 By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "configured_applications.h"
17 #include <basis/astring.h>
18 #include <basis/mutex.h>
19 #include <configuration/ini_configurator.h>
20 #include <configuration/section_manager.h>
21 #include <configuration/variable_tokenizer.h>
22 #include <loggers/program_wide_logger.h>
23 #include <structures/set.h>
24 #include <structures/string_table.h>
25 #include <textual/parser_bits.h>
27 using namespace basis;
28 using namespace configuration;
29 using namespace loggers;
30 using namespace structures;
31 using namespace textual;
35 //#define DEBUG_APP_CONFIG
36 // uncomment for noisier debugging version.
39 #define LOG(to_print) program_wide_logger::get().log(to_print, ALWAYS_PRINT)
43 const char *PRODUCT_HEADING() { return "product"; }
44 // the string used for our startup entries as a prefix to the product.
46 const char *ASSIGN_TOKEN() { return "="; }
47 // how we distinguish the key from the value for startup entries.
49 const char *SEPARATOR_TOKEN() { return ","; }
50 // the character between separate key/value pairs in the startup string.
52 const char *SEPARATOR_TEXT() { return ", "; }
53 // the string we use for the separator when printing it.
55 const char *PARMS_HEADING() { return "parms"; }
56 // the tag for parameters in the startup entry.
58 const char *ONESHOT_HEADING() { return "oneshot"; }
59 // the key name for startup entries' flag for once only execution.
63 configured_applications::configured_applications(const astring &config_file,
64 const astring &basename)
66 _config(new ini_configurator(config_file, ini_configurator::RETURN_ONLY,
67 ini_configurator::APPLICATION_DIRECTORY)),
68 _sector(new section_manager(*_config, astring(basename) + "_TOC",
69 astring(PRODUCT_HEADING()) + "_"))
71 FUNCDEF("constructor");
72 string_table startup_info;
73 if (!find_section(STARTUP_SECTION(), startup_info)) {
74 // if there's no startup section, we do nothing right now.
75 LOG(astring("the startup section doesn't exist yet; adding it now."));
76 astring entry = make_startup_entry(basename, "", false);
77 startup_info.add(STARTUP_APP_NAME(), entry);
78 add_section(STARTUP_SECTION(), startup_info);
82 configured_applications::~configured_applications()
89 const char *configured_applications::STARTUP_SECTION()
90 { return "PRIVATE_STARTUP_LNCH1.0"; }
92 const char *configured_applications::STARTUP_APP_NAME()
93 { return "placeholder"; }
95 bool configured_applications::product_exists(const astring &product)
97 auto_synchronizer l(*_lock);
98 if (!_sector->section_exists(product)) return false;
102 astring configured_applications::find_program(const astring &product,
103 const astring &app_name, int &level)
105 auto_synchronizer l(*_lock);
106 astring heading = _sector->make_section_heading(product);
107 astring found = _sector->config().load(heading, app_name, "");
109 //overly specific bits here...
110 //hmmm: add this in as a specialization provided by real owner of class.
112 // we didn't find the entry under the section we wanted to find it in.
113 // there are a couple cases where we can kludge this section to a
114 // different name, based on legacy requirements, and still find the
115 // right item possibly.
116 if (product.iequals("supervisor")) {
117 // for some older installs, they say "supervisor" but mean "core".
118 heading = _sector->make_section_heading("core");
119 found = _sector->config().load(heading, app_name, "");
120 } else if (product.iequals("lightlink")) {
121 heading = _sector->make_section_heading("core");
122 found = _sector->config().load(heading, app_name, "");
124 // we can take one more remedial step for this phrase.
125 heading = _sector->make_section_heading("server");
126 found = _sector->config().load(heading, app_name, "");
130 //end of overly specific.
132 found = parser_bits::substitute_env_vars(found);
134 int comma_loc = found.find(",");
135 if (negative(comma_loc)) return ""; // couldn't find our priority.
136 level = found.convert(0);
137 found.zap(0, comma_loc);
142 bool configured_applications::add_program(const astring &product,
143 const astring &app_name, const astring &full_path, int level)
145 #ifdef DEBUG_APP_CONFIG
146 FUNCDEF("add_program");
148 auto_synchronizer l(*_lock);
150 // lookup the section, if it exists.
151 string_table info_table;
152 if (!_sector->section_exists(product)) {
155 find_section(product, info_table);
156 #ifdef DEBUG_APP_CONFIG
158 LOG(astring("section for ") + product + " found:");
159 for (int i = 0; i < info_table.symbols(); i++)
160 LOG(astring("key=") + info_table.name(i) + " value=" + info_table[i]);
161 } else LOG(astring("section for ") + product + " not found.");
163 // remove any existing entry.
164 info_table.whack(app_name);
165 // plug in our new entry.
166 a_sprintf full_entry("%d,%s", level, full_path.s());
167 info_table.add(app_name, full_entry);
168 #ifdef DEBUG_APP_CONFIG
169 LOG(astring("new section for ") + product + " has:");
170 for (int i = 0; i < info_table.symbols(); i++)
171 LOG(astring("key=") + info_table.name(i) + " value=" + info_table[i]);
173 // now call the proper storage function based on whether the section
174 // existed before or not.
175 if (existed) return replace_section(product, info_table);
176 else return add_section(product, info_table);
179 bool configured_applications::remove_program(const astring &product,
180 const astring &app_name)
182 FUNCDEF("remove_program");
183 auto_synchronizer l(*_lock);
184 // if the section's missing, there's nothing to remove...
185 string_table info_table;
186 if (!find_section(product, info_table)) return true;
187 // the section did exist, so remove any existing entry.
188 info_table.whack(app_name);
189 // now call the proper storage function based on whether the section
190 // existed before or not.
191 return replace_section(product, info_table);
194 bool configured_applications::find_section(const astring §ion_name,
195 string_table &info_found)
197 FUNCDEF("find_section");
199 auto_synchronizer l(*_lock);
200 if (!_sector->find_section(section_name, info_found)) {
201 LOG(section_name + " was not found in the configuration.");
207 bool configured_applications::add_section(const astring §ion_name,
208 const string_table &info_found)
210 auto_synchronizer l(*_lock);
211 return _sector->add_section(section_name, info_found);
214 bool configured_applications::replace_section(const astring §ion_name,
215 const string_table &info_found)
217 auto_synchronizer l(*_lock);
218 return _sector->replace_section(section_name, info_found);
221 astring configured_applications::make_startup_entry(const astring &product,
222 const astring &parms, bool one_shot)
224 return astring(PRODUCT_HEADING()) + ASSIGN_TOKEN() + product
225 + SEPARATOR_TEXT() + PARMS_HEADING() + ASSIGN_TOKEN()
226 + parms + SEPARATOR_TEXT() + ONESHOT_HEADING() + ASSIGN_TOKEN()
227 + astring(astring::SPRINTF, "%d", one_shot);
230 bool configured_applications::parse_startup_entry(const astring &info,
231 astring &product, astring &parms, bool &one_shot)
233 FUNCDEF("parse_startup_section");
234 // parse the items that are in the entry for this program.
235 variable_tokenizer entry_parser(SEPARATOR_TOKEN(), ASSIGN_TOKEN());
236 entry_parser.parse(info);
237 // grab the pertinent bits for the program to be started.
238 product = entry_parser.find(PRODUCT_HEADING());
239 parms = entry_parser.find(PARMS_HEADING());
240 //LOG(astring("parms=") + parms);
241 astring once = entry_parser.find(ONESHOT_HEADING());
242 one_shot = (bool)once.convert(0);
243 // we require the product part at least.
244 if (!product) return false;
248 bool configured_applications::find_entry(const string_table &table,
249 const astring &name, astring &location)
251 // seek the entry in the table specified.
252 astring *found = table.find(name);
253 if (!found) return false;
254 // found the entry using the name.
259 bool configured_applications::add_startup_entry(const astring &product,
260 const astring &app_name, const astring ¶meters, int one_shot)
262 FUNCDEF("add_startup_entry");
263 auto_synchronizer l(*_lock);
265 LOG(astring("product \"") + product + "\", application \"" + app_name
266 + (one_shot? astring("\", OneShot") : astring("\", MultiUse")));
268 string_table startup_info;
269 if (!find_section(STARTUP_SECTION(), startup_info)) {
270 // if there's no startup section, we can't go on. that should have been
271 // created during startup of this program.
272 LOG(astring("internal startup section not found!"));
276 astring new_entry = make_startup_entry(product, parameters,
278 startup_info.add(app_name, new_entry);
279 if (!replace_section(STARTUP_SECTION(), startup_info))
281 //hmmm: that's a bogus error; this is really an internal fup error.
286 bool configured_applications::remove_startup_entry(const astring &product,
287 const astring &app_name)
289 FUNCDEF("remove_startup_entry");
290 auto_synchronizer l(*_lock);
292 LOG(astring("product \"") + product + "\", application \"" + app_name + "\"");
294 string_table startup_info;
295 if (!find_section(STARTUP_SECTION(), startup_info)) {
296 // if there's no startup section, we try to add one.
297 add_section(STARTUP_SECTION(), startup_info);
298 // if it still doesn't exist afterwards, we're hosed.
299 if (!find_section(STARTUP_SECTION(), startup_info)) {
300 /// COMPLAIN_PRODUCT;
301 //massive fup of some unanticipated sort.
307 // check that the entry already exists for this program.
309 if (!find_entry(startup_info, app_name, entry_found)) {
310 // COMPLAIN_APPLICATION;
311 LOG(astring("no entry was found for ") + app_name);
315 startup_info.whack(app_name);
316 if (!replace_section(STARTUP_SECTION(), startup_info)) {
317 //what happened with that?