ucommon  7.0.0
About: GNU uCommon C++ is a portable and optimized class framework for writing C++ applications that need to use threads and support concurrent synchronization, and that use sockets, XML parsing, object serialization, thread-optimized string and data structure classes, etc..
  Fossies Dox: ucommon-7.0.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

shell.cpp
Go to the documentation of this file.
1 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This file is part of GNU uCommon C++.
5 //
6 // GNU uCommon C++ is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Lesser General Public License as published
8 // by the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // GNU uCommon C++ is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
18 
19 #include <ucommon-config.h>
20 #include <ucommon/export.h>
21 #include <ucommon/protocols.h>
22 #include <ucommon/string.h>
23 #include <ucommon/memory.h>
24 #include <ucommon/thread.h>
25 #include <ucommon/fsys.h>
26 #include <ucommon/shell.h>
27 
28 #ifndef UCOMMON_SYSRUNTIME
29 #include <ucommon/stream.h>
30 #endif
31 
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #include <ctype.h>
38 
39 #ifdef _MSWINDOWS_
40 #include <process.h>
41 #include <winreg.h>
42 #include <conio.h>
43 #else
44 #include <sys/wait.h>
45 #include <sys/ioctl.h>
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49 #ifdef HAVE_TERMIOS_H
50 #include <termios.h>
51 #endif
52 #ifdef HAVE_TERMIO_H
53 #include <termio.h>
54 #endif
55 #endif
56 
57 #ifdef HAVE_SYS_RESOURCE_H
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #endif
61 
62 #ifdef HAVE_SETLOCALE
63 #include <locale.h>
64 #else
65 #define setlocale(s, t)
66 #endif
67 
68 #ifndef HAVE_LIBINTL_H
69 #undef HAVE_GETTEXT
70 #endif
71 
72 #ifdef HAVE_GETTEXT
73 #include <libintl.h>
74 #else
75 #define dgettext(d, s) s
76 #define gettext(s) s
77 #define bindtextdomain(s, t)
78 #define textdomain(s)
79 #endif
80 
81 #ifdef HAVE_SYSLOG_H
82 #include <syslog.h>
83 #endif
84 
85 #ifndef OPEN_MAX
86 #define OPEN_MAX 20
87 #endif
88 
89 #ifndef WEXITSTATUS
90 #define WEXITSTATUS(status) ((unsigned)(status) >> 8)
91 #endif
92 
93 #ifndef _PATH_TTY
94 #define _PATH_TTY "/dev/tty"
95 #endif
96 
97 namespace ucommon {
98 
101 static const char *errname = NULL;
104 static char **_orig = NULL;
105 static shell::Option *ofirst = NULL, *olast = NULL;
106 static const char *_domain = NULL;
109 static long numeric_value = 0l;
110 
111 shell::Option::Option(char shortopt, const char *longopt, const char *value, const char *help) :
112 LinkedObject()
113 {
114  if(olast) {
115  olast->Next = this;
116  olast = this;
117  }
118  else
119  ofirst = olast = this;
120 
121  while(longopt && *longopt == '-')
122  ++longopt;
123 
124  short_option = shortopt;
125  long_option = longopt;
126  uses_option = value;
127  help_string = help;
128  trigger_option = false;
129 }
130 
132 {
133 }
134 
136 {
137  ofirst = olast = NULL;
138 }
139 
141 {
142  return ofirst;
143 }
144 
146 {
147  short_option = 0;
148  long_option = NULL;
149  help_string = NULL;
150  uses_option = NULL;
151 }
152 
153 shell::flagopt::flagopt(char short_option, const char *long_option, const char *help_string, bool single_use) :
154 shell::Option(short_option, long_option, NULL, help_string)
155 {
156  single = single_use;
157  counter = 0;
158 }
159 
160 const char *shell::flagopt::assign(const char *value)
161 {
162  if(single && counter)
164 
165  ++counter;
166  return NULL;
167 }
168 
169 shell::numericopt::numericopt(char short_option, const char *long_option, const char *help_string, const char *type, long def_value) :
170 shell::Option(short_option, long_option, type, help_string)
171 {
172  used = false;
173  number = def_value;
174 }
175 
176 const char *shell::numericopt::assign(const char *value)
177 {
178  char *endptr = NULL;
179 
180  if(used)
181  return errmsg(shell::OPTION_USED);
182 
183  used = true;
184  number = strtol(value, &endptr, 0);
185  if(!endptr || *endptr != 0)
186  return errmsg(shell::BAD_VALUE);
187 
188  return NULL;
189 }
190 
191 shell::counteropt::counteropt(char short_option, const char *long_option, const char *help_string, const char *type, long def_value) :
192 shell::Option(short_option, long_option, type, help_string)
193 {
194  used = false;
195  number = def_value;
196  trigger_option = true;
197 }
198 
199 const char *shell::counteropt::assign(const char *value)
200 {
201  char *endptr = NULL;
202 
203  // trigger option mode received...
204  if(value == NULL) {
205  ++number;
206  used = true;
207  return NULL;
208  }
209 
210  if(used)
211  return errmsg(shell::OPTION_USED);
212 
213  used = true;
214  number = strtol(value, &endptr, 0);
215  if(!endptr || *endptr != 0)
216  return errmsg(shell::BAD_VALUE);
217 
218  return NULL;
219 }
220 
221 shell::groupopt::groupopt(const char *help_string) :
222 shell::Option(0, NULL, NULL, help_string)
223 {
224 }
225 
226 const char *shell::groupopt::assign(const char *value)
227 {
228  return NULL;
229 }
230 
231 shell::stringopt::stringopt(char short_option, const char *long_option, const char *help_string, const char *type, const char *def_value) :
232 shell::Option(short_option, long_option, type, help_string)
233 {
234  used = false;
235  text = def_value;
236 }
237 
238 const char *shell::stringopt::assign(const char *value)
239 {
240  if(used)
242 
243  text = value;
244  used = true;
245  return NULL;
246 }
247 
248 shell::charopt::charopt(char short_option, const char *long_option, const char *help_string, const char *type, char def_value) :
249 shell::Option(short_option, long_option, type, help_string)
250 {
251  used = false;
252  code = def_value;
253 }
254 
255 const char *shell::charopt::assign(const char *value)
256 {
257  long number;
258  char *endptr = NULL;
259 
260  if(used)
262 
263  used = true;
264  if(value[1] == 0) {
265  code = value[0];
266  return NULL;
267  }
268 
269  number = strtol(value, &endptr, 0);
270  if(!endptr || *endptr != 0)
271  return errmsg(shell::BAD_VALUE);
272 
273  if(number < 0 || number > 255)
274  return errmsg(shell::BAD_VALUE);
275 
276  code = (char)(number);
277  return NULL;
278 }
279 
281 {
282  char **argv = _argv = (char **)mempager::_alloc(sizeof(char **) * (_argc + 1));
283  linked_pointer<args> ap = first;
284  while(is(ap)) {
285  *(argv++) = ap->item;
286  ap.next();
287  }
288  *argv = NULL;
289 }
290 
291 void shell::set0(char *argv0)
292 {
293  char prefix[256];
294 
295  if(_argv0)
296  return;
297 
298  if(argv0 && *argv0 != '/' && *argv0 != '\\' && argv0[1] != ':') {
299  fsys::prefix(prefix, sizeof(prefix));
300  String::add(prefix, sizeof(prefix), "/");
301  String::add(prefix, sizeof(prefix), argv0);
302  }
303  else
304  String::set(prefix, sizeof(prefix), argv0);
305 
306  argv0 = _exedir = dup(prefix);
307 
308  _argv0 = strrchr(argv0, '/');
309 #ifdef _MSWINDOWS_
310  if(!_argv0)
311  _argv0 = strrchr(argv0, '\\');
312  if(!_argv0)
313  _argv0 = strchr(argv0, ':');
314 #endif
315  if(!_argv0)
316  _argv0 = argv0;
317  else
318  (*_argv0++) = 0;
319 
320  if(eq(_argv0, "lt-", 3))
321  _argv0 += 3;
322 
323 // _argv0 = dup(_argv0);
324 
325 #ifdef _MSWINDOWS_
326  char *ext = strrchr(_argv0, '.');
327  if(eq_case(ext, ".exe") || eq_case(ext, ".com"))
328  *ext = 0;
329 #endif
330 
331  if(!_domain)
332  bind(_argv0);
333 }
334 
337 {
338  _exedir = NULL;
339  _argv0 = NULL;
340  _argv = NULL;
341  _argc = 0;
342  _syms = NULL;
343 }
344 
345 shell::shell(const char *string, size_t pagesize) :
346 mempager(pagesize)
347 {
348  _argv0 = NULL;
349  _argv = NULL;
350  _argc = 0;
351  _syms = NULL;
352 
353  parse(string);
354 }
355 
356 shell::shell(int argc, char **argv, size_t pagesize) :
357 mempager(pagesize)
358 {
359  _argv0 = NULL;
360  _argv = NULL;
361  _argc = 0;
362  _syms = NULL;
363 
364  parse(argc, argv);
365 }
366 
367 static const char *msgs[] = {
368  _TEXT("missing command line arguments"),
369  _TEXT("missing argument for option"),
370  _TEXT("option does not have argument"),
371  _TEXT("unknown command option"),
372  _TEXT("option already used"),
373  _TEXT("invalid argument used"),
374  _TEXT("numeric value already set"),
375  NULL};
376 
377 const char *shell::errmsg(errmsg_t id)
378 {
379  return dgettext("ucommon", msgs[id]);
380 }
381 
382 void shell::errmsg(errmsg_t id, const char *text)
383 {
384  msgs[id] = shell::text(text);
385 }
386 
388 {
389  numeric_mode = mode;
390  numeric_value = 0l;
391 }
392 
394 {
395  return numeric_value;
396 }
397 
398 unsigned shell::count(char **argv)
399 {
400  unsigned count = 0;
401 
402  while(argv && argv[count])
403  ++count;
404 
405  return count;
406 }
407 
408 void shell::help(void)
409 {
411  size_t hp = 0, count = 0;
412  while(is(op)) {
413  if(!op->help_string) {
414  ++op;
415  continue;
416  }
417  if(op->short_option && op->long_option && op->uses_option && !op->trigger_option) {
418  printf(" -%c .., ", op->short_option);
419  hp = 9;
420  }
421  else if(op->short_option && op->long_option) {
422  printf(" -%c, ", op->short_option);
423  hp = 6;
424  }
425  else if(op->long_option) {
426  printf(" ");
427  hp = 2;
428  }
429  else if(op->uses_option) {
430  printf(" -%c %s", op->short_option, op->uses_option);
431  hp = 5 + strlen(op->uses_option);
432  }
433  else if(op->short_option) {
434  printf(" -%c ", op->short_option);
435  hp = 5;
436  }
437  else { // grouping separator
438  if(count)
439  printf("\n%s:\n", op->help_string);
440  else
441  printf("%s:\n", op->help_string);
442  ++op;
443  continue;
444  }
445 
446  ++count;
447 
448  if(op->long_option && op->uses_option) {
449  printf("--%s=%s", op->long_option, op->uses_option);
450  hp += strlen(op->long_option) + strlen(op->uses_option) + 3;
451  }
452  else if(op->long_option) {
453  printf("--%s", op->long_option);
454  hp += strlen(op->long_option) + 2;
455  }
456  if(hp > 29) {
457  printf("\n");
458  hp = 0;
459  }
460  while(hp < 30) {
461  putchar(' ');
462  ++hp;
463  }
464  const char *hs = shell::text(op->help_string);
465  while(*hs) {
466  if(*hs == '\n' || (((*hs == ' ' || *hs == '\t')) && (hp > 75))) {
467  printf("\n ");
468  hp = 30;
469  }
470  else if(*hs == '\t') {
471  if(!(hp % 8)) {
472  putchar(' ');
473  ++hp;
474  }
475  while(hp % 8) {
476  putchar(' ');
477  ++hp;
478  }
479  }
480  else
481  putchar(*hs);
482  ++hs;
483  }
484  printf("\n");
485  ++op;
486  }
487 }
488 
489 char **shell::parse(const char *string)
490 {
491  assert(string != NULL);
492 
493  args *arg;
494  char quote = 0;
495  char *cp = mempager::dup(string);
496  bool active = false;
497  OrderedIndex arglist;
498 
499  _argc = 0;
500 
501  while(*cp) {
502  if(isspace(*cp) && active && !quote) {
503 inactive:
504  active = false;
505  *(cp++) = 0;
506  continue;
507  }
508  if(*cp == '\'' && !active) {
509  quote = *cp;
510  goto argument;
511  }
512  if(*cp == '\"' && !active) {
513  quote = *(cp++);
514  goto argument;
515  }
516  if(*cp == quote && active) {
517  if(quote == '\"')
518  goto inactive;
519  if(isspace(cp[1])) {
520  ++cp;
521  goto inactive;
522  }
523  }
524  if(!isspace(*cp) && !active) {
525 argument:
526  ++_argc;
527  active = true;
528  arg = init<args>((args *)mempager::_alloc(sizeof(args)));
529  arg->item = (cp++);
530  arg->enlist(&arglist);
531  continue;
532  }
533  ++cp;
534  }
535  collapse(arglist.begin());
536  set0(*_argv);
537  return _argv;
538 }
539 
540 int shell::systemf(const char *format, ...)
541 {
542  va_list args;
543  char buffer[1024];
544 
545  va_start(args, format);
546  vsnprintf(buffer, sizeof(buffer), format, args);
547  va_end(args);
548 
549  return system(buffer);
550 }
551 
552 void shell::parse(int argc, char **argv)
553 {
554  if(!_orig)
555  _orig = argv;
556 
557  getargv0(argv);
558  getargv(++argv);
559 }
560 
561 char *shell::getargv0(char **argv)
562 {
563  if(!argv || !argv[0])
564  errexit(-1, "*** %s\n", errmsg(shell::NOARGS));
565  else
566  set0(argv[0]);
567  return _argv0;
568 }
569 
570 char **shell::getargv(char **argv)
571 {
572  char *arg, *opt;
573  size_t len;
574  const char *value;
575  const char *err;
576  unsigned argp = 0;
577  bool skip;
578 
579  while(argv[argp]) {
580  skip = false;
581  if(eq(argv[argp], "--")) {
582  ++argp;
583  break;
584  }
585  arg = opt = argv[argp];
586 
587  switch(numeric_mode) {
588  case shell::NUMERIC_DASH:
589  case shell::NUMERIC_ALL:
590  if(opt[0] == '-' && opt[1] >= '0' && opt[1] <= '9') {
591  if(numeric_value)
592  shell::errexit(1, "*** %s: %s: %s\n",
594  numeric_value = atol(opt);
595  skip = true;
596  }
597  break;
598  default:
599  break;
600  }
601 
602  switch(numeric_mode) {
603  case shell::NUMERIC_PLUS:
604  case shell::NUMERIC_ALL:
605  if(opt[0] == '+' && opt[1] >= '0' && opt[1] <= '9') {
606  if(numeric_value)
607  shell::errexit(1, "*** %s: %s: %s\n",
609  numeric_value = atol(++opt);
610  skip = true;
611  }
612  break;
613  default:
614  break;
615  }
616 
617  if(skip) {
618  ++argp;
619  continue;
620  }
621 
622  if(*arg != '-')
623  break;
624 
625  ++argp;
626 
628  err = NULL;
629  value = NULL;
630 
631  ++opt;
632  if(*opt == '-')
633  ++opt;
634 
635  // long option parsing...
636 
637  while(is(op)) {
638  if(!op->long_option) {
639  op.next();
640  continue;
641  }
642  len = strlen(op->long_option);
643  value = NULL;
644  if(op->long_option && eq(op->long_option, opt, len)) {
645  if(opt[len] == '=' && !op->uses_option)
646  errexit(1, "*** %s: --%s: %s\n", _argv0, op->long_option, errmsg(shell::INVARGUMENT));
647  if(opt[len] == '=') {
648  value = opt + len + 1;
649  break;
650  }
651  if(opt[len] == 0) {
652  if(op->uses_option)
653  value = argv[argp++];
654  break;
655  }
656  }
657  op.next();
658  }
659 
660  // if we have long option, try to assign it...
661  if(is(op)) {
662  if(op->uses_option && value == NULL)
663  errexit(1, "*** %s: --%s: %s\n", _argv0, op->long_option, errmsg(shell::NOARGUMENT));
664  err = op->assign(value);
665  if(err)
666  errexit(1, "*** %s: --%s: %s\n", _argv0, op->long_option, shell::text(err));
667  continue;
668  }
669 
670  // if unknown long option was used...
671  if(eq(arg, "--", 2)) {
672  char *cp = strchr(arg, '=');
673  if(cp)
674  *cp = 0;
675  errexit(1, "*** %s: %s: %s\n", _argv0, arg, errmsg(shell::BADOPTION));
676  }
677 
678  // short form -xyz flags parsing...
679 
680  while(*(++arg) != 0) {
681  value = NULL;
682 
683  op = Option::first();
684  while(is(op)) {
685  if(op->short_option == *arg)
686  break;
687  op.next();
688  }
689 
690  if(!is(op))
691  errexit(1, "*** %s: -%c: %s\n", _argv0, *arg, errmsg(shell::BADOPTION));
692 
693  value = NULL;
694  if(op->trigger_option)
695  goto trigger;
696 
697  if(op->uses_option && arg[1] == 0)
698  value = argv[argp++];
699  else if(op->uses_option)
700  value = ++arg;
701 
702  if(op->uses_option && value == NULL)
703  errexit(1, "*** %s: -%c: %s\n", _argv0, op->short_option, errmsg(shell::NOARGUMENT));
704 trigger:
705  err = op->assign(value);
706  if(err)
707  errexit(1, "*** %s: -%c: %s\n", _argv0, op->short_option, shell::text(err));
708  if(value)
709  break;
710  }
711  }
712  _argv = &argv[argp];
713 
714  _argc = 0;
715  argv = _argv;
716  while(argv[_argc])
717  ++_argc;
718 
719 #if defined(_MSWINDOWS_) && defined(_MSC_VER)
720  const char *fn;
721  char dirname[128];
722  WIN32_FIND_DATA entry;
723  args *argitem;
724  fd_t dir;
725  OrderedIndex arglist;
726  _argc = 0;
727 
728  while(_argv != NULL && *_argv != NULL) {
729  fn = strrchr(*_argv, '/');
730  arg = *_argv;
731  if(!fn)
732  fn = strrchr(*_argv, '\\');
733  if(!fn && arg[1] == ':')
734  fn = strrchr(*_argv, ':');
735  if(fn)
736  ++fn;
737  else
738  fn = *_argv;
739  if(!*fn)
740  goto skip;
741  // url type things do not get expanded...
742  if(strchr(fn, ':'))
743  goto skip;
744  if(*fn != '*' && fn[strlen(fn) - 1] != '*' && !strchr(fn, '?'))
745  goto skip;
746  if(eq(fn, "*"))
747  fn = "*.*";
748  len = fn - *_argv;
749  if(len >= sizeof(dirname))
750  len = sizeof(dirname) - 1;
751  if(len == 0)
752  dirname[0] = 0;
753  else
754  String::set(dirname, ++len, *_argv);
755  len = strlen(dirname);
756  if(len)
757  String::set(dirname + len, sizeof(dirname) - len, fn);
758  else
759  String::set(dirname, sizeof(dirname), fn);
760  dir = FindFirstFile(dirname, &entry);
762  goto skip;
763  do {
764  if(len)
765  String::set(dirname + len, sizeof(dirname) - len, fn);
766  else
767  String::set(dirname, sizeof(dirname), fn);
768  argitem = init<args>((args *)mempager::_alloc(sizeof(args)));
769  argitem->item = mempager::dup(dirname);
770  argitem->enlist(&arglist);
771  ++_argc;
772  } while(FindNextFile(dir, &entry));
773  CloseHandle(dir);
774  ++*_argv;
775  continue;
776 skip:
777  argitem = init<args>((args *)mempager::_alloc(sizeof(args)));
778  argitem->item = *(_argv++);
779  argitem->enlist(&arglist);
780  ++_argc;
781  }
782  collapse(arglist.begin());
783 #endif
784  return _argv;
785 }
786 
787 void shell::errlog(const char *format, ...)
788 {
789  va_list args;
790  char buf[256];
791 
792  String::set(buf, sizeof(buf) - 1, format);
793  size_t len = strlen(buf);
794 
795  if(buf[len - 1] != '\n') {
796  buf[len] = '\n';
797  buf[len + 1] = 0;
798  }
799  else
800  --len;
801 
802  format = buf;
803 
804  va_start(args, format);
805  if(!eq("*** ", format, 4))
806  fputs("*** ", stderr);
807  vfprintf(stderr, format, args);
808  fflush(stderr);
809 
810  buf[len] = 0;
811 
812 #ifdef HAVE_SYSLOG_H
813  if(errname && errmode != NONE && (ERR <= errlevel)) {
814  if(eq("*** ", format, 4)) {
815  format += 4;
816  const char *cp = format;
817  while(isalnum(*cp) || *cp == '-' || *cp == '.')
818  ++cp;
819  if(*cp == ':' && cp[1] == ' ')
820  format = cp + 2;
821  }
822  vsyslog(LOG_ERR, format, args);
823  }
824 #endif
825  va_end(args);
826 }
827 
828 void shell::errexit(int exitcode, const char *format, ...)
829 {
830  if(!exitcode)
831  return;
832 
833  va_list args;
834  char buf[256];
835 
836  String::set(buf, sizeof(buf) - 1, format);
837  size_t len = strlen(buf);
838 
839  if(buf[len - 1] != '\n') {
840  buf[len] = '\n';
841  buf[len + 1] = 0;
842  }
843  else
844  --len;
845 
846  format = buf;
847 
848  va_start(args, format);
849  if(!eq("*** ", format, 4))
850  fputs("*** ", stderr);
851  vfprintf(stderr, format, args);
852  fflush(stderr);
853 
854  buf[len] = 0;
855 
856 #ifdef HAVE_SYSLOG_H
857  if(errname && errmode != NONE && (FAIL <= errlevel)) {
858  if(eq("*** ", format, 4)) {
859  format += 4;
860  const char *cp = format;
861  while(isalnum(*cp) || *cp == '-' || *cp == '.')
862  ++cp;
863  if(*cp == ':' && cp[1] == ' ')
864  format = cp + 2;
865  }
866  vsyslog(LOG_CRIT, format, args);
867  }
868 #endif
869 
870  va_end(args);
871  ::exit(exitcode);
872 }
873 
874 size_t shell::printf(const char *format, ...)
875 {
876  va_list args;
877  va_start(args, format);
878  size_t result = vprintf(format, args);
879  va_end(args);
880  if(result == (size_t)EOF)
881  result = 0;
882  fflush(stdout);
883  return result;
884 }
885 
886 #ifdef _MSWINDOWS_
887 
888 static void pathfinder(const char *name, char *buf, size_t size)
889 {
890  char path[512];
891  char *tokbuf = NULL;
892  char *element;
893  char *ext;
894 
895  String::set(buf, size, name);
896 
897  if(!GetEnvironmentVariable("PATH", path, sizeof(path)))
898  goto tail;
899 
900  if(strchr(name, '/') || strchr(name, '\\') || strchr(name, ':'))
901  goto tail;
902 
903  while(NULL != (element = String::token(path, &tokbuf, ";"))) {
904  snprintf(buf, sizeof(buf), "%s\\%s", element, name);
905  ext = strrchr(buf, '.');
906  if(!ext || (!eq_case(ext, ".exe") && !eq_case(ext, ".com")))
907  String::add(buf, size, ".exe");
908  if(fsys::is_file(buf))
909  return;
910  }
911 
912  String::set(buf, size, name);
913 
914 tail:
915  ext = strrchr(buf, '.');
916  if(!ext || (!eq_case(ext, ".exe") && !eq_case(ext, ".com")))
917  String::add(buf, size, ".exe");
918 }
919 
920 void shell::relocate(const char *argv0)
921 {
922 }
923 
924 String shell::userid(void)
925 {
926  char buf[128];
927  DWORD size = sizeof(buf);
928 
929  String::set(buf, sizeof(buf), "nobody");
930  GetUserName(buf, &size);
931  return str(buf);
932 }
933 
934 String shell::path(path_t id)
935 {
936  char buf[512];
937 
938  string_t result = "";
939 
940  if(!_domain)
941  return result;
942 
943  switch(id) {
944  case SERVICE_CONTROL:
945  result = str("~\\SOFTWARE\\Services\\Control");
946  break;
947  case PROGRAM_CONFIG:
948  result = str("~\\Software\\Applications\\") + _domain;
949  break;
950  case SERVICE_CONFIG:
951  result = str("-\\SOFTWARE\\Services\\") + _domain;
952  break;
953  case USER_DEFAULTS:
954  if(GetEnvironmentVariable("SystemRoot", buf, sizeof(buf)))
955  result = str(buf) + "\\" + _domain + ".ini";
956  break;
957  case USER_HOME:
958  if(GetEnvironmentVariable("USERPROFILE", buf, sizeof(buf)))
959  result = str(buf);
960  break;
961  case SERVICE_DATA:
962  case USER_DATA:
963  if(GetEnvironmentVariable("APPDATA", buf, sizeof(buf))) {
964  result = str(buf) + "\\" + _domain;
966  }
967  break;
968  case USER_CONFIG:
969  if(GetEnvironmentVariable("USERPROFILE", buf, sizeof(buf))) {
970  result = str(buf) + "\\Local Settings\\" + _domain;
972  }
973  break;
974  case USER_CACHE:
975  case SERVICE_CACHE:
976  if(GetEnvironmentVariable("TEMP", buf, sizeof(buf))) {
977  result = str(buf) + "\\" + _domain;
979  break;
980  }
981  if(GetEnvironmentVariable("APPDATA", buf, sizeof(buf))) {
982  result = str(buf) + "\\" + _domain;
984  }
985  break;
986  case SYSTEM_TEMP:
987  dir::create("c:\\temp", fsys::DIR_TEMPORARY);
988  result ^= "c:\\temp";
989  break;
990  case PROGRAM_TEMP:
991  snprintf(buf, sizeof(buf), "$$%ld$$.tmp", (long)GetCurrentProcessId());
992  result = str("c:\\temp\\") + str(buf);
993  break;
994  case SYSTEM_ETC:
995  if(GetEnvironmentVariable("SystemRoot", buf, sizeof(buf)))
996  result = str(buf) + "\\etc";
997  break;
998  case SYSTEM_CFG:
999  result = path(SYSTEM_PREFIX, UCOMMON_CFGPATH);
1000  break;
1001  case SYSTEM_VAR:
1002  result = path(SYSTEM_PREFIX, UCOMMON_VARPATH);
1003  break;
1004  case SYSTEM_PREFIX:
1005  result ^= UCOMMON_PREFIX;
1006  break;
1007  case SYSTEM_SHARE:
1008  result ^= UCOMMON_PREFIX;
1009  break;
1010  case PROGRAM_PLUGINS:
1011  result = str(UCOMMON_PREFIX) + "\\plugins\\" + _domain;
1012  break;
1013  }
1014 
1015  return result;
1016 }
1017 
1018 const char *shell::getenv(const char *id, const char *value)
1019 {
1020  char buf[512];
1021  char path[255];
1022  const char *keyid = NULL;
1023 
1024  if(GetEnvironmentVariable(id, buf, sizeof(buf)))
1025  return dup(buf);
1026 
1027  if(errname)
1028  keyid = errname;
1029  else if(_domain)
1030  keyid = _domain;
1031  else if(_argv0)
1032  keyid = _argv0;
1033 
1034  if(keyid) {
1035  snprintf(path, sizeof(path), "Default Environment\\%s", keyid);
1036  HKEY key;
1037  if(RegOpenKey(HKEY_CLASSES_ROOT, path, &key) == ERROR_SUCCESS) {
1038  LONG dlen = sizeof(buf);
1039  buf[0] = 0;
1040  RegQueryValueA(key, id, (LPTSTR)buf, &dlen);
1041  RegCloseKey(key);
1042  if(buf[0])
1043  return dup(buf);
1044  }
1045  }
1046 
1047  return value;
1048 }
1049 
1050 int shell::system(const char *cmd, const char **envp)
1051 {
1052  char cmdspec[128];
1053  PROCESS_INFORMATION pi;
1054  char *ep = NULL;
1055  size_t len = 0;
1056 
1057  if(envp)
1058  ep = new char[4096];
1059 
1060  while(envp && *envp && len < 4090) {
1061  String::set(ep + len, 4094 - len, *envp);
1062  len += strlen(*(envp++)) + 1;
1063  }
1064 
1065  if(ep)
1066  ep[len] = 0;
1067 
1068  if(!GetEnvironmentVariable("SHELL", cmdspec, sizeof(cmdspec)))
1069  GetEnvironmentVariable("ComSpec", cmdspec, sizeof(cmdspec));
1070 
1071  if(!CreateProcess((CHAR *)cmdspec, (CHAR *)cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, ep, NULL, NULL, &pi)) {
1072  if(ep)
1073  delete[] ep;
1074  return -1;
1075  }
1076  if(ep)
1077  delete[] ep;
1078 
1079  CloseHandle(pi.hThread);
1080  int status = wait(pi.hProcess);
1081  return status;
1082 }
1083 
1084 int shell::wait(shell::pid_t pid)
1085 {
1086  DWORD code;
1087 
1088  if(WaitForSingleObject(pid, INFINITE) == WAIT_FAILED) {
1089  return -1;
1090  }
1091 
1092  GetExitCodeProcess(pid, &code);
1093  CloseHandle(pid);
1094  return (int)code;
1095 }
1096 
1097 shell::pid_t shell::spawn(const char *path, char **argv, char **envp, fd_t *stdio)
1098 {
1099  STARTUPINFO si;
1100  PROCESS_INFORMATION pi;
1101  char filename[128];
1102  int pos;
1103  pid_t pid = INVALID_PID_VALUE;
1104  fd_t stdfd;
1105  fd_t dups[3] =
1107 
1108  char *ep = NULL;
1109  size_t len = 0;
1110 
1111  memset(&si, 0, sizeof(STARTUPINFO));
1112  si.cb = sizeof(STARTUPINFO);
1113 
1114  if(envp)
1115  ep = new char[4096];
1116 
1117  while(envp && *envp && len < 4090) {
1118  String::set(ep + len, 4094 - len, *envp);
1119  len += strlen(*(envp++)) + 1;
1120  }
1121 
1122  if(ep)
1123  ep[len] = 0;
1124 
1125  pathfinder(path, filename, sizeof(filename));
1126  char *args = new char[32768];
1127 
1128  args[0] = 0;
1129  unsigned argc = 0;
1130  while(argv && argv[argc]) {
1131  if(!argc)
1132  String::add(args, 32768, " ");
1133  String::add(args, 32768, argv[argc++]);
1134  }
1135 
1136  if(stdio) {
1137  for(pos = 0; pos < 3; ++pos) {
1138  stdfd = INVALID_HANDLE_VALUE;
1139  switch(pos) {
1140  case 0:
1141  if(stdio[pos] == INVALID_HANDLE_VALUE)
1142  stdfd = GetStdHandle(STD_INPUT_HANDLE);
1143  break;
1144  case 1:
1145  if(stdio[pos] == INVALID_HANDLE_VALUE)
1146  stdfd = GetStdHandle(STD_OUTPUT_HANDLE);
1147  break;
1148  case 2:
1149  if(stdio[pos] == INVALID_HANDLE_VALUE)
1150  stdfd = GetStdHandle(STD_ERROR_HANDLE);
1151  break;
1152  }
1153  if(stdfd != INVALID_HANDLE_VALUE) {
1154  DuplicateHandle(GetCurrentProcess(), stdfd,
1155  GetCurrentProcess(), &dups[pos], 0,
1156  TRUE, DUPLICATE_SAME_ACCESS);
1157  stdfd = dups[pos];
1158  }
1159  else
1160  stdfd = stdio[pos];
1161  switch(pos) {
1162  case 0:
1163  si.hStdInput = stdfd;
1164  break;
1165  case 1:
1166  si.hStdOutput = stdfd;
1167  break;
1168  case 2:
1169  si.hStdError = stdfd;
1170  break;
1171  }
1172  }
1173  si.dwFlags = STARTF_USESTDHANDLES;
1174  }
1175 
1176  if(!CreateProcess((CHAR *)filename, (CHAR *)args, NULL, NULL, TRUE, 0, ep, NULL, &si, &pi))
1177  goto exit;
1178 
1179  pid = pi.hProcess;
1180  CloseHandle(pi.hThread);
1181 
1182 exit:
1183  if(ep)
1184  delete[] ep;
1185  delete[] args;
1186  for(pos = 0; pos < 3; ++pos) {
1187  if(dups[pos] != INVALID_HANDLE_VALUE)
1188  CloseHandle(dups[pos]);
1189  }
1190  return pid;
1191 }
1192 
1193 static void exit_handler(void)
1194 {
1195  if(_exitproc) {
1196  (*_exitproc)();
1197  _exitproc = NULL;
1198  }
1199 }
1200 
1201 static BOOL WINAPI _stop(DWORD code)
1202 {
1203  exit_handler();
1204  return true;
1205 }
1206 
1207 void shell::exiting(exitproc_t handler)
1208 {
1209  if(!_exitproc && handler) {
1210  _exitproc = handler;
1211  if(_domain)
1212  SetConsoleTitle(_domain);
1213  SetConsoleCtrlHandler((PHANDLER_ROUTINE)_stop, TRUE);
1214  atexit(exit_handler);
1215  }
1216  else
1217  _exitproc = handler;
1218 }
1219 
1220 void shell::release(int exit_code)
1221 {
1222 }
1223 
1224 void shell::detach(mainproc_t entry)
1225 {
1226  const char *name = _argv0;
1227 
1228  if(_domain)
1229  name = _domain;
1230 
1231  // detach only called once, keeps persistent name...
1232 
1233  if(entry == NULL)
1234  return;
1235 
1236  name = ::strdup(name);
1237 
1238  SERVICE_TABLE_ENTRY servicetable[] = {
1239  {(LPSTR)name, (LPSERVICE_MAIN_FUNCTION)entry},
1240  {NULL, NULL}
1241  };
1242 
1243  if(!StartServiceCtrlDispatcher(servicetable))
1244  errexit(1, "*** %s: %s\n", name, _TEXT("failed service start"));
1245 }
1246 
1247 void shell::restart(void)
1248 {
1249 }
1250 
1251 int shell::detach(const char *path, char **argv, char **envp, fd_t *stdio)
1252 {
1253  STARTUPINFO si;
1254  PROCESS_INFORMATION pi;
1255  char filename[128];
1256  int err;
1257  int pos;
1258  pid_t pid = INVALID_PID_VALUE;
1259  fd_t stdfd;
1260  fd_t dups[3] =
1262 
1263  char *ep = NULL;
1264  size_t len = 0;
1265 
1266  memset(&si, 0, sizeof(STARTUPINFO));
1267  si.cb = sizeof(STARTUPINFO);
1268 
1269  if(envp)
1270  ep = new char[4096];
1271 
1272  while(envp && *envp && len < 4090) {
1273  String::set(ep + len, 4094 - len, *envp);
1274  len += strlen(*(envp++)) + 1;
1275  }
1276 
1277  if(ep)
1278  ep[len] = 0;
1279 
1280  pathfinder(path, filename, sizeof(filename));
1281  char *args = new char[32768];
1282 
1283  args[0] = 0;
1284  unsigned argc = 0;
1285  while(argv && argv[argc]) {
1286  if(!argc)
1287  String::add(args, 32768, " ");
1288  String::add(args, 32768, argv[argc++]);
1289  }
1290 
1291  if(stdio) {
1292  for(pos = 0; pos < 3; ++pos) {
1293  stdfd = INVALID_HANDLE_VALUE;
1294  switch(pos) {
1295  case 0:
1296  if(stdio[pos] == INVALID_HANDLE_VALUE)
1297  stdfd = GetStdHandle(STD_INPUT_HANDLE);
1298  break;
1299  case 1:
1300  if(stdio[pos] == INVALID_HANDLE_VALUE)
1301  stdfd = GetStdHandle(STD_OUTPUT_HANDLE);
1302  break;
1303  case 2:
1304  if(stdio[pos] == INVALID_HANDLE_VALUE)
1305  stdfd = GetStdHandle(STD_ERROR_HANDLE);
1306  break;
1307  }
1308  if(stdfd != INVALID_HANDLE_VALUE) {
1309  DuplicateHandle(GetCurrentProcess(), stdfd,
1310  GetCurrentProcess(), &dups[pos], 0,
1311  TRUE, DUPLICATE_SAME_ACCESS);
1312  stdfd = dups[pos];
1313  }
1314  else
1315  stdfd = stdio[pos];
1316  switch(pos) {
1317  case 0:
1318  si.hStdInput = stdfd;
1319  break;
1320  case 1:
1321  si.hStdOutput = stdfd;
1322  break;
1323  case 2:
1324  si.hStdError = stdfd;
1325  break;
1326  }
1327  }
1328  si.dwFlags = STARTF_USESTDHANDLES;
1329  }
1330 
1331  if(!CreateProcess((CHAR *)filename, (CHAR *)args, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, ep, NULL, &si, &pi)) {
1332  err = fsys::remapError();
1333  goto exit;
1334  }
1335 
1336  pid = pi.hProcess;
1337  CloseHandle(pi.hThread);
1338  err = 0;
1339 
1340 exit:
1341  if(ep)
1342  delete[] ep;
1343  delete[] args;
1344  for(pos = 0; pos < 3; ++pos) {
1345  if(dups[pos] != INVALID_HANDLE_VALUE)
1346  CloseHandle(dups[pos]);
1347  }
1348  if(pid == INVALID_PID_VALUE)
1349  return err;
1350 
1351  return 0;
1352 }
1353 
1354 char *shell::getpass(const char *prompt, char *buffer, size_t size)
1355 {
1356  size_t pos = 0;
1357  fputs(prompt, stderr);
1358 
1359  while(pos < size - 1) {
1360  buffer[pos] = (char)getch();
1361  if(buffer[pos] == '\r' || buffer[pos] == '\n')
1362  break;
1363  else if(buffer[pos] == '\b' && pos)
1364  --pos;
1365  else
1366  ++pos;
1367  }
1368  buffer[pos] = 0;
1369  return buffer;
1370 }
1371 
1372 int shell::inkey(const char *prompt)
1373 {
1374  if(prompt && fsys::is_tty(shell::input()))
1375  fputs(prompt, stdout);
1376  else
1377  return 0;
1378 
1379  return (char)getch();
1380 }
1381 
1382 int shell::cancel(shell::pid_t pid)
1383 {
1384  if(!TerminateProcess(pid, 255))
1385  return -1;
1386  return 0;
1387 }
1388 
1389 char *shell::getline(const char *prompt, char *buffer, size_t size)
1390 {
1391  unsigned pos = 0;
1392 
1393  if(!fsys::is_tty(shell::input()))
1394  return fgets(buffer, (socksize_t)size, stdin);
1395 
1396  fputs(prompt, stdout);
1397 
1398  while(pos < size - 1) {
1399  buffer[pos] = (char)getch();
1400  if(buffer[pos] == '\r' || buffer[pos] == '\n')
1401  break;
1402  else if(buffer[pos] == '\b' && pos) {
1403  fputs("\b \b", stdout);
1404  --pos;
1405  }
1406  else {
1407  fputc(buffer[pos], stdout);
1408  ++pos;
1409  }
1410  fflush(stdout);
1411  }
1412  printf("\n");
1413  buffer[pos] = 0;
1414  return buffer;
1415 }
1416 
1417 #else
1418 
1419 static const char *system_prefix = UCOMMON_PREFIX;
1420 
1421 #if defined(HAVE_TERMIOS_H)
1422 static struct termios io_prior, io_current;
1423 #elif defined(HAVE_TERMIO_H)
1424 static struct termio io_prior, io_current;
1425 #endif
1426 
1427 static void noecho(int fd)
1428 {
1429 #if defined(HAVE_TERMIOS_H)
1430  tcgetattr(fd, &io_prior);
1431  tcgetattr(fd, &io_current);
1432  io_current.c_lflag &= ~ECHO;
1433  tcsetattr(fd, TCSAFLUSH, &io_current);
1434 #elif defined(HAVE_TERMIO_H)
1435  ioctl(fd, TCGETA, &io_prior);
1436  ioctl(fd, TCGETA, &io_current);
1437  io_current.c_lflag &= ~ECHO;
1438  ioctl(fd, TCSETA, &io_current);
1439 #endif
1440 }
1441 
1442 static void echo(int fd)
1443 {
1444 #if defined(HAVE_TERMIOS_H)
1445  tcsetattr(fd, TCSAFLUSH, &io_prior);
1446 #elif defined(HAVE_TERMIO_H)
1447  ioctl(fd, TCSETA, &io_prior);
1448 #endif
1449 }
1450 
1451 char *shell::getline(const char *prompt, char *buffer, size_t size)
1452 {
1453  size_t pos = 0;
1454 
1455  if(!fsys::is_tty(input()))
1456  return fgets(buffer, size, stdin);
1457 
1458  noecho(1);
1459  fputs(prompt, stdout);
1460 
1461  while(pos < size - 1) {
1462  buffer[pos] = getc(stdin);
1463  if(buffer[pos] == '\r' || buffer[pos] == '\n')
1464  break;
1465  else if(buffer[pos] == '\b' && pos) {
1466  fputs("\b \b", stdout);
1467  --pos;
1468  }
1469  else {
1470  fputc(buffer[pos], stdout);
1471  ++pos;
1472  }
1473  fflush(stdout);
1474  }
1475  printf("\n");
1476  buffer[pos] = 0;
1477  echo(1);
1478  return buffer;
1479 }
1480 
1481 
1482 
1483 char *shell::getpass(const char *prompt, char *buffer, size_t size)
1484 {
1485  size_t count;
1486  int fd = ::open("/dev/tty", O_RDONLY);
1487  if(-1 == fd)
1488  fd = 1;
1489 
1490  noecho(fd);
1491  fputs(prompt, stderr);
1492  count = ::read(fd, buffer, size);
1493  if(count)
1494  --count;
1495  buffer[count] = 0;
1496 
1497 #if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
1498  fputs("\n", stderr);
1499 #endif
1500  echo(fd);
1501  if(fd != 1)
1502  ::close(fd);
1503  return buffer;
1504 }
1505 
1506 int shell::inkey(const char *prompt)
1507 {
1508  if(!fsys::is_tty(1))
1509  return 0;
1510 
1511  noecho(1);
1512  if(prompt)
1513  fputs(prompt, stdout);
1514  int ch = getc(stdin);
1515  echo(1);
1516 
1517  return ch;
1518 }
1519 
1520 void shell::relocate(const char *argv0)
1521 {
1522 #ifdef HAVE_REALPATH
1523  char *path0 = realpath(argv0, NULL);
1524  if(!path0)
1525  return;
1526 
1527  // strip out exe name...
1528  char *cp = strrchr(path0, '/');
1529  if(cp) {
1530  *cp = 0;
1531  // strip out bin subdir...
1532  cp = strrchr(path0, '/');
1533  if(cp && (eq(cp, "/bin") || eq(cp, "/sbin"))) {
1534  *cp = 0;
1535  system_prefix = path0;
1536  }
1537  }
1538 #endif
1539 }
1540 
1542 {
1543  const char *id = ::getenv("LOGNAME");
1544 
1545  if(!id)
1546  id = "nobody";
1547 
1548  return str(id);
1549 }
1550 
1552 {
1553  string_t result = "";
1554  const char *home = NULL;
1555  char buf[65];
1556 
1557  if(!_domain)
1558  return result;
1559 
1560  switch(id) {
1561  case USER_DEFAULTS:
1562  home = ::getenv("HOME");
1563  if(!home)
1564  break;
1565  result = str(home) + "/." + _domain + "rc";
1566  break;
1567  case USER_HOME:
1568  home = ::getenv("HOME");
1569  if(!home)
1570  break;
1571  result = str(home);
1572  break;
1573  case SERVICE_DATA:
1574  result = path(SYSTEM_PREFIX, UCOMMON_VARPATH "/lib/") + _domain;
1575  break;
1576  case USER_DATA:
1577  home = ::getenv("HOME");
1578  if(!home)
1579  break;
1580 #ifdef __APPLE__
1581  result = str(home) + "/Library/Application Support/" + _domain;
1582 #else
1583  result = str(home) + "/.local/share/" + _domain;
1584 #endif
1585  break;
1586  case USER_CONFIG:
1587  home = ::getenv("HOME");
1588  if(!home)
1589  break;
1590 #ifdef __APPLE__
1591  result = str(home) + "/Library/Preferences/" + _domain;
1592 #else
1593  result = str(home) + "/.config/" + _domain;
1594 #endif
1596  break;
1597  case USER_CACHE:
1598  home = ::getenv("HOME");
1599  if(!home)
1600  break;
1601 #ifdef __APPLE__
1602  result = str(home) + "/Library/Caches/" + _domain;
1603 #else
1604  result = str(home) + "/.cache/" + _domain;
1605 #endif
1606  break;
1607  case SERVICE_CACHE:
1608  result = path(SYSTEM_PREFIX, UCOMMON_VARPATH "/cache/") + _domain;
1609  break;
1610  case SERVICE_CONTROL:
1611 #ifdef __APPLE__
1612  result = str(home) + "/Library/Caches";
1613 #else
1614  result = str(home) + "/.cache";
1615 #endif
1616  break;
1617  case PROGRAM_CONFIG:
1618  home = ::getenv("HOME");
1619  if(!home)
1620  break;
1621 #ifdef __APPLE__
1622  result = str(home) + "/Library/Preferences/" + _domain;
1623 #else
1624  result = str(home) + "/.config/" + _domain;
1625 #endif
1627 
1628 #ifdef __APPLE__
1629  result = result + "/" + _domain + ".conf";
1630 #else
1631  result = result + "/" + _domain + "rc";
1632 #endif
1633  break;
1634  case SERVICE_CONFIG:
1635  result = path(SYSTEM_PREFIX, UCOMMON_CFGPATH "/") + _domain + ".conf";
1636  break;
1637  case SYSTEM_TEMP:
1638  result ^= "/tmp";
1639  break;
1640  case PROGRAM_TEMP:
1641  snprintf(buf, sizeof(buf), ".$$%ld$$.tmp", (long)getpid());
1642  result = str("/tmp/") + str(buf);
1643  break;
1644  case SYSTEM_ETC:
1645  case SYSTEM_CFG:
1646  result = path(SYSTEM_PREFIX, UCOMMON_CFGPATH);
1647  break;
1648  case SYSTEM_VAR:
1649  result = path(SYSTEM_PREFIX, UCOMMON_VARPATH);
1650  break;
1651  case SYSTEM_PREFIX:
1652  result ^= system_prefix;
1653  break;
1654  case SYSTEM_SHARE:
1655  result = str(system_prefix) + "/share";
1656  break;
1657  case PROGRAM_PLUGINS:
1658  result = str(system_prefix) + "/lib/" + _domain;
1659  break;
1660  }
1661 
1662  return result;
1663 }
1664 
1665 const char *shell::getenv(const char *id, const char *value)
1666 {
1667  const char *v = ::getenv(id);
1668  if(v)
1669  return dup(v);
1670 
1671  return value;
1672 }
1673 
1674 int shell::system(const char *cmd, const char **envp)
1675 {
1676  assert(cmd != NULL);
1677 
1678  char symname[129];
1679  const char *cp;
1680  char *ep;
1681  int status;
1682  int max = sizeof(fd_set) * 8;
1683 
1684 #ifdef RLIMIT_NOFILE
1685  struct rlimit rlim;
1686 
1687  if(!getrlimit(RLIMIT_NOFILE, &rlim))
1688  max = rlim.rlim_max;
1689 #endif
1690 
1691  pid_t pid = fork();
1692  if(pid < 0)
1693  return -1;
1694 
1695  if(pid > 0) {
1696  if(::waitpid(pid, &status, 0) != pid)
1697  status = -1;
1698  return status;
1699  }
1700 
1701  for(int fd = 3; fd < max; ++fd)
1702  ::close(fd);
1703 
1704  while(envp && *envp) {
1705  String::set(symname, sizeof(symname), *envp);
1706  ep = strchr(symname, '=');
1707  if(ep)
1708  *ep = 0;
1709  cp = strchr(*envp, '=');
1710  if(cp) {
1711  ++cp;
1712  ::setenv(symname, cp, 1);
1713  }
1714  ++envp;
1715  }
1716 
1717  ::signal(SIGHUP, SIG_DFL);
1718  ::signal(SIGABRT, SIG_DFL);
1719  ::signal(SIGQUIT, SIG_DFL);
1720  ::signal(SIGINT, SIG_DFL);
1721  ::signal(SIGCHLD, SIG_DFL);
1722  ::signal(SIGPIPE, SIG_DFL);
1723  ::signal(SIGUSR1, SIG_DFL);
1724  ::execlp("/bin/sh", "sh", "-c", cmd, NULL);
1725  ::exit(-1);
1726 }
1727 
1728 void shell::restart(void)
1729 {
1730  pid_t pid;
1731  int status;
1732 
1733 restart:
1734  pid = fork();
1735  if(pid > 0) {
1736  waitpid(pid, &status, 0);
1737  if(WIFSIGNALED(status))
1738  status = WTERMSIG(status);
1739  else
1740  status = WIFEXITED(status);
1741  switch(status) {
1742 #ifdef SIGPWR
1743  case SIGPWR:
1744 #endif
1745  case SIGINT:
1746  case SIGQUIT:
1747  case SIGTERM:
1748  case 0:
1749  exit(status);
1750  default:
1751  goto restart;
1752  }
1753  }
1754 }
1755 
1756 static void exit_handler(void)
1757 {
1758  if(_exitproc) {
1759  (*_exitproc)();
1760  _exitproc = NULL;
1761  }
1762 }
1763 
1764 extern "C" {
1765  static void abort_handler(int signo)
1766  {
1767  exit_handler();
1768  }
1769 }
1770 
1771 void shell::exiting(exitproc_t handler)
1772 {
1773 
1774  if(!_exitproc && handler) {
1775  _exitproc = handler;
1776  ::signal(SIGABRT, abort_handler);
1777 #ifdef HAVE_ATEXIT
1778  ::atexit(exit_handler);
1779 #endif
1780  }
1781  else
1782  _exitproc = handler;
1783 }
1784 
1786 {
1787  const char *dev = "/dev/null";
1788  pid_t pid;
1789  int fd;
1790 
1791  fflush(stdout);
1792  fflush(stderr);
1793 
1794  close(0);
1795  close(1);
1796  close(2);
1797 #ifdef SIGTTOU
1798  signal(SIGTTOU, SIG_IGN);
1799 #endif
1800 
1801 #ifdef SIGTTIN
1802  signal(SIGTTIN, SIG_IGN);
1803 #endif
1804 
1805 #ifdef SIGTSTP
1806  signal(SIGTSTP, SIG_IGN);
1807 #endif
1808  pid = fork();
1809  if(pid > 0)
1810  exit(exit_code);
1811  crit(pid == 0, "detach without process");
1812 
1813 #if defined(SIGTSTP) && defined(TIOCNOTTY)
1814  crit(setpgid(0, getpid()) == 0, "detach without process group");
1815  if((fd = open(_PATH_TTY, O_RDWR)) >= 0) {
1816  ioctl(fd, TIOCNOTTY, NULL);
1817  close(fd);
1818  }
1819 #else
1820 
1821 #ifdef HAVE_SETPGRP
1822  crit(setpgrp() == 0, "detach without process group");
1823 #else
1824  crit(setpgid(0, getpid()) == 0, "detach without process group");
1825 #endif
1826  signal(SIGHUP, SIG_IGN);
1827  pid = fork();
1828  if(pid > 0)
1829  exit(0);
1830  crit(pid == 0, "detach without process");
1831 #endif
1832  if(dev && *dev) {
1833  fd = open(dev, O_RDWR);
1834  //fixme: for later review...
1835  if(fd != 0)
1836  dup2(fd, 0);
1837  if(fd != 1)
1838  dup2(fd, 1);
1839  if(fd != 2)
1840  dup2(fd, 2);
1841  if(fd > 2)
1842  close(fd);
1843  }
1844 }
1845 
1847 {
1848  const char *dev = "/dev/null";
1849  pid_t pid;
1850  int fd;
1851 
1852  close(0);
1853  close(1);
1854  close(2);
1855 #ifdef SIGTTOU
1856  signal(SIGTTOU, SIG_IGN);
1857 #endif
1858 
1859 #ifdef SIGTTIN
1860  signal(SIGTTIN, SIG_IGN);
1861 #endif
1862 
1863 #ifdef SIGTSTP
1864  signal(SIGTSTP, SIG_IGN);
1865 #endif
1866  pid = fork();
1867  if(pid > 0)
1868  exit(0);
1869  crit(pid == 0, "detach without process");
1870 
1871 #if defined(SIGTSTP) && defined(TIOCNOTTY)
1872  crit(setpgid(0, getpid()) == 0, "detach without process group");
1873  if((fd = open(_PATH_TTY, O_RDWR)) >= 0) {
1874  ioctl(fd, TIOCNOTTY, NULL);
1875  close(fd);
1876  }
1877 #else
1878 
1879 #ifdef HAVE_SETPGRP
1880  crit(setpgrp() == 0, "detach without process group");
1881 #else
1882  crit(setpgid(0, getpid()) == 0, "detach without process group");
1883 #endif
1884  signal(SIGHUP, SIG_IGN);
1885  pid = fork();
1886  if(pid > 0)
1887  exit(0);
1888  crit(pid == 0, "detach without process");
1889 #endif
1890  if(dev && *dev) {
1891  fd = open(dev, O_RDWR);
1892  if(fd > 0)
1893  dup2(fd, 0);
1894  if(fd != 1)
1895  dup2(fd, 1);
1896  if(fd != 2)
1897  dup2(fd, 2);
1898  if(fd > 2)
1899  close(fd);
1900  }
1901 }
1902 
1903 int shell::detach(const char *path, char **argv, char **envp, fd_t *stdio)
1904 {
1905  char symname[129];
1906  const char *cp;
1907  char *ep;
1908  fd_t fd;
1909 
1910  int max = sizeof(fd_set) * 8;
1911 #ifdef RLIMIT_NOFILE
1912  struct rlimit rlim;
1913 
1914  if(!getrlimit(RLIMIT_NOFILE, &rlim))
1915  max = rlim.rlim_max;
1916 #endif
1917 
1918  pid_t pid = fork();
1919  if(pid < 0)
1920  return errno;
1921 
1922  if(pid > 0)
1923  return 0;
1924 
1925  ::signal(SIGQUIT, SIG_DFL);
1926  ::signal(SIGINT, SIG_DFL);
1927  ::signal(SIGCHLD, SIG_DFL);
1928  ::signal(SIGPIPE, SIG_DFL);
1929  ::signal(SIGHUP, SIG_DFL);
1930  ::signal(SIGABRT, SIG_DFL);
1931  ::signal(SIGUSR1, SIG_DFL);
1932 
1933 #ifdef SIGTTOU
1934  ::signal(SIGTTOU, SIG_IGN);
1935 #endif
1936 
1937 #ifdef SIGTTIN
1938  ::signal(SIGTTIN, SIG_IGN);
1939 #endif
1940 
1941 #ifdef SIGTSTP
1942  ::signal(SIGTSTP, SIG_IGN);
1943 #endif
1944 
1945  for(fd = 0; fd < 3; ++fd) {
1946  if(stdio && stdio[fd] != INVALID_HANDLE_VALUE)
1947  ::dup2(stdio[fd], fd);
1948  else
1949  ::close(fd);
1950  }
1951 
1952  for(fd = 3; fd < max; ++fd)
1953  ::close(fd);
1954 
1955 #if defined(SIGTSTP) && defined(TIOCNOTTY)
1956  if(setpgid(0, getpid()) == -1)
1957  ::exit(-1);
1958 
1959  if((fd = open("/dev/tty", O_RDWR)) >= 0) {
1960  ::ioctl(fd, TIOCNOTTY, NULL);
1961  ::close(fd);
1962  }
1963 #else
1964 
1965 #ifdef HAVE_SETPGRP
1966  if(setpgrp() == -1)
1967  ::exit(-1);
1968 #else
1969  if(setpgid(0, getpid()) == -1)
1970  ::exit(-1);
1971 #endif
1972 
1973  if(getppid() != 1) {
1974  if((pid = fork()) < 0)
1975  ::exit(-1);
1976  else if(pid > 0)
1977  ::exit(0);
1978  }
1979 #endif
1980 
1981  for(fd = 0; fd < 3; ++fd) {
1982  if(stdio && stdio[fd] != INVALID_HANDLE_VALUE)
1983  continue;
1984  fd_t tmp = ::open("/dev/null", O_RDWR);
1985  if(tmp != fd) {
1986  ::dup2(tmp, fd);
1987  ::close(tmp);
1988  }
1989  }
1990 
1991  while(envp && *envp) {
1992  String::set(symname, sizeof(symname), *envp);
1993  ep = strchr(symname, '=');
1994  if(ep)
1995  *ep = 0;
1996  cp = strchr(*envp, '=');
1997  if(cp) {
1998  ++cp;
1999  ::setenv(symname, cp, 1);
2000  }
2001  ++envp;
2002  }
2003 
2004  if(strchr(path, '/'))
2005  execv(path, argv);
2006  else
2007  execvp(path, argv);
2008  exit(-1);
2009 }
2010 
2011 
2012 shell::pid_t shell::spawn(const char *path, char **argv, char **envp, fd_t *stdio)
2013 {
2014  char symname[129];
2015  const char *cp;
2016  char *ep;
2017  int fd;
2018 
2019  int max = sizeof(fd_set) * 8;
2020 #ifdef RLIMIT_NOFILE
2021  struct rlimit rlim;
2022 
2023  if(!getrlimit(RLIMIT_NOFILE, &rlim))
2024  max = rlim.rlim_max;
2025 #endif
2026 
2027  pid_t pid = fork();
2028  if(pid < 0)
2029  return INVALID_PID_VALUE;
2030 
2031  if(pid > 0)
2032  return pid;
2033 
2034  ::signal(SIGQUIT, SIG_DFL);
2035  ::signal(SIGINT, SIG_DFL);
2036  ::signal(SIGCHLD, SIG_DFL);
2037  ::signal(SIGPIPE, SIG_DFL);
2038  ::signal(SIGHUP, SIG_DFL);
2039  ::signal(SIGABRT, SIG_DFL);
2040  ::signal(SIGUSR1, SIG_DFL);
2041 
2042  for(fd = 0; fd < 3; ++fd) {
2043  if(stdio && stdio[fd] != INVALID_HANDLE_VALUE)
2044  ::dup2(stdio[fd], fd);
2045  }
2046 
2047  for(fd = 3; fd < max; ++fd)
2048  ::close(fd);
2049 
2050  while(envp && *envp) {
2051  String::set(symname, sizeof(symname), *envp);
2052  ep = strchr(symname, '=');
2053  if(ep)
2054  *ep = 0;
2055  cp = strchr(*envp, '=');
2056  if(cp) {
2057  ++cp;
2058  ::setenv(symname, cp, 1);
2059  }
2060  ++envp;
2061  }
2062 
2063  if(strchr(path, '/'))
2064  execv(path, argv);
2065  else
2066  execvp(path, argv);
2067  exit(-1);
2068 }
2069 
2071 {
2072  int status = -1;
2073 
2074  if(pid == INVALID_PID_VALUE || ::waitpid(pid, &status, 0) != pid)
2075  return -1;
2076 
2077  if(status == -1)
2078  return -1;
2079 
2080  return WEXITSTATUS(status);
2081 }
2082 
2084 {
2085  if(kill(pid, SIGTERM))
2086  return -1;
2087  return wait(pid);
2088 }
2089 
2090 #endif
2091 
2092 const char *shell::texts(const char *singular, const char *plural, unsigned long value)
2093 {
2094 #ifdef HAVE_GETTEXT
2095  return ::ngettext(singular, plural, value);
2096 #else
2097  if(value > 1)
2098  return plural;
2099 
2100  return singular;
2101 #endif
2102 }
2103 
2104 const char *shell::text(const char *msg)
2105 {
2106 #ifdef HAVE_GETTEXT
2107  return ::gettext(msg);
2108 #else
2109  return msg;
2110 #endif
2111 }
2112 
2113 void shell::bind(const char *name)
2114 {
2115  string_t locale;
2116  const char *prior = _domain;
2117 
2118  _domain = name;
2119  locale = path(SYSTEM_SHARE) + "/locale";
2120 
2121  if(!prior) {
2122  setlocale(LC_ALL, "");
2123  bindtextdomain("ucommon", *locale);
2124  }
2125 
2126  bindtextdomain(name, *locale);
2127  textdomain(name);
2128 }
2129 
2130 void shell::rebind(const char *name)
2131 {
2132  if(name)
2133  textdomain(name);
2134  else
2136 }
2137 
2138 #ifdef _MSWINDOWS_
2139 void shell::priority(int level)
2140 {
2141 }
2142 #else
2143 void shell::priority(int level)
2144 {
2145 #if _POSIX_PRIORITY_SCHEDULING > 0
2146  int policy = SCHED_OTHER;
2147 
2148  if(level > 0)
2149  policy = SCHED_RR;
2150 
2151  struct sched_param sparam;
2152  int min = sched_get_priority_min(policy);
2153  int max = sched_get_priority_max(policy);
2154  int pri = (int)level;
2155 
2156  if(min == max)
2157  pri = min;
2158  else
2159  pri += min;
2160  if(pri > max)
2161  pri = max;
2162 
2163  setpriority(PRIO_PROCESS, 0, -level);
2164  memset(&sparam, 0, sizeof(sparam));
2165  sparam.sched_priority = pri;
2166  sched_setscheduler(0, policy, &sparam);
2167 #else
2168  nice(-level);
2169 #endif
2170 }
2171 #endif
2172 
2173 void shell::debug(unsigned level, const char *fmt, ...)
2174 {
2175  assert(fmt != NULL && *fmt != 0);
2176 
2177  char buf[256];
2178  va_list args;
2179 
2180  level += (unsigned)DEBUG0;
2181 
2182  if(!errname || level > (unsigned)errlevel)
2183  return;
2184 
2185  va_start(args, fmt);
2186  vsnprintf(buf, sizeof(buf), fmt, args);
2187  va_end(args);
2188 
2189  if(fmt[strlen(fmt) - 1] == '\n')
2190  fprintf(stderr, "%s: %s", errname, buf);
2191  else
2192  fprintf(stderr, "%s: %s\n", errname, buf);
2193 }
2194 
2195 #ifdef HAVE_SYSLOG_H
2196 
2197 #ifndef LOG_AUTHPRIV
2198 #define LOG_AUTHPRIV LOG_AUTH
2199 #endif
2200 
2201 void shell::log(const char *name, loglevel_t level, logmode_t mode, logproc_t handler)
2202 {
2203  errlevel = level;
2204  errmode = mode;
2205  errname = name;
2206 
2207  if(handler != (logproc_t)NULL)
2208  errproc = handler;
2209 
2210  switch(mode) {
2211  case NONE:
2212  closelog();
2213  return;
2214  case CONSOLE_LOG:
2215  ::openlog(name, LOG_CONS, LOG_DAEMON);
2216  return;
2217  case USER_LOG:
2218  ::openlog(name, 0, LOG_USER);
2219  return;
2220  case SYSTEM_LOG:
2221  ::openlog(name, LOG_CONS, LOG_DAEMON);
2222  return;
2223  case SECURITY_LOG:
2224  ::openlog(name, LOG_CONS, LOG_AUTHPRIV);
2225  return;
2226  }
2227 }
2228 
2229 void shell::security(loglevel_t loglevel, const char *fmt, ...)
2230 {
2231  assert(fmt != NULL && *fmt != 0);
2232 
2233  char buf[256];
2234  va_list args;
2235  int level= LOG_ERR;
2236 
2237  if(!errname || errmode == NONE || loglevel >= DEBUG0)
2238  return;
2239 
2240  va_start(args, fmt);
2241  vsnprintf(buf, sizeof(buf), fmt, args);
2242  va_end(args);
2243 
2244  switch(loglevel) {
2245  case INFO:
2246  level = LOG_INFO;
2247  break;
2248  case NOTIFY:
2249  level = LOG_NOTICE;
2250  break;
2251  case WARN:
2252  level = LOG_WARNING;
2253  break;
2254  case ERR:
2255  level = LOG_ERR;
2256  break;
2257  case FAIL:
2258  level = LOG_CRIT;
2259  break;
2260  default:
2261  level = LOG_ERR;
2262  }
2263 
2264  ::syslog(level | LOG_AUTHPRIV, "%s", buf);
2265 
2266  if(level == LOG_CRIT)
2267  cpr_runtime_error(buf);
2268 }
2269 
2270 void shell::log(loglevel_t loglevel, const char *fmt, ...)
2271 {
2272  assert(fmt != NULL && *fmt != 0);
2273 
2274  char buf[256];
2275  va_list args;
2276  int level= LOG_ERR;
2277 
2278  if(!errname || errmode == NONE || loglevel > errlevel)
2279  return;
2280 
2281  va_start(args, fmt);
2282  vsnprintf(buf, sizeof(buf), fmt, args);
2283  va_end(args);
2284 
2285  if(errproc != (logproc_t)NULL) {
2286  if((*errproc)(loglevel, buf))
2287  return;
2288  }
2289 
2290  if(loglevel >= DEBUG0) {
2291  if(getppid() > 1) {
2292  if(fmt[strlen(fmt) - 1] == '\n')
2293  fprintf(stderr, "%s: %s", errname, buf);
2294  else
2295  fprintf(stderr, "%s: %s\n", errname, buf);
2296  }
2297  return;
2298  }
2299 
2300  switch(loglevel) {
2301  case INFO:
2302  level = LOG_INFO;
2303  break;
2304  case NOTIFY:
2305  level = LOG_NOTICE;
2306  break;
2307  case WARN:
2308  level = LOG_WARNING;
2309  break;
2310  case ERR:
2311  level = LOG_ERR;
2312  break;
2313  case FAIL:
2314  level = LOG_CRIT;
2315  break;
2316  default:
2317  level = LOG_ERR;
2318  }
2319 
2320  if(getppid() > 1) {
2321  if(fmt[strlen(fmt) - 1] == '\n')
2322  fprintf(stderr, "%s: %s", errname, buf);
2323  else
2324  fprintf(stderr, "%s: %s\n", errname, buf);
2325  }
2326  ::syslog(level, "%s", buf);
2327 
2328  if(level == LOG_CRIT)
2329  cpr_runtime_error(buf);
2330 }
2331 
2332 #else
2333 
2334 void shell::log(const char *name, loglevel_t level, logmode_t mode, logproc_t handler)
2335 {
2336  errlevel = level;
2337  errmode = mode;
2338  errname = name;
2339 
2340  if(handler != (logproc_t)NULL)
2341  errproc = handler;
2342 }
2343 
2344 void shell::security(loglevel_t loglevel, const char *fmt, ...)
2345 {
2346  assert(fmt != NULL && *fmt != 0);
2347 
2348  char buf[256];
2349  va_list args;
2350 
2351  if(!errname || errmode == NONE || loglevel >= DEBUG0)
2352  return;
2353 
2354  va_start(args, fmt);
2355  vsnprintf(buf, sizeof(buf), fmt, args);
2356  va_end(args);
2357 
2358  if(fmt[strlen(fmt) - 1] == '\n')
2359  fprintf(stderr, "%s: %s", errname, buf);
2360  else
2361  fprintf(stderr, "%s: %s\n", errname, buf);
2362 
2363  if(loglevel == FAIL)
2364  cpr_runtime_error(buf);
2365 }
2366 
2367 void shell::log(loglevel_t loglevel, const char *fmt, ...)
2368 {
2369  assert(fmt != NULL && *fmt != 0);
2370 
2371  char buf[256];
2372  va_list args;
2373 
2374  if(!errname || errmode == NONE || loglevel > errlevel)
2375  return;
2376 
2377  va_start(args, fmt);
2378  vsnprintf(buf, sizeof(buf), fmt, args);
2379  va_end(args);
2380 
2381  if(errproc != (logproc_t)NULL) {
2382  if((*errproc)(loglevel, buf))
2383  return;
2384  }
2385 
2386  if(loglevel >= DEBUG0) {
2387  if(fmt[strlen(fmt) - 1] == '\n')
2388  fprintf(stderr, "%s: %s", errname, buf);
2389  else
2390  fprintf(stderr, "%s: %s\n", errname, buf);
2391  return;
2392  }
2393 
2394  if(fmt[strlen(fmt) - 1] == '\n')
2395  fprintf(stderr, "%s: %s", errname, buf);
2396  else
2397  fprintf(stderr, "%s: %s\n", errname, buf);
2398 
2399  if(loglevel == FAIL)
2400  cpr_runtime_error(buf);
2401 }
2402 
2403 #endif
2404 
2405 #ifndef _MSWINDOWS_
2406 
2407 void shell::restart(char *argv0, char **argv, char **list)
2408 {
2409  unsigned args = count(argv);
2410  unsigned head = count(list);
2411  unsigned argc = 2 + args + head;
2412  char **newargs = (char **)mempager::_alloc(sizeof(char **) * argc--);
2413 
2414  memcpy(newargs, list, head * sizeof(char **));
2415  newargs[head++] = argv0;
2416  if(args)
2417  memcpy(&newargs[head], argv, args * sizeof(char **));
2418 
2419  newargs[argc] = NULL;
2420  execvp(*list, newargs);
2421  exit(-1);
2422 }
2423 
2424 #else
2425 
2426 void shell::restart(char *argv0, char **argv, char **list)
2427 {
2428  exit(-1);
2429 }
2430 
2431 #endif
2432 
2433 bool shell::is_sym(const char *name) const
2434 {
2435  symlock.acquire();
2436 
2438 
2439  while(is(sp)) {
2440  if(eq(sp->name, name)) {
2441  symlock.release();
2442  return true;
2443  }
2444  ++sp;
2445  }
2446  symlock.release();
2447  return false;
2448 }
2449 
2450 const char *shell::getsym(const char *name, const char *value)
2451 {
2452  symlock.acquire();
2454 
2455  while(is(sp)) {
2456  if(eq(sp->name, name)) {
2457  value = sp->value;
2458  symlock.release();
2459  return value;
2460  }
2461  ++sp;
2462  }
2463 
2464  symlock.release();
2465  return shell::getenv(name, value);
2466 }
2467 
2468 void shell::setsym(const char *name, const char *value)
2469 {
2470  symlock.acquire();
2472 
2473  while(is(sp)) {
2474  if(eq(sp->name, name)) {
2475  sp->value = dup(value);
2476  symlock.release();
2477  return;
2478  }
2479  ++sp;
2480  }
2481 
2482  syms *v = (syms *)mempager::_alloc(sizeof(syms));
2483  v->name = dup(name);
2484  v->value = dup(value);
2485  v->enlist(&_syms);
2486  symlock.release();
2487 }
2488 
2490 {
2491  if(*dir == '\\' || *dir == '/')
2492  return str(dir);
2493 
2494  if(strchr(prefix, '\\'))
2495  return prefix + "\\" + dir;
2496 
2497  return prefix + "/" + dir;
2498 }
2499 
2500 String shell::path(path_t id, const char *dir)
2501 {
2502  string_t result;
2503 
2504  if(*dir == '\\' || *dir == '/')
2505  result = dir;
2506  else {
2507  result = path(id);
2508  if(strchr(*result, '\\'))
2509  result = result + "\\" + dir;
2510  else
2511  result = result + "/" + dir;
2512  }
2513  return result;
2514 }
2515 
2516 } // namespace ucommon
ucommon::shell::charopt::used
bool used
Definition: shell.h:345
ucommon::_exitproc
static shell::exitproc_t _exitproc
Definition: shell.cpp:107
ucommon::mempager
Definition: memory.h:184
ucommon::shell::NOARGS
Definition: shell.h:99
ucommon::errlevel
static shell::loglevel_t errlevel
Definition: shell.cpp:99
ucommon::shell::counteropt::counteropt
counteropt(char short_option, const char *long_option=NULL, const char *help=NULL, const char *type="numeric", long def_value=0)
Definition: shell.cpp:191
ucommon::errname
static const char * errname
Definition: shell.cpp:101
ucommon::shell::shell
shell(const char *string, size_t pagesize=0)
Definition: shell.cpp:345
ucommon::shell::charopt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:255
ucommon::shell::SERVICE_CACHE
Definition: shell.h:122
ucommon::LinkedObject::Next
LinkedObject * Next
Definition: linked.h:62
ucommon::shell::systemf
static int systemf(const char *format,...) __PRINTF(1
Definition: shell.cpp:540
ucommon::shell::Option::assign
virtual const char * assign(const char *value)=0
ucommon::shell::count
static unsigned count(char **argv)
Definition: shell.cpp:398
ucommon::shell::SYSTEM_CFG
Definition: shell.h:122
ucommon::shell::Option::Option
Option(char short_option=0, const char *long_option=NULL, const char *value_type=NULL, const char *help=NULL)
Definition: shell.cpp:111
ucommon::shell::spawn
static shell::pid_t spawn(const char *path, char **argv, char **env=NULL, fd_t *stdio=NULL)
Definition: shell.cpp:2012
setlocale
#define setlocale(s, t)
Definition: shell.cpp:65
ucommon::_orig
static char ** _orig
Definition: shell.cpp:104
dgettext
#define dgettext(d, s)
Definition: shell.cpp:75
export.h
argv0
static const char * argv0
Definition: car.cpp:40
ucommon::shell::Option::uses_option
const char * uses_option
Definition: shell.h:194
ucommon::shell::getpass
static char * getpass(const char *prompt, char *buffer, size_t size)
Definition: shell.cpp:1483
ucommon::shell::path
static String path(path_t id)
Definition: shell.cpp:1551
fd_t
int fd_t
Definition: platform.h:415
ucommon::shell::_argv0
char * _argv0
Definition: shell.h:64
ucommon::shell::INVARGUMENT
Definition: shell.h:99
ucommon::shell::bind
static void bind(const char *name)
Definition: shell.cpp:2113
ucommon::eq_case
bool eq_case(char const *s1, char const *s2)
Definition: string.h:1699
ucommon::shell::CONSOLE_LOG
Definition: shell.h:104
ucommon::shell::stringopt::text
const char * text
Definition: shell.h:303
ucommon
Definition: access.cpp:23
ucommon::shell::syms
Definition: shell.h:76
ucommon::shell::INFO
Definition: shell.h:109
ucommon::shell::exitproc_t
void(* exitproc_t)(void)
Definition: shell.h:139
ucommon::shell::flagopt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:160
ucommon::shell::SYSTEM_VAR
Definition: shell.h:123
ucommon::memalloc::size
size_t size(void) const
Definition: memory.h:125
ucommon::shell::counteropt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:199
ucommon::shell::Option::disable
void disable(void)
Definition: shell.cpp:145
protocols.h
ucommon::fsys::is_tty
bool is_tty(void) const
Definition: fsys.cpp:801
ucommon::shell::NONE
Definition: shell.h:104
ucommon::LinkedObject::enlist
void enlist(LinkedObject **root)
Definition: linked.cpp:62
ucommon::shell::NUMERIC_SET
Definition: shell.h:99
ost::String
ucommon::String String
Definition: string.h:54
ucommon::shell::setsym
void setsym(const char *name, const char *value)
Definition: shell.cpp:2468
ucommon::shell::USER_CONFIG
Definition: shell.h:122
ucommon::shell::args::item
char * item
Definition: shell.h:73
ucommon::shell::USER_DEFAULTS
Definition: shell.h:120
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: platform.h:417
ucommon::String
Definition: string.h:78
result
static void result(const char *path, int code)
Definition: mdsum.cpp:35
ucommon::shell::parse
char ** parse(const char *string)
Definition: shell.cpp:489
ucommon::shell::getsym
const char * getsym(const char *name, const char *value=NULL)
Definition: shell.cpp:2450
ucommon::shell::_argv
char ** _argv
Definition: shell.h:62
ucommon::mempager::_alloc
virtual void * _alloc(size_t size) __OVERRIDE
Definition: memory.cpp:279
ucommon::shell::syms::name
const char * name
Definition: shell.h:79
ucommon::fsys::DIR_TEMPORARY
Definition: fsys.h:144
ucommon::shell::NO_NUMERIC
Definition: shell.h:114
ucommon::shell::NOTIFY
Definition: shell.h:109
ucommon::shell::SERVICE_CONFIG
Definition: shell.h:120
ucommon::min
T &() min(T &o1, T &o2)
Definition: generics.h:456
ucommon::shell::loglevel_t
loglevel_t
Definition: shell.h:109
ucommon::shell::counteropt::used
bool used
Definition: shell.h:441
ucommon::system_prefix
static const char * system_prefix
Definition: shell.cpp:1419
ucommon::fsys::remapError
static int remapError(void)
Definition: fsys.h:152
ucommon::shell::SYSTEM_LOG
Definition: shell.h:104
ucommon::shell::Option::long_option
const char * long_option
Definition: shell.h:193
ucommon::shell::SECURITY_LOG
Definition: shell.h:104
ucommon::memalloc::max
unsigned max(void) const
Definition: memory.h:117
ucommon::shell::SYSTEM_TEMP
Definition: shell.h:121
ucommon::shell::is_sym
bool is_sym(const char *name) const
Definition: shell.cpp:2433
ucommon::shell::WARN
Definition: shell.h:109
ucommon::shell::text
static const char * text(const char *string)
Definition: shell.cpp:2104
ucommon::noecho
static void noecho(int fd)
Definition: shell.cpp:1427
ucommon::shell::numericopt::number
long number
Definition: shell.h:397
ucommon::shell::syms::value
const char * value
Definition: shell.h:80
ucommon::errproc
static shell::logproc_t errproc
Definition: shell.cpp:102
ucommon::shell::relocate
static int static void relocate(const char *argv0)
Definition: shell.cpp:1520
ucommon::shell::stringopt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:238
ucommon::exit_handler
static void exit_handler(void)
Definition: shell.cpp:1756
ucommon::string_t
String string_t
Definition: string.h:1579
ucommon::shell::groupopt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:226
ucommon::shell::charopt::charopt
charopt(char short_option, const char *long_option=NULL, const char *help=NULL, const char *type="char", char default_code=' ')
Definition: shell.cpp:248
ucommon::shell::inkey
static int inkey(const char *prompt=NULL)
Definition: shell.cpp:1506
process.h
Process services.
exit_code
static int exit_code
Definition: car.cpp:39
ucommon::shell::FAIL
Definition: shell.h:109
ucommon::shell::Option::help_string
const char * help_string
Definition: shell.h:195
quote
static shell::stringopt quote('q', "--quote", _TEXT("set quote for each argument"), "string", "")
ucommon::shell::USER_DATA
Definition: shell.h:122
ucommon::Mutex::acquire
void acquire(void)
Definition: thread.h:486
ucommon::shell::args
Definition: shell.h:70
ucommon::memalloc::pagesize
size_t pagesize
Definition: memory.h:66
ucommon::shell::input
static fd_t input(void)
Definition: shell.h:869
ucommon::shell::PROGRAM_CONFIG
Definition: shell.h:120
ucommon::dir::create
static int create(const char *path, unsigned mode)
Definition: fsys.cpp:895
ucommon::shell::errexit
static void static void errexit(int exitcode, const char *format=NULL,...) __PRINTF(2
Definition: shell.cpp:828
thread.h
ucommon::OrderedIndex
Definition: linked.h:176
ucommon::shell::USER_LOG
Definition: shell.h:104
ucommon::shell::errlog
static void errlog(const char *format,...) __PRINTF(1
Definition: shell.cpp:787
ucommon::Mutex::release
void release(void)
Definition: thread.h:507
WTERMSIG
#define WTERMSIG(status)
Definition: process.cpp:223
ucommon::shell::BAD_VALUE
Definition: shell.h:99
ucommon::shell::getNumeric
static long getNumeric(void)
Definition: shell.cpp:393
ucommon::shell::path_t
path_t
Definition: shell.h:119
ucommon::OrderedObject::enlist
virtual void enlist(OrderedIndex *index)
Definition: linked.cpp:676
ucommon::_domain
static const char * _domain
Definition: shell.cpp:106
ucommon::String::token
static char * token(char *text, char **last, const char *list, const char *quote=NULL, const char *end=NULL)
Definition: string.cpp:1305
stream.h
ucommon::shell::setNumeric
static void setNumeric(numeric_t)
Definition: shell.cpp:387
ucommon::shell::getenv
const char * getenv(const char *name, const char *value=NULL)
Definition: shell.cpp:1665
_PATH_TTY
#define _PATH_TTY
Definition: shell.cpp:94
ucommon::shell
Definition: shell.h:59
ucommon::eq
bool eq(const struct sockaddr *s1, const struct sockaddr *s2)
Definition: socket.h:2100
ucommon::shell::numeric_t
numeric_t
Definition: shell.h:114
ucommon::numeric_mode
static shell::numeric_t numeric_mode
Definition: shell.cpp:108
ucommon::shell::getline
static char * getline(const char *prompt, char *buffer, size_t size)
Definition: shell.cpp:1451
ucommon::shell::OPTION_USED
Definition: shell.h:99
ucommon::dup
T * dup(const T &object)
Definition: generics.h:324
ucommon::String::set
void set(const char *text)
Definition: string.cpp:802
ucommon::counter
Definition: counter.h:43
ucommon::shell::stringopt::stringopt
stringopt(char short_option, const char *long_option=NULL, const char *help=NULL, const char *type="text", const char *def_text=NULL)
Definition: shell.cpp:231
ucommon::shell::system
static int system(const char *command, const char **env=NULL)
Definition: shell.cpp:1674
ucommon::shell::SYSTEM_ETC
Definition: shell.h:122
ucommon::shell::flagopt::single
bool single
Definition: shell.h:238
crit
#define crit(x, text)
Definition: platform.h:541
ch
#define ch(x, y, z)
Definition: sha2.cpp:120
ucommon::shell::mainproc_t
cpr_service_t mainproc_t
Definition: shell.h:134
ucommon::shell::argv
char ** argv(void) const
Definition: shell.h:741
ucommon::shell::cancel
static int cancel(shell::pid_t pid)
Definition: shell.cpp:2083
ucommon::linked_pointer
Definition: linked.h:991
ucommon::shell::errmsg
static const char * errmsg(errmsg_t id)
Definition: shell.cpp:377
ucommon::symlock
static mutex_t symlock
Definition: shell.cpp:103
ucommon::shell::Option::~Option
virtual ~Option()
Definition: shell.cpp:131
ucommon::shell::PROGRAM_TEMP
Definition: shell.h:124
ucommon::shell::restart
void restart(void)
Definition: shell.cpp:1728
ucommon::fsys::OWNER_PRIVATE
Definition: fsys.h:139
ucommon::shell::SERVICE_DATA
Definition: shell.h:121
ucommon::shell::charopt::code
char code
Definition: shell.h:350
ucommon::shell::SYSTEM_PREFIX
Definition: shell.h:123
ucommon::shell::numericopt::used
bool used
Definition: shell.h:392
ucommon::olast
static shell::Option * olast
Definition: shell.cpp:105
gettext
#define gettext(s)
Definition: shell.cpp:76
ucommon::shell::getargv
char ** getargv(char **argv)
Definition: shell.cpp:570
cpr_runtime_error
void cpr_runtime_error(const char *str)
Definition: cpr.cpp:83
ucommon::shell::Option::reset
static void reset(void)
Definition: shell.cpp:135
fsys.h
ucommon::shell::_argc
unsigned _argc
Definition: shell.h:63
textdomain
#define textdomain(s)
Definition: shell.cpp:78
ucommon::LinkedObject
Definition: linked.h:55
ucommon::dir
Definition: fsys.h:743
ucommon::shell::Option::trigger_option
bool trigger_option
Definition: shell.h:196
ucommon::str
String str(Socket &so, size_t size)
Definition: socket.cpp:3507
ucommon::shell::numericopt::assign
virtual const char * assign(const char *value)
Definition: shell.cpp:176
ucommon::shell::getargv0
char * getargv0(char **argv)
Definition: shell.cpp:561
ucommon::shell::logmode_t
logmode_t
Definition: shell.h:104
ucommon::linked_pointer::next
void next(void)
Definition: linked.h:1106
ucommon::msgs
static const char * msgs[]
Definition: shell.cpp:367
buffer
static uint8_t buffer[65536]
Definition: zerofill.cpp:27
ucommon::String::add
void add(const char *text)
Definition: string.cpp:992
ucommon::shell::userid
static String userid(void)
Definition: shell.cpp:1541
ucommon::shell::rebind
static void rebind(const char *name=NULL)
Definition: shell.cpp:2130
ucommon::shell::errmsg_t
errmsg_t
Definition: shell.h:99
ucommon::shell::NUMERIC_DASH
Definition: shell.h:114
socksize_t
size_t socksize_t
Definition: platform.h:296
ucommon::shell::stringopt::used
bool used
Definition: shell.h:298
bindtextdomain
#define bindtextdomain(s, t)
Definition: shell.cpp:77
ucommon::shell::ERR
Definition: shell.h:109
ucommon::shell::NUMERIC_ALL
Definition: shell.h:114
ucommon::shell::pid_t
int pid_t
Definition: shell.h:147
ucommon::shell::NOARGUMENT
Definition: shell.h:99
ucommon::echo
static void echo(int fd)
Definition: shell.cpp:1442
ucommon::numeric_value
static long numeric_value
Definition: shell.cpp:109
ucommon::shell::exiting
static void exiting(exitproc_t)
Definition: shell.cpp:1771
ucommon::shell::set0
void set0(char *argv0)
Definition: shell.cpp:291
string.h
ucommon::shell::argv0
const char * argv0() const
Definition: shell.h:664
ucommon::shell::Option::short_option
char short_option
Definition: shell.h:192
ucommon::shell::flagopt::flagopt
flagopt(char short_option, const char *long_option=NULL, const char *help=NULL, bool single_use=true)
Definition: shell.cpp:153
ucommon::shell::security
static void static void static void security(loglevel_t level, const char *format,...) __PRINTF(2
Definition: shell.cpp:2344
ucommon::shell::collapse
void collapse(LinkedObject *first)
Definition: shell.cpp:280
ucommon::shell::NUMERIC_PLUS
Definition: shell.h:114
ucommon::shell::groupopt::groupopt
groupopt(const char *help)
Definition: shell.cpp:221
ucommon::shell::USER_CACHE
Definition: shell.h:121
prefix
static char prefix[80]
Definition: args.cpp:33
ucommon::fsys::prefix
static stringref_t prefix(void)
Definition: fsys.cpp:1803
ucommon::shell::logproc_t
bool(* logproc_t)(loglevel_t level, const char *text)
Definition: shell.h:129
ucommon::shell::debug
static void debug(unsigned level, const char *format,...) __PRINTF(2
Definition: shell.cpp:2173
ucommon::shell::SERVICE_CONTROL
Definition: shell.h:120
ucommon::ofirst
static shell::Option * ofirst
Definition: shell.cpp:105
ucommon::shell::_syms
LinkedObject * _syms
Definition: shell.h:66
ucommon::shell::texts
static const char * texts(const char *singular, const char *plural, unsigned long count)
Definition: shell.cpp:2092
ucommon::shell::USER_HOME
Definition: shell.h:121
ucommon::abort_handler
static void abort_handler(int signo)
Definition: shell.cpp:1765
ucommon::shell::PROGRAM_PLUGINS
Definition: shell.h:123
WIFEXITED
#define WIFEXITED(status)
Definition: process.cpp:219
ucommon::shell::detach
void detach(mainproc_t mainentry=(mainproc_t) NULL)
Definition: shell.cpp:1846
ucommon::shell::numericopt::numericopt
numericopt(char short_option, const char *long_option=NULL, const char *help=NULL, const char *type="numeric", long def_value=0)
Definition: shell.cpp:169
ucommon::errmode
static shell::logmode_t errmode
Definition: shell.cpp:100
shell.h
ucommon::shell::Option
Definition: shell.h:186
ucommon::shell::help
static void help(void)
Definition: shell.cpp:408
ucommon::shell::counteropt::number
long number
Definition: shell.h:446
WEXITSTATUS
#define WEXITSTATUS(status)
Definition: shell.cpp:90
ucommon::shell::printf
static size_t printf(const char *format,...) __PRINTF(1
Definition: shell.cpp:874
ucommon::fsys::is_file
static bool is_file(const char *path)
Definition: fsys.cpp:1453
ucommon::Mutex
Definition: thread.h:459
memory.h
ucommon::shell::argc
static size_t unsigned argc(void) const
Definition: shell.h:732
ucommon::shell::DEBUG0
Definition: shell.h:109
ucommon::shell::priority
static void priority(int pri=1)
Definition: shell.cpp:2143
ucommon::shell::log
static void static void log(loglevel_t level, const char *format,...) __PRINTF(2
Definition: shell.cpp:2367
ucommon::shell::BADOPTION
Definition: shell.h:99
ucommon::shell::wait
static int wait(shell::pid_t pid)
Definition: shell.cpp:2070
ucommon::is
bool is(T &object)
Definition: generics.h:292
ucommon::shell::SYSTEM_SHARE
Definition: shell.h:123
EOF
#define EOF
Definition: stream.cpp:51
ucommon::shell::Option::first
static LinkedObject * first(void)
Definition: shell.cpp:140
ucommon::_TEXT
const char * _TEXT(const char *s)
Definition: shell.h:911
ucommon::OrderedIndex::begin
LinkedObject * begin(void) const
Definition: linked.h:270
INVALID_PID_VALUE
#define INVALID_PID_VALUE
Definition: shell.h:43
ucommon::shell::release
static void release(int exit_code=0)
Definition: shell.cpp:1785
ucommon::shell::_exedir
char * _exedir
Definition: shell.h:65