~ubuntu-branches/debian/sid/menu/sid

« back to all changes in this revision

Viewing changes to update-menus/update-menus.cc

  • Committer: Bazaar Package Importer
  • Author(s): Bill Allombert
  • Date: 2005-05-24 10:34:47 UTC
  • mfrom: (1.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050524103447-9zu50so5d0nte3o9
Tags: 2.1.24
* The "head or tail" release 
* Fix .menus typo in menufile.5. Closes: #306564. Thanks Sean Finney.
* Add Vietnamese menu messages and menu sections translations.
  Thanks Clytie Siddall. Closes: #307450, #308953.
* Update Esperanto menu sections translation. Thanks MJ Ray.
* Add Esperanto menu messages translation. Thanks MJ Ray.
* Unfuzzy Norwegian Bokmål menu messages translation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright:  GPL */
2
1
/*
3
 
  Witten by joost witteveen;  
4
 
  read_pkginfo function by Tom Lees, run_menumethods by both.
5
 
  
6
 
  */
 
2
 * Debian menu system -- update-menus
 
3
 * update-menus/update-menus.cc
 
4
 *
 
5
 * Copyright (C) 1996-2003  Joost Witteveen, 
 
6
 * Copyright (C) 2002-2004  Bill Allombert and Morten Brix Pedersen.
 
7
 * 
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License with
 
19
 * the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL;
 
20
 * if not, write to the Free Software Foundation, Inc., 59 Temple Place,
 
21
 * Suite 330, Boston, MA  02111-1307  USA
 
22
 *
 
23
 *
 
24
 * Written by Joost Witteveen;
 
25
 * read_pkginfo function by Tom Lees, run_menumethods by both.
 
26
 */
7
27
 
8
 
#include "update-menus.h"
9
 
#include <fstream.h>
 
28
#include <fstream>
 
29
#include <sstream>
10
30
#include <set>
11
 
#include <stdio.h>
12
 
#include <string.h>
 
31
#include <cstdio>
13
32
#include <unistd.h>
14
 
#include <fcntl.h>
 
33
#include <getopt.h>
 
34
#include <cerrno>
 
35
#include <cctype>
15
36
#include <sys/stat.h>
16
37
#include <sys/types.h>
17
38
#include <sys/wait.h>
18
39
#include <sys/file.h>
19
 
#include <ctype.h>
20
40
#include <dirent.h>
21
41
#include <signal.h>
22
42
#include <syslog.h>
23
 
#include <errno.h>
24
 
#include <procbuf.h>
25
 
 
26
 
int debug=0, verbose=0;
27
 
set <String, less<String> > installed_packages;
28
 
set <String, less<String> > menufiles_processed;
29
 
 
30
 
extern char **environ;
31
 
 
 
43
#include <pwd.h>
 
44
#include "config.h"
 
45
#include "update-menus.h"
 
46
#include "stringtoolbox.h"
 
47
 
 
48
using std::set;
 
49
using std::vector;
 
50
using std::string;
 
51
using std::cout;
 
52
using std::cerr;
 
53
using std::ostream;
 
54
using namespace exceptions;
 
55
 
 
56
static const char * home_dir;
 
57
 
 
58
set<string> installed_packages;
 
59
set<string> menufiles_processed;
 
60
int total_menuentries;
32
61
 
33
62
translateinfo *transinfo;
34
63
configinfo     config;
 
64
bool is_root;
35
65
 
36
 
DIR *open_dir_check(String dirname){
 
66
/** Try to open a directory. Throws dir_error_read if failed, and a DIR*
 
67
 * descriptor if succeeded.
 
68
 */
 
69
DIR *open_dir_check(const string& dirname)
 
70
{
37
71
  struct stat st;
38
 
  int r;
39
 
 
40
 
  r=stat (dirname.c_str(), &st);
41
 
  if (r || (!S_ISDIR (st.st_mode)))
42
 
    throw dir_error_read(dirname);
43
 
 
44
 
  return opendir (dirname.c_str());
 
72
 
 
73
  if (stat(dirname.c_str(), &st) || (!S_ISDIR (st.st_mode)))
 
74
      throw dir_error_read();
 
75
 
 
76
  return opendir(dirname.c_str());
45
77
}
46
78
 
47
 
bool executable(const String &s){
 
79
/** Checks whether a file is executable */
 
80
bool executable(const string &s)
 
81
{
48
82
  struct stat st;
49
 
  int r;
50
 
  r=stat (s.c_str(), &st);
51
 
  if(r!=0)
 
83
  if (stat(s.c_str(), &st)) {
52
84
    return false;
53
 
  else
54
 
    return (((st.st_mode & S_IXOTH) || 
55
 
             ((st.st_mode & S_IXGRP) && st.st_gid == getegid ()) || 
56
 
             ((st.st_mode & S_IXUSR) && st.st_uid == geteuid ())) && 
57
 
            (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
58
 
}
59
 
 
60
 
/////////////////////////////////////////////////////
61
 
//  menuentry:
62
 
//
63
 
 
64
 
/*void gettext_translate(menuentry &m){
65
 
  StrVec v;
66
 
  StrVec::iterator i;
67
 
  String t;
68
 
 
69
 
  
70
 
  t=String(dgettext(GETTEXTDOMAIN,m.data[TITLE_VAR].c_str()));
71
 
  m.data[TITLE_VAR]=t;
72
 
 
73
 
  t=m.data[SECTION_VAR];
74
 
  break_slashes(t,v);
75
 
  t=String("");
76
 
  for(i=v.begin(); i!=v.end(); i++){
77
 
    if(i!=v.begin())
78
 
      t=t+String("/");
79
 
    t=t+String(dgettext(GETTEXTDOMAIN,(*i).c_str()));
 
85
  } else {
 
86
    return (((st.st_mode & S_IXOTH) ||
 
87
          ((st.st_mode & S_IXGRP) && st.st_gid == getegid ()) ||
 
88
          ((st.st_mode & S_IXUSR) && st.st_uid == geteuid ())) &&
 
89
        (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
80
90
  }
81
 
  m.data[SECTION_VAR]=t;
82
91
}
83
 
*/
84
 
bool menuentry::test_installed(String filename){
85
 
  
86
 
  if(filename.contains("local.",0))
 
92
 
 
93
/** Checks whether a package is installed */
 
94
bool is_pkg_installed(const string& filename)
 
95
{
 
96
  if (contains(filename, "local."))
87
97
    return true;
88
98
  else
89
 
    return installed_packages.find(filename)!=installed_packages.end();
90
 
}
91
 
 
92
 
bool menuentry::check_install(parsestream &i, String &name){
93
 
  String function;
94
 
 
95
 
  function=i.get_name();
96
 
  if(function!=String(COND_PACKAGE))
 
99
    return installed_packages.find(filename) != installed_packages.end();
 
100
}
 
101
 
 
102
menuentry::menuentry(parsestream &i, const std::string& file, const std::string& shortfile)
 
103
{
 
104
  char c = i.get_char();
 
105
  if (c == '?') {
 
106
    read_menuentry(i);
 
107
  } else {
 
108
    // old format menuentry
 
109
    if (!is_pkg_installed(shortfile)) {
 
110
      i.skip_line();
 
111
      throw cond_inst_false();
 
112
    }
 
113
    data[PACKAGE_VAR] = shortfile;
 
114
    i.put_back(c);
 
115
    data[NEEDS_VAR]   = i.get_stringconst();
 
116
    data[SECTION_VAR] = i.get_stringconst();
 
117
    i.get_stringconst(); //id is unused
 
118
    data[ICON_VAR]    = i.get_stringconst();
 
119
    data[TITLE_VAR]   = i.get_stringconst();
 
120
    i.skip_space();
 
121
    data[COMMAND_VAR] = i.get_line();
 
122
  }
 
123
  check_req_tags(file);
 
124
}
 
125
 
 
126
/** This function checks the package name to see if it's valid and installed.
 
127
 * Multiple package names can exist, seperated by comma. */
 
128
void menuentry::check_pkg_validity(parsestream &i, std::string &name)
 
129
{
 
130
  string function = i.get_name();
 
131
  if (function != COND_PACKAGE)
97
132
    throw unknown_cond_package(&i, function);
98
 
  i.skip_char('(');
99
 
  name=i.get_name();
100
 
  if(!test_installed(name)){
101
 
    i.skip_line();
102
 
    throw cond_inst_false();
 
133
 
 
134
  // Read an entry, such as (foo) or (foo, bar)
 
135
  char c;
 
136
  while ((c = i.get_char()))
 
137
  {
 
138
      if (c == ',' || c == '(') {
 
139
          // A package name follows.
 
140
          string pkgname = i.get_name();
 
141
 
 
142
          if (!name.empty())
 
143
                name += ", ";
 
144
 
 
145
          name += pkgname;
 
146
          if (!is_pkg_installed(pkgname)) {
 
147
              i.skip_line();
 
148
              throw cond_inst_false();
 
149
          }
 
150
      } else if (c == ')') {
 
151
          // We are finished with the package requirements.
 
152
          return;
 
153
      }
103
154
  }
104
155
  i.skip_char(')');
105
 
  return true;
106
 
}
107
 
 
108
 
void menuentry::menuentry_constr_gccbug(parsestream &i)
109
 
110
 
  char c;
111
 
  String name, val;
112
 
  //new format menuentry
113
 
  
114
 
  //read available info
115
 
  check_install(i, name);
116
 
  data[PACKAGE_VAR]=name;
 
156
}
 
157
 
 
158
/** Checks whether we have all the tags we need. */
 
159
void menuentry::check_req_tags(const std::string& filename)
 
160
{
 
161
  vector<string> need;
 
162
 
 
163
  need.push_back(SECTION_VAR);
 
164
  need.push_back(TITLE_VAR);
 
165
  need.push_back(NEEDS_VAR);
 
166
 
 
167
  for(vector<string>::iterator i = need.begin(); i != need.end(); ++i)
 
168
  {
 
169
    std::map<string, string>::const_iterator j = data.find(*i);
 
170
    if ((j == data.end()) || j->second.empty())
 
171
        throw missing_tag(filename, *i);
 
172
  }
 
173
 
 
174
}
 
175
 
 
176
/** Parse a menuentry from a parsestream */
 
177
void menuentry::read_menuentry(parsestream &i)
 
178
{
 
179
  // a new format menuentry
 
180
  string name;
 
181
 
 
182
  // read available info
 
183
  check_pkg_validity(i, name);
 
184
  data[PACKAGE_VAR] = name;
117
185
  i.skip_space();
118
186
  i.skip_char(':');
119
 
  //read menuentry:
120
 
  try{
121
 
    do{
122
 
      name=i.get_name();
123
 
      val=i.get_eq_Stringconst();
124
 
      data[name]=val;
125
 
      c=i.get_char();
 
187
  i.doescaping = false;
 
188
 
 
189
  // read menuentry:
 
190
  try {
 
191
    char c;
 
192
    do {
 
193
      string key = i.get_name();
 
194
      string value = i.get_eq_stringconst();
 
195
      data[key] = value;
 
196
      c = i.get_char();
126
197
      i.put_back(c);
127
 
    }while(c);
 
198
    } while(c);
128
199
  }
129
 
  catch(endofline){};
 
200
  catch (endofline) { }
130
201
  i.skip_line();
131
202
}
132
203
 
133
 
menuentry::menuentry(parsestream &i, const String &filename){
134
 
  char c;
135
 
 
136
 
  c=i.get_char();
137
 
  if(c=='?'){
138
 
    menuentry_constr_gccbug(i);
139
 
  }else{
140
 
    //old format menuentry
141
 
    if(!test_installed(filename)){
142
 
      i.skip_line();
143
 
      throw cond_inst_false();
144
 
    }
145
 
    data[PACKAGE_VAR]=filename;
146
 
    i.put_back(c);
147
 
    data[NEEDS_VAR]  =i.get_Stringconst();
148
 
    data[SECTION_VAR]=i.get_Stringconst();
149
 
    i.get_Stringconst(); //id is unused
150
 
    data[ICON_VAR]   =i.get_Stringconst();
151
 
    data[TITLE_VAR]  =i.get_Stringconst();
152
 
    i.skip_space();
153
 
    data[COMMAND_VAR]=i.get_line();
154
 
  }
155
 
}
156
 
 
157
 
void menuentry::output(vector<String> &s){
158
 
  String t;
159
 
  map<String, String, less<String> >::iterator i;
160
 
  if((i=data.begin())!=data.end())
161
 
    while (true){
162
 
      t+=String((*i).first) + "=\"" + 
163
 
         escape_String((*i).second,"\"\n") + "\"";
 
204
void menuentry::output(std::vector<std::string> &s)
 
205
{
 
206
  string t;
 
207
  std::map<string, string>::const_iterator i = data.begin();
 
208
  if (i != data.end()) {
 
209
    while (true)
 
210
    {
 
211
      t += i->first + "=\"" + i->second + '"';
164
212
      i++;
165
 
      if(i==data.end()){
166
 
        break;
167
 
      } else
168
 
        t+=" ";
 
213
      if (i == data.end())
 
214
          break;
 
215
      else
 
216
          t += ' ';
169
217
    }
170
 
  t+="\n";
171
 
  config.report(String("ADDING: ")+t,configinfo::report_debug);
 
218
  }
 
219
  t += '\n';
172
220
  s.push_back(t);
173
221
}
174
222
 
175
 
ostream &menuentry::debugoutput(ostream &o){
176
 
  map<String, String, less<String> >::iterator i;
177
 
 
178
 
  o<<"MENUENTRY:"<<endl;
179
 
  for(i=data.begin(); i!=data.end(); i++)
180
 
    o<<"  data["<<(*i).first<<"]="<<(*i).second<<endl;
181
 
  return o;
182
 
}
183
 
 
184
223
/////////////////////////////////////////////////////
185
224
//  configinfo
186
225
//
187
 
configinfo::configinfo(){
188
 
  verbosity=report_quiet;
189
 
  method=method_stderr;
190
 
  compat=parsestream::eol_newline;
191
 
  usedefaultmenufilesdirs=true;
192
 
}
193
 
 
194
 
void configinfo::parse_def(const String &var, parsestream &p){
195
 
  String s;
196
 
  s=p.get_Stringconst();
197
 
  if(var==String("compat")){
198
 
    if(s==String("menu-1")) compat=parsestream::eol_newline;
199
 
    else if(s==String("menu-2")) compat=parsestream::eol_semicolon;
200
 
    else throw def_error(&p, s);
201
 
  } else if(var==String("verbosity")){
202
 
    if     (s==String("quiet"))   verbosity=report_quiet;
203
 
    else if(s==String("normal"))  verbosity=report_normal;
204
 
    else if(s==String("verbose")) verbosity=report_verbose;
205
 
    else if(s==String("debug"))   verbosity=report_debug;
206
 
    else throw def_error(&p, s);
207
 
  } else if(var==String("method")){
208
 
    if     (s==String("stdout"))  method=method_stdout;
209
 
    else if(s==String("stderr"))  method=method_stderr;
210
 
    else if(s==String("syslog")) { 
211
 
      method=method_syslog;
212
 
      String facility;
213
 
      String priority;
214
 
      facility=p.get_Stringconst();
215
 
      cerr<<"FACILITY="<<facility<<endl;
216
 
 
217
 
      priority=p.get_Stringconst();
218
 
      cerr<<"priority="<<priority<<endl;
219
 
           if(facility==String("auth"))       syslog_facility=LOG_AUTH;
220
 
      else if(facility==String("authpriv"))   syslog_facility=LOG_AUTHPRIV;
221
 
      else if(facility==String("authcron"))   syslog_facility=LOG_CRON;
222
 
      else if(facility==String("authdaemon")) syslog_facility=LOG_AUTHPRIV;
223
 
      else if(facility==String("authkern"))   syslog_facility=LOG_KERN;
224
 
      else if(facility==String("authlocal0")) syslog_facility=LOG_LOCAL0;
225
 
      else if(facility==String("authlocal1")) syslog_facility=LOG_LOCAL1;
226
 
      else if(facility==String("authlocal2")) syslog_facility=LOG_LOCAL2;
227
 
      else if(facility==String("authlocal3")) syslog_facility=LOG_LOCAL3;
228
 
      else if(facility==String("authlocal4")) syslog_facility=LOG_LOCAL4;
229
 
      else if(facility==String("authlocal5")) syslog_facility=LOG_LOCAL5;
230
 
      else if(facility==String("authlocal6")) syslog_facility=LOG_LOCAL6;
231
 
      else if(facility==String("authlocal7")) syslog_facility=LOG_LOCAL7;
232
 
      else if(facility==String("authlpr"))    syslog_facility=LOG_LPR;
233
 
      else if(facility==String("authmail"))   syslog_facility=LOG_MAIL;
234
 
      else if(facility==String("authnews"))   syslog_facility=LOG_NEWS;
235
 
      else if(facility==String("authsyslog")) syslog_facility=LOG_SYSLOG;
236
 
      else if(facility==String("authuser"))   syslog_facility=LOG_USER;
237
 
      else if(facility==String("authuucp"))   syslog_facility=LOG_UUCP;
238
 
      else throw def_error(&p, facility);
239
 
 
240
 
           if(priority==String("emerg"))      syslog_priority=LOG_EMERG;
241
 
      else if(priority==String("alert"))      syslog_priority=LOG_ALERT;
242
 
      else if(priority==String("crit"))       syslog_priority=LOG_CRIT;
243
 
      else if(priority==String("err"))        syslog_priority=LOG_ERR;
244
 
      else if(priority==String("warning"))    syslog_priority=LOG_WARNING;
245
 
      else if(priority==String("notice"))     syslog_priority=LOG_NOTICE;
246
 
      else if(priority==String("info"))       syslog_priority=LOG_INFO;
247
 
      else if(priority==String("debug"))      syslog_priority=LOG_DEBUG;
248
 
      else throw def_error(&p, priority);
249
 
    }
250
 
    else throw def_error(&p,s);
251
 
  }
252
 
  else throw def_error(&p, var);
253
 
}
254
 
 
255
 
void configinfo::update(String filename){
256
 
  try{
257
 
    parsestream p(filename);
258
 
    while(true){
259
 
      String var;
260
 
      var=p.get_name();
261
 
      p.skip_char('=');
262
 
      parse_def(var,p);
263
 
      p.skip_line();
264
 
    }
265
 
  } 
266
 
  catch (endoffile){};
267
 
}
268
 
 
269
 
void configinfo::report(const String &message,
270
 
                        verbosity_type v){
271
 
  if(v<=verbosity){
272
 
    switch(method){
 
226
 
 
227
/** Handle key/value configuration pair */
 
228
void configinfo::parse_config(const std::string &key, const std::string& value)
 
229
{
 
230
  if (key=="compat") {
 
231
    if (value=="menu-1") compat = parsestream::eol_newline;
 
232
    else if(value=="menu-2") compat = parsestream::eol_semicolon;
 
233
  } else if(key=="verbosity") {
 
234
    if     (value=="quiet")   verbosity=report_quiet;
 
235
    else if(value=="normal")  verbosity=report_normal;
 
236
    else if(value=="verbose") verbosity=report_verbose;
 
237
    else if(value=="debug") verbosity=report_debug;
 
238
  } else if(key=="method") {
 
239
    if     (value=="stdout")  method=method_stdout;
 
240
    else if(value=="stderr")  method=method_stderr;
 
241
    else if(value=="syslog") {
 
242
 
 
243
      method = method_syslog;
 
244
      string facility;
 
245
      string priority;
 
246
 
 
247
      std::istringstream ss(value);
 
248
      ss >> facility;
 
249
      ss >> priority;
 
250
 
 
251
           if(facility=="auth")       syslog_facility=LOG_AUTH;
 
252
      else if(facility=="authpriv")   syslog_facility=LOG_AUTHPRIV;
 
253
      else if(facility=="authcron")   syslog_facility=LOG_CRON;
 
254
      else if(facility=="authdaemon") syslog_facility=LOG_AUTHPRIV;
 
255
      else if(facility=="authkern")   syslog_facility=LOG_KERN;
 
256
      else if(facility=="authlocal0") syslog_facility=LOG_LOCAL0;
 
257
      else if(facility=="authlocal1") syslog_facility=LOG_LOCAL1;
 
258
      else if(facility=="authlocal2") syslog_facility=LOG_LOCAL2;
 
259
      else if(facility=="authlocal3") syslog_facility=LOG_LOCAL3;
 
260
      else if(facility=="authlocal4") syslog_facility=LOG_LOCAL4;
 
261
      else if(facility=="authlocal5") syslog_facility=LOG_LOCAL5;
 
262
      else if(facility=="authlocal6") syslog_facility=LOG_LOCAL6;
 
263
      else if(facility=="authlocal7") syslog_facility=LOG_LOCAL7;
 
264
      else if(facility=="authlpr")    syslog_facility=LOG_LPR;
 
265
      else if(facility=="authmail")   syslog_facility=LOG_MAIL;
 
266
      else if(facility=="authnews")   syslog_facility=LOG_NEWS;
 
267
      else if(facility=="authsyslog") syslog_facility=LOG_SYSLOG;
 
268
      else if(facility=="authuser")   syslog_facility=LOG_USER;
 
269
      else if(facility=="authuucp")   syslog_facility=LOG_UUCP;
 
270
 
 
271
           if(priority=="emerg")      syslog_priority=LOG_EMERG;
 
272
      else if(priority=="alert")      syslog_priority=LOG_ALERT;
 
273
      else if(priority=="crit")       syslog_priority=LOG_CRIT;
 
274
      else if(priority=="err")        syslog_priority=LOG_ERR;
 
275
      else if(priority=="warning")    syslog_priority=LOG_WARNING;
 
276
      else if(priority=="notice")     syslog_priority=LOG_NOTICE;
 
277
      else if(priority=="info")       syslog_priority=LOG_INFO;
 
278
      else if(priority=="debug")      syslog_priority=LOG_DEBUG;
 
279
    }
 
280
  }
 
281
}
 
282
 
 
283
void configinfo::read_file(const std::string& filename)
 
284
{
 
285
  std::ifstream config_file(filename.c_str());
 
286
 
 
287
  if (!config_file)
 
288
      return;
 
289
 
 
290
  string str;
 
291
  while (getline(config_file, str))
 
292
  {
 
293
    // read a key and a value, seperated by '='.
 
294
    string::size_type pos = str.find("=");
 
295
    if (pos == string::npos)
 
296
        return;
 
297
 
 
298
    // parse key and value
 
299
    parse_config(str.substr(0, pos), str.substr(pos + 1));
 
300
  }
 
301
 
 
302
}
 
303
 
 
304
void configinfo::report(const std::string &message, verbosity_type v)
 
305
{
 
306
  if(v <= verbosity) {
 
307
    switch(method) {
273
308
    case method_stdout:
274
 
      cout<<"Update-menus["<<getpid()<<"]: "<<message<<endl;
 
309
      cout << String::compose("update-menus[%1]: %2\n",getpid(),message);
275
310
      break;
276
311
    case method_stderr:
277
 
      cerr<<"Update-menus["<<getpid()<<"]: "<<message<<endl;
 
312
      cerr << String::compose("update-menus[%1]: %2\n",getpid(),message);
278
313
      break;
279
314
    case method_syslog:
280
315
      openlog("update-menus",LOG_PID,syslog_facility);
283
318
    }
284
319
  }
285
320
}
 
321
 
286
322
/////////////////////////////////////////////////////
287
323
//  translate stuff
288
324
//
289
325
 
290
 
trans_class::trans_class(const String &m,
291
 
                         const String &r,
292
 
                         const String &rv){
293
 
  match=m;
294
 
  replace=r;
295
 
  replace_var=rv;
296
 
}
297
 
 
298
 
trans_class::~trans_class(){
299
 
  
300
 
}
301
 
 
302
 
bool  trans_class::check(String &s){
303
 
  config.report(String("checking ")+match+" < "+s,configinfo::report_debug);
304
 
  return match.contains(s,0);
305
 
}
306
 
 
307
 
String trans_class::debuginfo(){
308
 
  return String(" match=")+match+", replace="+replace+", replace_var="+replace_var;
309
 
}
310
 
 
311
 
void translate::process( menuentry &m,
312
 
                        const String &v){
313
 
  if(v==match)
314
 
    m.data[replace_var]=replace;
315
 
}
316
 
void subtranslate::process( menuentry &m,
317
 
                         const String &v){
318
 
  if(v.contains(match,0)){
319
 
    m.data[replace_var]=replace;
320
 
  }
321
 
}
322
 
 
323
 
void substitute::process( menuentry &m,
324
 
                   const String &v){
325
 
  String s,*t;
326
 
  if(v.contains(match,0)){
327
 
    t=&(m.data[replace_var]);
328
 
    if(t->length()>=replace.length())
329
 
      *t=replace+t->after(match.length());
330
 
  }
331
 
}
332
 
 
333
 
void translateinfo::init(parsestream &i){
334
 
  String name, match, replace, match_var, replace_var;
335
 
  Regex ident("[a-zA-Z_][a-zA-Z0-9_]*");
336
 
 
337
 
  config.report(String("Reading translate info in ")+i.filename(),
338
 
                configinfo::report_verbose);
339
 
  while(true){
340
 
    name=i.get_name(ident);
341
 
    config.report(String("name=")+name,
342
 
                  configinfo::report_debug);
343
 
    i.skip_space();
344
 
    match_var=i.get_name(ident);
345
 
    config.report(String("match_var=")+match_var,
346
 
                  configinfo::report_debug);
347
 
    i.skip_space();
348
 
    i.skip_char('-');
349
 
    i.skip_char('>');
350
 
    i.skip_space();
351
 
    replace_var=i.get_name(ident);
352
 
    config.report(String("replace_var=")+replace_var,
353
 
                  configinfo::report_debug);
354
 
    
355
 
    i.skip_line();
356
 
    while(true){
357
 
      trans_class *trcl;
358
 
      
359
 
      i.skip_space();
360
 
      match=i.get_Stringconst();
361
 
      if(match==String(ENDTRANSLATE_TRANS)){
362
 
        i.skip_line();
363
 
        break;
364
 
      }
365
 
      if(match[0]=='#'){
366
 
        i.skip_line();
367
 
        continue;
368
 
      }
369
 
      i.skip_space();
370
 
      replace=i.get_Stringconst();
371
 
      if(name==TRANSLATE_TRANS)
372
 
        trcl=new translate(match,replace,replace_var);
373
 
      if(name==SUBTRANSLATE_TRANS)
374
 
        trcl=new subtranslate(match,replace,replace_var);
375
 
      if(name==SUBSTITUTE_TRANS)
376
 
        trcl=new substitute(match,replace,replace_var);
377
 
      
378
 
      pair<const String, trans_class *> p(match,trcl);
379
 
      
380
 
      config.report(String("adding translate rule: [")+p.first+
381
 
                    "]"+ trcl->debuginfo(),
382
 
                    configinfo::report_debug);
383
 
      trans[match_var].insert(p);
384
 
      i.skip_line();
385
 
    }
386
 
  }
387
 
}
388
 
 
389
 
translateinfo::translateinfo(parsestream &i){
390
 
  init(i);
391
 
}
392
 
 
393
 
translateinfo::translateinfo(const String &filename){
394
 
  try{
395
 
    config.report(String("attempting to open ")+filename+".. ",
396
 
                  configinfo::report_debug);
397
 
    parsestream ps(filename);
398
 
    
399
 
    init(ps);
400
 
  }
401
 
  catch(endoffile p)
402
 
    {config.report(String("End reading translate info"),
403
 
                   configinfo::report_debug);}
404
 
  
405
 
}
406
 
 
407
 
void translateinfo::process(menuentry &m){
408
 
  map<String, trans_map, less<String> >::iterator i;
409
 
  trans_map::iterator j;
410
 
  String *match;
411
 
  for(i=trans.begin(); i!=trans.end(); i++){
412
 
    match=&m.data[(*i).first];
413
 
    j=(*i).second.lower_bound(*match);
414
 
    if((j==(*i).second.end()) ||
415
 
       ((j!=(*i).second.begin()) && ((*j).first != *match)))
416
 
      j--;
417
 
    do{
418
 
      config.report(String("translate: var[")+*match+"]"+
419
 
                    " testing trans rule match for:"+
420
 
                    (*j).first,
421
 
                    configinfo::report_debug);
422
 
      (*j).second->process(m,*match);
423
 
      j++;
424
 
    } while((j!=(*i).second.end())&&
425
 
            (*j).second->check(*match));
426
 
    
427
 
  }
428
 
}
429
 
void translateinfo::debuginfo(){
430
 
  map<String, trans_map, less<String> >::iterator i;
431
 
  trans_map::iterator j;
432
 
  for(i=trans.begin(); i!=trans.end(); i++){
433
 
    config.report(String("TRANS: [")+(*i).first+"]",
434
 
                  configinfo::report_debug);
435
 
    for(j=(*i).second.begin();
436
 
        j!=(*i).second.end();
437
 
        j++){
438
 
      config.report(String("key=")+(*j).first+
439
 
                    (*j).second->debuginfo()+"\n",
440
 
                    configinfo::report_debug);
441
 
      
442
 
      
443
 
    }
444
 
  } 
445
 
}
 
326
void translate::process(menuentry &m, const std::string &search)
 
327
{
 
328
  if (search == match)
 
329
      m.data[replace_var] = replace;
 
330
}
 
331
 
 
332
void subtranslate::process(menuentry &m, const std::string &search)
 
333
{
 
334
  if (contains(search, match))
 
335
      m.data[replace_var] = replace;
 
336
}
 
337
 
 
338
void substitute::process(menuentry &m, const std::string &search)
 
339
{
 
340
  if (contains(search, match)) {
 
341
    string *current = &(m.data[replace_var]);
 
342
    if (current->length() >= match.length())
 
343
        *current = replace + current->substr(match.length());
 
344
  }
 
345
}
 
346
 
 
347
translateinfo::translateinfo(const std::string &filename)
 
348
{
 
349
  parsestream *i = 0;
 
350
  try {
 
351
    i = new parsestream(filename);
 
352
 
 
353
    Regex ident("[[:alpha:]][[:alnum:]_]*");
 
354
    /*Translation here and below refer to the file 
 
355
      /etc/menu-methods/translate_menus that allow to rename and reorganize
 
356
      menu entries automatically. It does not refer to the localisation
 
357
      (translation to other languages).
 
358
     */
 
359
    config.report(String::compose(_("Reading translation rules in %1."), i->filename()),
 
360
        configinfo::report_verbose);
 
361
    while (true)
 
362
    {
 
363
      string name = i->get_name(ident);
 
364
      i->skip_space();
 
365
      string match_var = i->get_name(ident);
 
366
      i->skip_space();
 
367
      i->skip_char('-');
 
368
      i->skip_char('>');
 
369
      i->skip_space();
 
370
      string replace_var = i->get_name(ident);
 
371
 
 
372
      i->skip_line();
 
373
      while (true)
 
374
      {
 
375
        i->skip_space();
 
376
        string match = i->get_stringconst();
 
377
        if (match == ENDTRANSLATE_TRANS) {
 
378
          i->skip_line();
 
379
          break;
 
380
        }
 
381
        if (match[0]=='#') {
 
382
          i->skip_line();
 
383
          continue;
 
384
        }
 
385
        i->skip_space();
 
386
        string replace = i->get_stringconst();
 
387
        trans_class *trcl;
 
388
        if (name == TRANSLATE_TRANS) {
 
389
          trcl = new translate(match,replace,replace_var);
 
390
        } else if (name == SUBTRANSLATE_TRANS) {
 
391
          trcl = new subtranslate(match,replace,replace_var);
 
392
        } else if (name == SUBSTITUTE_TRANS) {
 
393
          trcl = new substitute(match,replace,replace_var);
 
394
        } else {
 
395
          i->skip_line();
 
396
          continue;
 
397
        }
 
398
 
 
399
        std::pair<const string, trans_class *> p(match, trcl);
 
400
 
 
401
        trans[match_var].push_back(p);
 
402
        i->skip_line();
 
403
      }
 
404
    }
 
405
  } catch(endoffile p) { }
 
406
  delete i;
 
407
}
 
408
 
 
409
void translateinfo::process(menuentry &m)
 
410
{
 
411
  std::map<string, std::vector<trans_pair> >::const_iterator i;
 
412
  std::vector<trans_pair>::const_iterator j;
 
413
  string *search;
 
414
  for (i = trans.begin(); i != trans.end(); ++i)
 
415
  {
 
416
    search = &m.data[i->first];
 
417
    for (j = i->second.begin(); j != i->second.end(); ++j)
 
418
    {
 
419
      j->second->process(m, *search);
 
420
    }
 
421
  }
 
422
}
 
423
 
446
424
/////////////////////////////////////////////////////
447
425
//  Installed Package Status:
448
426
//
449
427
 
450
 
void read_pkginfo (void)
451
 
{
452
 
  FILE *status;
453
 
  char tmp[MAX_LINE];
454
 
  char *getselections=
455
 
    "dpkg --get-selections|sed -n -e 's/[ \t]*\\(install\\|hold\\)$//p'";
456
 
 
457
 
  status=popen(getselections,"r");
458
 
 
459
 
  if(!status)
460
 
    throw pipeerror_read(getselections);
461
 
 
462
 
  config.report(String("Reading installed packages..."),
463
 
                configinfo::report_verbose);
464
 
  while (!feof (status)){
465
 
    fgets (tmp, MAX_LINE, status);
466
 
    if(tmp[strlen(tmp)-1]=='\n')
467
 
      tmp[strlen(tmp)-1]=0;
468
 
    installed_packages.insert(tmp);
469
 
  }
470
 
  pclose (status);
471
 
}
472
 
 
473
 
void read_menufile(const String &filename,
474
 
                   const String &shortfilename,
475
 
                   vector<String> &menudata){
476
 
  bool wrote_filename=false;
477
 
  parsestream *i;
478
 
  procbuf pr;
479
 
  istream *pipe_istr=NULL;
480
 
  int linenr=1;
481
 
 
482
 
  config.report(String("Reading menuentryfile ")+filename,
483
 
                configinfo::report_debug);
484
 
  try{
485
 
    if(executable(filename)){
486
 
      pr.open(filename.c_str(),ios::in);
487
 
      pipe_istr=new istream(&pr);
488
 
      try{
489
 
        i=new parsestream(*pipe_istr);
490
 
      } catch (endoffile d){
491
 
        cerr<<"Error (or no input available from stdout) while executing "<<endl
492
 
            <<filename<<" . Note that it is"<<endl
493
 
            <<"a _feature_ of menu that it executes menuentryfiles that have"<<endl
494
 
            <<"the executable bit set. See the documentation."<<endl;
495
 
        throw endoffile(d);
496
 
      }
497
 
    }
498
 
    else
499
 
      i=new parsestream(filename);
500
 
  } catch(endoffile p){
501
 
    return;
502
 
  }
503
 
 
504
 
  try{
505
 
    // Set compat mode:
506
 
    i->seteolmode(config.compat);
507
 
 
508
 
    while(true){//i->good()){
509
 
      try{
510
 
        menuentry m(*i,shortfilename);
511
 
        linenr++;
512
 
        if(transinfo)
513
 
          transinfo->process(m);
514
 
        //gettext_translate(m);
515
 
        if(!wrote_filename){
516
 
          menudata.push_back(String("!F ") + filename + "\n");
517
 
          wrote_filename=true;
518
 
        }
519
 
        m.output(menudata);
520
 
        if(i->linenumber() != linenr){
521
 
          menudata.push_back(String("!L ") + itoString(i->linenumber())+ "\n");
522
 
          linenr=i->linenumber();
523
 
        }
524
 
      }
525
 
      catch(cond_inst_false){}
526
 
    }
527
 
  }
528
 
  catch(endoffile p){
529
 
    if(executable(filename)){
530
 
      if(pipe_istr)
531
 
        delete pipe_istr;
532
 
      pr.close();
533
 
    }
534
 
    delete i;
535
 
  }
536
 
}
537
 
 
538
 
void read_menufilesdir(vector<String> &menudata){
539
 
  
540
 
  struct stat st;
541
 
  DIR *dir;
542
 
  struct dirent *entry;
543
 
  int r;
544
 
  String name;
545
 
  String dummy;
546
 
  cStrVec::iterator method_i;
547
 
  String dirname;
548
 
 
549
 
  for(method_i=config.menufilesdir.begin();
550
 
      method_i!=config.menufilesdir.end();
551
 
      method_i++){
552
 
    dirname=(*method_i);
553
 
    config.report(String("Reading menuentryfiles in ")+dirname,
554
 
                  configinfo::report_verbose);
555
 
    try{
556
 
      dir=open_dir_check(dirname);
557
 
      while((entry=readdir(dir))){
558
 
        name=String(entry->d_name);
559
 
        if((name!=String("README"))&&(name!=String("core"))&&(name[0]!='.')&&
560
 
           (name.find(".bak")==string::npos)&&
561
 
           (!name.contains(String("menu.config")))&&
562
 
           (name[name.length()-1]!='~'))
563
 
          if(menufiles_processed.find(name)==menufiles_processed.end()){
564
 
            menufiles_processed.insert(name);
565
 
            name=dirname+name;
566
 
            r=stat(name.c_str(),&st);
567
 
            try {
568
 
              if((!r)&&(S_ISREG(st.st_mode)||S_ISLNK(st.st_mode)))
569
 
                read_menufile(name,entry->d_name,
570
 
                              menudata);
571
 
            }
572
 
            catch(endofline p){
573
 
              cerr << "error reading " << name << endl;
574
 
            }
575
 
          }
576
 
      }
577
 
    } catch (dir_error_read p){dummy=p.name;}
578
 
  }
579
 
}
580
 
void run_menumethod(String methodname,
581
 
                    const vector<String> &menudata){
582
 
  const char *str;
 
428
/** Read in list of installed packages */
 
429
void read_pkginfo()
 
430
{
 
431
  // Here we get the list of *installed* packages from dpkg, using sed to
 
432
  // retrieve the package name.
 
433
  char *pkgs = "dpkg-query --show --showformat='${status} ${package}\\n' | sed -n -e 's/.*installed *//p'";
 
434
  FILE *status = popen(pkgs, "r");
 
435
 
 
436
  if (!status)
 
437
    throw pipeerror_read(pkgs);
 
438
 
 
439
  config.report(_("Reading installed packages list..."),
 
440
                  configinfo::report_verbose);
 
441
 
 
442
  while (!feof(status))
 
443
  {
 
444
    char tmp[MAX_LINE];
 
445
    if (fgets(tmp, MAX_LINE, status) != NULL) {
 
446
      if (tmp[strlen(tmp)-1] == '\n')
 
447
          tmp[strlen(tmp)-1] = 0;
 
448
 
 
449
      installed_packages.insert(tmp);
 
450
    }
 
451
  }
 
452
  pclose(status);
 
453
}
 
454
 
 
455
/** Read a menufile and create one (or more) menu entries for it.
 
456
 *
 
457
 * Returns the number of menu entries read. */
 
458
int read_menufile(const string &filename, const string &shortfilename,
 
459
                  vector<string> &menudata)
 
460
{
 
461
  int menuentries = 0;
 
462
  parsestream *ps = 0;
 
463
  std::stringstream *sstream = 0;
 
464
 
 
465
  try {
 
466
    // Whenever we encounter a file which has the executable bit set, we
 
467
    // need to execute it and read its output from stdout.
 
468
 
 
469
    if (executable(filename)) {
 
470
      FILE *status = popen(filename.c_str(), "r");
 
471
 
 
472
      sstream = new std::stringstream;
 
473
 
 
474
      if (!status)
 
475
          throw pipeerror_read(filename.c_str());
 
476
 
 
477
      while (!feof(status))
 
478
      {
 
479
        char tmp[MAX_LINE];
 
480
        if (fgets(tmp, MAX_LINE, status) != NULL)
 
481
            *sstream << tmp;
 
482
      }
 
483
      pclose(status);
 
484
 
 
485
      try {
 
486
        ps = new parsestream(*sstream);
 
487
      } catch (endoffile d) {
 
488
        cerr << String::compose(_("Execution of %1 generated no output or returned an error.\n"), filename);
 
489
        throw endoffile(d);
 
490
      }
 
491
    } else {
 
492
      ps = new parsestream(filename);
 
493
    }
 
494
  } catch (endoffile p) {
 
495
    delete sstream;
 
496
    return menuentries;
 
497
  }
 
498
 
 
499
  try {
 
500
    ps->seteolmode(config.compat);
 
501
 
 
502
    bool wrote_filename = false;
 
503
    int linenr = 1;
 
504
    while (true)
 
505
    {
 
506
      try {
 
507
        menuentry m(*ps, filename, shortfilename);
 
508
        linenr++;
 
509
        if (transinfo)
 
510
            transinfo->process(m);
 
511
        //gettext_translate(m);
 
512
        if (!wrote_filename) {
 
513
          menudata.push_back(string("!F ") + filename + '\n');
 
514
          wrote_filename = true;
 
515
        }
 
516
        m.output(menudata);
 
517
        menuentries++;
 
518
        if (ps->linenumber() != linenr) {
 
519
          menudata.push_back(string("!L ") + itostring(ps->linenumber())+ '\n');
 
520
          linenr = ps->linenumber();
 
521
        }
 
522
      }
 
523
      catch (cond_inst_false) { }
 
524
    }
 
525
  } 
 
526
  catch (endoffile p) { }
 
527
  catch (missing_tag& exc) {
 
528
    std::cerr << exc.message() << std::endl;
 
529
    std::cerr << _("Skipping file because of errors...\n");
 
530
  }
 
531
  catch (except_pi& exc) {
 
532
    exc.report();
 
533
    std::cerr << _("Skipping file because of errors...\n");
 
534
  }
 
535
 
 
536
  delete ps;
 
537
  delete sstream;
 
538
  return menuentries;
 
539
}
 
540
 
 
541
/** Read a directory full of menu files */
 
542
void read_menufilesdir(vector<string> &menudata)
 
543
{
 
544
  int menuentries = 0;
 
545
  for(vector<string>::const_iterator method_i = config.menufilesdir.begin();
 
546
      method_i != config.menufilesdir.end();
 
547
      ++method_i)
 
548
  {
 
549
    string dirname = *method_i;
 
550
    config.report(String::compose(_("Reading menu-entry files in %1."), dirname),
 
551
        configinfo::report_verbose);
 
552
    try {
 
553
      struct dirent *entry;
 
554
      DIR *dir = open_dir_check(dirname);
 
555
      while((entry = readdir(dir)))
 
556
      {
 
557
        string name = entry->d_name;
 
558
        if ((name != "README") && (name != "core") && (name[0] != '.') &&
 
559
            (name.find(".bak") == string::npos) &&
 
560
            (!contains(name, "menu.config")) &&
 
561
            (name[name.length()-1] != '~'))
 
562
 
 
563
            if (menufiles_processed.find(name) == menufiles_processed.end()) {
 
564
              menufiles_processed.insert(name);
 
565
              name = dirname+name;
 
566
              struct stat st;
 
567
              int r = stat(name.c_str(),&st);
 
568
              try {
 
569
                if ((!r) && (S_ISREG(st.st_mode)||S_ISLNK(st.st_mode)))
 
570
                    menuentries += read_menufile(name,entry->d_name, menudata);
 
571
              }
 
572
              catch (endofline p) {
 
573
                cerr << String::compose(_("Error reading %1.\n"), name);
 
574
              }
 
575
            }
 
576
      }
 
577
    } catch (dir_error_read p) { }
 
578
    total_menuentries += menuentries;
 
579
    config.report(String::compose(_("%1 menu entries found (%2 total)."), menuentries, total_menuentries), configinfo::report_verbose);
 
580
  }
 
581
}
 
582
 
 
583
/** Run a menu method */
 
584
void run_menumethod(string methodname, const vector<string> &menudata)
 
585
{
583
586
  int fds[2];
584
 
  const vector<String> *md;
585
 
  const char *args[]={methodname.c_str(), "-f", "--stdin", NULL, NULL};
586
 
  unsigned int i;
 
587
  const char *args[] = { methodname.c_str(), NULL };
587
588
  pid_t child, r;
588
 
  int status, ret;
589
 
 
590
 
  md=&menudata;
591
 
  config.report(String("Running method:")+methodname,
592
 
                configinfo::report_verbose);  
593
 
  
594
 
  ret=pipe(fds);
595
 
  if(ret==-1){
596
 
    config.report(String("Cannot create pipe"),
597
 
                  configinfo::report_quiet);  
598
 
    exit(1);
 
589
  int status;
 
590
 
 
591
  config.report(String::compose(_("Running method: %1"), methodname), configinfo::report_verbose);
 
592
 
 
593
  if (pipe(fds) == -1) {
 
594
      config.report(_("Cannot create pipe."), configinfo::report_quiet);
 
595
      exit(1);
599
596
  }
600
 
  if(!(child=fork())){
601
 
    //child:
 
597
 
 
598
  if (!(child=fork())) {
 
599
    // child:
602
600
    close(fds[1]);
603
601
    close(0);
604
602
    dup(fds[0]);
605
 
    
 
603
 
606
604
    //???
607
605
    // The next 2 lines seem strange! But if I leave it out,
608
606
    // pipes (in commands executed in the /etc/menu-method/* scripts as
614
612
 
615
613
    close(1);
616
614
    open("/dev/null", O_RDWR);
617
 
    execve(args[0],(char **)args, environ);
 
615
    execv(args[0],(char **)args);
618
616
    exit(1);
619
617
  } else {
620
 
    //parent:
 
618
    // parent:
621
619
    signal(SIGPIPE,SIG_IGN);
622
620
    close(fds[0]);
623
 
    for(i=0;i!=md->size();i++){
624
 
      str=(*md)[i].c_str();
625
 
      write(fds[1],str,strlen(str));
626
 
    }
 
621
 
 
622
    for(vector<string>::const_iterator i = menudata.begin(); i != menudata.end(); ++i)
 
623
        write(fds[1], i->c_str(), i->length());
 
624
 
627
625
    close(fds[1]);
628
 
    r=wait4(child,&status, 0, NULL);
 
626
    r = wait4(child, &status, 0, NULL);
629
627
    signal(SIGPIPE,SIG_DFL);
630
628
  }
631
 
  if(r==-1)
632
 
    config.report(String("Script ")+methodname+" could not be executed.",
633
 
                  configinfo::report_quiet);  
634
 
  if(WEXITSTATUS(status))
635
 
    config.report(String("Script ")+methodname+" returned error status "
636
 
                  +itoString(WEXITSTATUS(status))+".",
637
 
                  configinfo::report_quiet);  
638
 
  else if(WIFSIGNALED(status))
639
 
    config.report(String("Script ")+methodname+" recieved signal "
640
 
                  +itoString(WTERMSIG(status))+".",
641
 
                  configinfo::report_quiet);  
 
629
  if (r == -1)
 
630
    config.report(String::compose(_("Script %1 could not be executed."), methodname),
 
631
        configinfo::report_quiet);
 
632
  if (WEXITSTATUS(status))
 
633
    config.report(String::compose(_("Script %1 returned error status %2."), methodname, WEXITSTATUS(status)),
 
634
        configinfo::report_quiet);
 
635
  else if (WIFSIGNALED(status))
 
636
    config.report(String::compose(_("Script %1 received signal %2."), methodname, WTERMSIG(status)),
 
637
        configinfo::report_quiet);
642
638
}
643
639
 
644
 
void run_menumethoddir (const String &dirname,
645
 
                        const vector<String> &menudata){
646
 
  struct stat st;
647
 
  DIR *dir;
 
640
/** Run a directory full of menu methods */
 
641
void run_menumethoddir(const string &dirname, const vector<string> &menudata)
 
642
{
648
643
  struct dirent *entry;
649
 
  char *s, tmp[MAX_LINE];
650
 
  int r;
 
644
  char *s;
651
645
 
652
 
  config.report(String("Running menu-methods in ")+dirname,
653
 
                configinfo::report_verbose);
654
 
  dir=open_dir_check(dirname);
655
 
  while ((entry = readdir (dir)) != NULL){
656
 
    if (!strcmp(entry->d_name, "README") ||
657
 
        !strcmp(entry->d_name, "core"))
 
646
  config.report(String::compose(_("Running menu-methods in %1."), dirname), configinfo::report_verbose);
 
647
  DIR *dir = open_dir_check(dirname);
 
648
  while ((entry = readdir (dir)) != NULL) {
 
649
    if (!strcmp(entry->d_name, "README") || !strcmp(entry->d_name, "core"))
658
650
      continue;
659
 
    for (s = entry->d_name; *s != '\0'; s++){
 
651
    for (s = entry->d_name; *s != '\0'; s++)
 
652
    {
660
653
      if (!(isalnum (*s) || (*s == '_') || (*s == '-')))
661
 
        break;
 
654
          break;
662
655
    }
663
656
    if (*s != '\0')
664
657
      continue;
665
658
    
666
 
    sprintf (tmp, "%s/%s", dirname.c_str(), entry->d_name);
667
 
    r=stat (tmp, &st);
668
 
    
669
 
    // Do we have execute permissions? 
670
 
    if ((!r)&&
671
 
        (((st.st_mode & S_IXOTH) || 
672
 
          ((st.st_mode & S_IXGRP) && st.st_gid == getegid ()) || 
673
 
          ((st.st_mode & S_IXUSR) && st.st_uid == geteuid ())) && 
674
 
         (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))))
675
 
      run_menumethod(tmp,menudata);
 
659
    string method = dirname + entry->d_name;
 
660
 
 
661
    if (executable(method))
 
662
        run_menumethod(method, menudata);
676
663
  }
677
664
  closedir (dir);
678
665
}
679
666
 
680
 
int create_lock(){
 
667
/** Try to create a lock file for update-menus */
 
668
int create_lock()
 
669
{
681
670
  // return lock fd if succesful, false if unsuccesfull.
682
 
  int fd=true;
683
 
  
684
 
  if(!getuid()){
685
 
    fd=open(UPMEN_LOCKFILE,O_WRONLY|O_CREAT,00644);
686
 
    
687
 
    if(flock(fd,LOCK_EX|LOCK_NB)){
688
 
      if(errno==EWOULDBLOCK){
689
 
        config.report(String("Other update-menus processes are already "
690
 
                             "locking " UPMEN_LOCKFILE ", quitting."),
691
 
                      configinfo::report_verbose);
692
 
      }else{
693
 
        config.report(String("Cannot lock "UPMEN_LOCKFILE": ")+
694
 
                             strerror(errno)+ " Aborting.",
695
 
                      configinfo::report_quiet);        
 
671
  int fd = true;
 
672
  char buf[64];
 
673
 
 
674
  if (is_root) {
 
675
    fd = open(UPMEN_LOCKFILE,O_WRONLY|O_CREAT,00644);
 
676
 
 
677
    if (flock(fd,LOCK_EX|LOCK_NB)) {
 
678
      if (errno == EWOULDBLOCK || errno == EAGAIN) {
 
679
        config.report(String::compose(_("Other update-menus processes are already locking %1, quitting."), UPMEN_LOCKFILE),
 
680
            configinfo::report_verbose);
 
681
      } else {
 
682
        config.report(String::compose(_("Cannot lock %1: %2 - Aborting."), UPMEN_LOCKFILE, strerror(errno)),
 
683
            configinfo::report_quiet);  
696
684
      }
697
685
      return false;
698
 
        
 
686
 
699
687
    }
700
688
 
701
 
    ofstream of(fd);
702
 
    of<<getpid();
703
 
    if(!of.good()){
704
 
      config.report("cannot write to lockfile "
705
 
                    UPMEN_LOCKFILE". Aborting.",
706
 
                    configinfo::report_quiet);
 
689
    sprintf(buf, "%d", getpid());
 
690
    if (write(fd, buf, sizeof(buf) < 1)) {
 
691
      config.report(String::compose(_("Cannot write to lockfile %1 - Aborting."), UPMEN_LOCKFILE),
 
692
          configinfo::report_quiet);
707
693
      return false;
708
694
    }
709
695
  }
710
696
  return fd;
711
697
}
712
698
 
713
 
void remove_lock(){
714
 
  if(!getuid()){
715
 
    if(unlink(UPMEN_LOCKFILE))
716
 
      config.report("Cannot remove lockfile "UPMEN_LOCKFILE,
717
 
                    configinfo::report_normal);
 
699
/** Try to remove update-menus lock */
 
700
void remove_lock()
 
701
{
 
702
  if (is_root) {
 
703
    if (unlink(UPMEN_LOCKFILE))
 
704
      config.report(String::compose(_("Cannot remove lockfile %1."), UPMEN_LOCKFILE),
 
705
          configinfo::report_normal);
718
706
  }
719
707
}
720
708
 
721
 
int check_dpkglock(){
722
 
  //return 1 if DPKG_LOCKFILE is locked and we should wait
723
 
  //return 0 if we don't need to wait (not root, or no dpkg lock)
 
709
/** Check whether dpkg is locked
 
710
  * return 1 if DPKG_LOCKFILE is locked and we should wait
 
711
  * return 0 if we don't need to wait (not root, or no dpkg lock)
 
712
  * when in doubt return 0 to avoid deadlocks.
 
713
  */
 
714
int check_dpkglock()
 
715
{
724
716
  int fd;
725
717
  struct flock fl;
726
 
  char buf[MAX_LINE];
727
 
  int er;
728
 
  if(getuid()){
729
 
    config.report("update-menus run by user -- cannot determine if dpkg is "
730
 
                  "locking "DPKG_LOCKFILE": assuming there is no lock",
731
 
                  configinfo::report_verbose);
732
 
    
 
718
  if (!is_root)
 
719
  {
 
720
    config.report(_("Update-menus is run by user."), configinfo::report_verbose);
733
721
    return 0;
734
722
  }
735
 
  fd=open(DPKG_LOCKFILE, O_RDWR|O_CREAT|O_TRUNC, 0660);
736
 
  if(fd==-1)
737
 
    return 0; // used to be 1, but why??? (Should not happen, anyway)
738
 
  fl.l_type= F_WRLCK;
739
 
  fl.l_whence= SEEK_SET;
740
 
  fl.l_start= 0;
741
 
  fl.l_len= 0;
742
 
  if (fcntl(fd,F_SETLK,&fl) == -1) {
743
 
    er=errno;
 
723
  fl.l_type = F_WRLCK;
 
724
  fl.l_whence = SEEK_SET;
 
725
  fl.l_start = 0;
 
726
  fl.l_len = 0;
 
727
  fd = open(DPKG_LOCKFILE, O_RDWR|O_CREAT|O_TRUNC, 0660);
 
728
  if (fd == -1)
 
729
    /* Probably /var/lib/dpkg does not exist.
 
730
     * Most probably dpkg is not running.
 
731
     */
 
732
      return 0; 
 
733
  if (fcntl(fd,F_GETLK,&fl) == -1)
 
734
  {
 
735
    /* Probably /var/lib/dpkg filesystem does not support
 
736
     * locks.
 
737
     */
744
738
    close(fd);
745
 
    if (er == EWOULDBLOCK || er == EAGAIN || er == EACCES)
746
 
      return 1;
747
 
    cerr<<"update-menus: Encountered an unknown errno (="
748
 
        <<er<<")."<<endl
749
 
        <<"update-menus: Could you please be so kind as to email joostje@debian.org"<<endl
750
 
        <<"update-menus: the errno (="<<er<<") with a discription of what you did to"<<endl
751
 
        <<"update-menus: trigger this. Thanks very much."<<endl
752
 
        <<"Press enter"<<endl;
753
 
    cin.get(buf,sizeof(buf));
754
 
    return 1;
755
 
  }
756
 
  fl.l_type= F_UNLCK;
757
 
  fl.l_whence= SEEK_SET;
758
 
  fl.l_start= 0;
759
 
  fl.l_len= 0;
760
 
  if (fcntl(fd,F_SETLK,&fl) == -1){
761
 
    // `cannot happen'
762
 
    cerr<<"update-menus: ?? Just locked the dpkg status database to see if another dpkg"<<endl
763
 
        <<"update-menus: Was running. Now I cannot unlock it! Aborting"<<endl;
764
 
    exit(1);
 
739
    return 0;
765
740
  }
766
741
  close(fd);
767
 
  return 0;
 
742
  return fl.l_type!=F_UNLCK;
768
743
}
769
744
 
770
 
void exit_on_signal(int signr){
 
745
void exit_on_signal(int signr)
 
746
{
771
747
  exit(0);
772
748
}
773
749
 
774
 
void wait_dpkg(String &stdoutfile){
 
750
/** Check whether dpkg is running, and fork into background waiting if it is
 
751
 */
 
752
void wait_dpkg(string &stdoutfile)
 
753
{
775
754
  int child;
776
755
  int parentpid;
777
756
  int i,r;
792
771
  // have started writing stuff to the console. To prevent that,
793
772
  // I use signals: the `background' process sents a signal to the
794
773
  // parent once it's written everything it wants to stdout,
795
 
  // and only after the parent receved the signal it wil exit(0);
 
774
  // and only after the parent received the signal it will exit(0);
 
775
  // [Oh god! (added by Bill trying to understand the fork() business)]
796
776
 
797
 
  if(check_dpkglock()){
 
777
  if (check_dpkglock()) {
798
778
    sigset_t sig,oldsig;
799
779
 
800
780
    // Apparently libc2 on 2.0 kernels, with threading on, blocks
801
 
    // SIGUSR1. This blocking would be inhereted by children, so
 
781
    // SIGUSR1. This blocking would be inherited by children, so
802
782
    // as apt was compiled with -lpthread, this caused problems in 
803
783
    // update-menus. I now get rid of that by using
804
784
    //  - SIGUSR2 instead of SIGUSR1,
805
785
    //  - sigprocmask to unblock SIGUSR2.
806
 
    // Eighter one of those solutions should be enough, though.
 
786
    // Either one of those solutions should be enough, though.
807
787
 
808
788
    sigemptyset(&sig);
809
789
    sigaddset(&sig,SIGUSR2);
810
790
    sigprocmask(SIG_UNBLOCK,&sig,&oldsig);
811
791
 
812
 
    signal(SIGUSR2,exit_on_signal);
 
792
    signal(SIGUSR2, exit_on_signal);
813
793
    parentpid=getpid();
814
 
    if((child=fork())){
815
 
      if(child==-1){
816
 
        perror("update-menus: fork");
817
 
        exit(1);
 
794
    if ((child=fork())) {
 
795
      if (child==-1) {
 
796
        perror("update-menus: fork");
 
797
        exit(1);
818
798
      }
819
799
      pause();
820
800
    } else {
821
 
      r=create_lock();
822
 
      if(r){
823
 
        stdoutfile=String("/tmp/update-menus.")+itoString(getpid());
824
 
        config.report("waiting for dpkg to finish (forking to background)\n"
825
 
                      "(checking " DPKG_LOCKFILE ")",
826
 
                      configinfo::report_normal);
827
 
        config.report(String("further output (if any) will appear in ")
828
 
                      +stdoutfile,
829
 
                      configinfo::report_normal);
830
 
        // Close all fd's except the lock fd, for daemon mode.
831
 
        for (i=0;i<32;i++) {
832
 
          if (i != r)
833
 
            close(i);
834
 
        }
835
 
        kill(parentpid, SIGUSR2);
 
801
      r = create_lock();
 
802
      if (r) {
 
803
        stdoutfile = string("/tmp/update-menus.")+itostring(getpid());
 
804
        config.report(String::compose(_("Waiting for dpkg to finish (forking to background).\n"
 
805
            "(checking %1)"), DPKG_LOCKFILE),
 
806
            configinfo::report_normal);
 
807
        config.report(String::compose(_("Further output (if any) will appear in %1."), stdoutfile),
 
808
            configinfo::report_normal);
 
809
        // Close all fd's except the lock fd, for daemon mode.
 
810
        for (i=0;i<32;i++) {
 
811
          if (i != r)
 
812
              close(i);
 
813
        }
 
814
        kill(parentpid, SIGUSR2);
836
815
 
837
 
        while(check_dpkglock())
838
 
          sleep(2);
 
816
        while(check_dpkglock())
 
817
            sleep(2);
839
818
      } else {
840
 
        // Exit without doing anything. Kill parent too!
841
 
        kill(parentpid,SIGUSR2);
842
 
        exit(0);
 
819
        // Exit without doing anything. Kill parent too!
 
820
        kill(parentpid,SIGUSR2);
 
821
        exit(0);
843
822
      }
844
823
    }
845
824
  } else {
846
 
    r=create_lock();
847
 
    if(!r){
 
825
    r = create_lock();
 
826
    if (!r)
 
827
        exit(1);
 
828
 
 
829
    config.report(_("Dpkg is not locking dpkg status area, good."),
 
830
        configinfo::report_verbose);
 
831
  }
 
832
}
 
833
 
 
834
/** Print usage information */
 
835
void usage(ostream &c)
 
836
{
 
837
      c <<
 
838
          _( /* This is the update-menus --help message*/
 
839
  "Usage: update-menus [options] \n"
 
840
  "Gather packages data from the menu database and generate menus for\n"
 
841
  "all programs providing menu-methods, usually window-managers.\n"
 
842
  "  -d                     Output debugging messages.\n"
 
843
  "  -v                     Be verbose about what is going on.\n"
 
844
  "  -h, --help             This message.\n"
 
845
  "  --menufilesdir=<dir>   Add <dir> to the lists of menu directories to search.\n"
 
846
  "  --menumethod=<method>  Run only the menu method <method>.\n"
 
847
  "  --nodefaultdirs        Disable the use of all the standard menu directories.\n"
 
848
  "  --stdout               Output menu list in format suitable for piping to\n"
 
849
  "                         install-menu.\n")
 
850
       << _(  /* This is the end of the update-menus --help message*/
 
851
  "  --version              Output version information and exit.\n"  );
 
852
}
 
853
 
 
854
struct option long_options[] = { 
 
855
  { "debug", no_argument, NULL, 'd' }, 
 
856
  { "verbose", no_argument, NULL, 'v' }, 
 
857
  { "help", no_argument, NULL, 'h' }, 
 
858
  { "menufilesdir", required_argument, NULL, 'f'},
 
859
  { "menumethod", required_argument, NULL, 'm'},
 
860
  { "nodefaultdirs", no_argument, NULL, 'n'},
 
861
  { "stdout", no_argument, NULL, 's'},
 
862
  { "version", no_argument, NULL, 'V'},
 
863
  { NULL, 0, NULL, 0 } };
 
864
 
 
865
 
 
866
/** Parse commandline parameters */
 
867
void parse_params(int argc, char **argv)
 
868
{
 
869
  while(1)
 
870
  {
 
871
    int c = getopt_long (argc, argv, "hvd", long_options, NULL);
 
872
    if (c == -1) 
 
873
      break;
 
874
    switch(c)
 
875
    {
 
876
    case 'v':
 
877
        config.set_verbosity(configinfo::report_verbose);
 
878
      break;
 
879
    case 'd':
 
880
        config.set_verbosity(configinfo::report_verbose);
 
881
      break;
 
882
    case 'n':
 
883
      config.usedefaultmenufilesdirs = false;
 
884
      break;
 
885
    case 's':
 
886
      config.onlyoutput_to_stdout = true;
 
887
      break;
 
888
    case 'f':
 
889
      config.menufilesdir.push_back(optarg);
 
890
      break;
 
891
    case 'm':
 
892
      config.menumethod = optarg;
 
893
      break;
 
894
    case 'V':
 
895
      cout << "update-menus "VERSION << std::endl;
 
896
      exit(0);
 
897
    case 'h':
 
898
      usage(cout);
 
899
      exit(0);
 
900
    default: 
 
901
      usage(cerr);
848
902
      exit(1);
849
903
    }
850
 
    config.report("Dpkg not locking dpkg status area. Good.",
851
 
                  configinfo::report_verbose);
852
 
  }
853
 
}
854
 
 
855
 
void parse_params(char **argv){
856
 
  while(*(++argv)){
857
 
    if(String("-d")==String(*argv))
858
 
      config.set_verbosity(configinfo::report_debug);
859
 
    if(String("-v")==String(*argv))
860
 
      config.set_verbosity(configinfo::report_verbose);
861
 
    if(String("--nodefaultdirs")==String(*argv))
862
 
      config.usedefaultmenufilesdirs=false;
863
 
    if(String("--menufiledir")==String(*argv)){
864
 
      argv++;
865
 
      if(*argv)
866
 
        (config.menufilesdir).push_back(String(*argv));
867
 
      else{
868
 
        cerr<<_("directory expected after --menufilesdir option")<<endl;
869
 
        throw informed_fatal();
870
 
      }
871
 
    }
872
 
    if(String("--menumethod")==String(*argv)){
873
 
      argv++;
874
 
      if(*argv)
875
 
        config.menumethod=String(*argv);
876
 
      else{
877
 
        cerr<<_("filename expected after --menumethod option")<<endl;
878
 
        throw informed_fatal();
879
 
      }
880
 
    }
881
 
    if(String("-h")==String(*argv)){
882
 
      cerr<<
883
 
        _("update-menus: update the various window-manager config files (and\n"
884
 
          "  dwww, and pdmenu) Usage: update-menus [options] \n"
885
 
          "    -v  be verbose about what is going on\n"
886
 
          "    -d  debugging (loads of unintelligible output)")<<endl;
887
 
        exit(1);
888
 
    }
889
 
  }
890
 
}
891
 
 
892
 
void read_userconfiginfo(){
893
 
  //Because of gcc-2.7.2.1 internal compiler errors, had to split this up.
894
 
  //(well, not sure of the configinfo stuff, but translateinfo failed)
895
 
  if(getuid()){
896
 
    try{
897
 
      config.update(String(getenv("HOME"))+"/"+USERCONFIG);
898
 
    } catch(ferror_open d){};
899
 
  };
900
 
}
901
 
 
902
 
void read_rootconfiginfo(){
 
904
  }
 
905
}
 
906
 
 
907
/** Read users configuration file */
 
908
void read_userconfiginfo()
 
909
{
 
910
  if (!is_root) {
 
911
    try {
 
912
      config.read_file(string(home_dir)+"/"+USERCONFIG);
 
913
    } catch(ferror_open d) { };
 
914
  }
 
915
}
 
916
 
 
917
/** Read roots configuration file */
 
918
void read_rootconfiginfo()
 
919
{
903
920
  if(!transinfo){
904
 
    try{
905
 
      config.update(CONFIG_FILE);
 
921
    try {
 
922
      config.read_file(CONFIG_FILE);
906
923
    } catch (ferror_open d){};
907
924
  }
908
925
}
909
926
 
910
 
void read_usertranslateinfo(){
911
 
  //Because of gcc-2.7.2.1 internal compiler errors, had to split this up.
912
 
  if(getuid()){
913
 
    try{
914
 
      transinfo=new translateinfo(String(getenv("HOME"))+"/"+USERTRANSLATE);
915
 
    } catch(ferror_open d){};
916
 
  };
917
 
}
918
 
 
919
 
void read_roottranslateinfo(){
920
 
  if(!transinfo){
921
 
    try{
922
 
      transinfo=new translateinfo(TRANSLATE_FILE);
923
 
    }catch (ferror_open d){};
924
 
  }
925
 
}
926
 
 
927
 
int main (int, char **argv){
928
 
  vector<String> menudata;
929
 
  String dummy;
930
 
  String stdoutfile;
 
927
/** Read users translate information */
 
928
void read_usertranslateinfo()
 
929
{
 
930
  if (!is_root) {
 
931
    try {
 
932
      transinfo = new translateinfo(string(home_dir)+"/"+USERTRANSLATE);
 
933
    } catch(ferror_open d) { };
 
934
  }
 
935
}
 
936
 
 
937
/** Read roots translate information */
 
938
void read_roottranslateinfo()
 
939
{
 
940
  if (!transinfo) {
 
941
    try {
 
942
      transinfo = new translateinfo(TRANSLATE_FILE);
 
943
    } catch (ferror_open d) { };
 
944
  }
 
945
}
 
946
 
 
947
/** Find our home directory */
 
948
void read_homedirectory()
 
949
{
 
950
  struct passwd *pwentry = getpwuid(getuid());
 
951
 
 
952
  if (pwentry != NULL)
 
953
      home_dir = pwentry->pw_dir;
 
954
  else
 
955
      home_dir = getenv("HOME");
 
956
}
 
957
 
 
958
int main (int argc, char **argv)
 
959
{
 
960
  is_root = (getuid() == 0);
 
961
  read_homedirectory();
 
962
 
 
963
  vector<string> menudata;
 
964
  string stdoutfile;
931
965
  struct stat st;
932
 
  int r;
933
 
  
934
 
  setlocale (LC_MESSAGES, "");
 
966
 
 
967
  setlocale (LC_ALL, "");
935
968
  bindtextdomain (PACKAGE, LOCALEDIR);
936
969
  textdomain (PACKAGE);
937
 
  
938
970
 
939
 
  debug=0;
940
 
  try{
941
 
    //  read_userconfiginfo();
 
971
  try {
942
972
    read_rootconfiginfo();
943
 
    parse_params(argv);
 
973
    parse_params(argc, argv);
944
974
    wait_dpkg(stdoutfile);
945
 
    if(stdoutfile.length()){
 
975
    if(!stdoutfile.empty()) {
946
976
      close(1);
947
 
      open(stdoutfile.c_str(),
948
 
           O_WRONLY|O_CREAT|O_SYNC|O_EXCL, 0666);
 
977
      open(stdoutfile.c_str(), O_WRONLY|O_CREAT|O_SYNC|O_EXCL, 0666);
949
978
      close(2);
950
979
      dup2(1,2);
951
980
    }
952
981
    read_pkginfo();
953
 
    transinfo=NULL;
 
982
    transinfo = 0;
954
983
 
955
984
    read_usertranslateinfo();
956
985
    read_roottranslateinfo();
957
 
    if(transinfo)
958
 
      transinfo->debuginfo();
959
 
    if(config.usedefaultmenufilesdirs){
960
 
      if(getuid())
961
 
        (config.menufilesdir).push_back(String(getenv("HOME"))+
962
 
                                        "/"+USERMENUS);
963
 
      (config.menufilesdir).push_back(String(CONFIGMENUS));
964
 
      (config.menufilesdir).push_back(String(PACKAGEMENUS));
965
 
      (config.menufilesdir).push_back(String(MENUMENUS));
 
986
 
 
987
    if (config.usedefaultmenufilesdirs) {
 
988
      if (!is_root)
 
989
          config.menufilesdir.push_back(string(home_dir)+"/"+USERMENUS);
 
990
      config.menufilesdir.push_back(CONFIGMENUS);
 
991
      config.menufilesdir.push_back(PACKAGEMENUSLIB);
 
992
      config.menufilesdir.push_back(PACKAGEMENUS);
 
993
      config.menufilesdir.push_back(MENUMENUS);
966
994
    }
967
 
    
 
995
 
968
996
    read_menufilesdir(menudata);
969
 
    
970
 
    if(config.menumethod.length())
971
 
      run_menumethod(config.menumethod,menudata);
972
 
    else{
973
 
      if(getuid()){
974
 
        try{
975
 
          run_menumethoddir(String(getenv("HOME"))+"/"+USERMETHODS,
976
 
                            menudata);
977
 
        }
978
 
        catch(dir_error_read d){
979
 
          dummy=d.name;
980
 
          run_menumethoddir(MENUMETHODS, menudata);     
981
 
        }
982
 
      } else
983
 
        run_menumethoddir(MENUMETHODS, menudata);
 
997
 
 
998
    if (config.onlyoutput_to_stdout) {
 
999
        for(vector<string>::const_iterator i = menudata.begin(); i != menudata.end(); ++i)
 
1000
              cout << *i;
 
1001
 
 
1002
    } else if (!config.menumethod.empty()) {
 
1003
      if (executable(config.menumethod))
 
1004
        run_menumethod(config.menumethod, menudata);
 
1005
      else
 
1006
        config.report(String::compose(_("Script %1 could not be executed."),
 
1007
              config.menumethod), configinfo::report_quiet);
 
1008
    } else {
 
1009
      if (!is_root) {
 
1010
        try {
 
1011
          run_menumethoddir(string(home_dir)+"/"+USERMETHODS, menudata);
 
1012
        }
 
1013
        catch(dir_error_read d) {
 
1014
          run_menumethoddir(MENUMETHODS, menudata);
 
1015
        }
 
1016
      } else {
 
1017
          run_menumethoddir(MENUMETHODS, menudata);
 
1018
      }
984
1019
    }
985
1020
  }
986
 
  catch(genexcept& p){p.report();}
987
 
  /*  catch(except_String& p){p.report();}
988
 
  catch(except_pi& p){p.report();}
989
 
  catch(unknown_cond_package p){  p.report(); }
990
 
  catch(informed_fatal p){};
991
 
  */
992
 
  /*  catch(endoffile p){        p.report(cerr); }
993
 
  catch(endofline p){        p.report(cerr); }
994
 
  catch(char_expected p){    p.report(cerr); }
995
 
  catch(char_unexpected p){  p.report(cerr); }
996
 
  catch(def_error p){        p.report(cerr); }
997
 
  catch(unknown_compat p){   p.report(cerr); }
998
 
 
999
 
  */
1000
 
  //  catch (ferror_read f){
1001
 
  //    cerr<<"Cannot open file "<<f.name<<" for reading"<<endl;
1002
 
  //  }
1003
 
  //  catch (dir_error_read d){
1004
 
  //    cerr<<"Cannot open directory "<<d.name<<" for reading"<<endl;
1005
 
  //  }
1006
 
  //catch (informed_fatal){
1007
 
  //  cerr<<"Aborting."<<endl;
1008
 
  //  }
 
1021
  catch(genexcept& p) { p.report(); }
1009
1022
 
1010
1023
  remove_lock();
1011
1024
 
1012
 
  if(stdoutfile.length()){
1013
 
    r=stat(stdoutfile.c_str(),&st);
1014
 
    if(!r)
1015
 
      if(!st.st_size)
1016
 
        unlink(stdoutfile.c_str());
1017
 
  }
1018
 
  return 0;
 
1025
  if(!stdoutfile.empty())
 
1026
      if (!stat(stdoutfile.c_str(),&st))
 
1027
          if (!st.st_size)
 
1028
              unlink(stdoutfile.c_str());
1019
1029
}