835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer.
f41b982009-05-07Martin Stjernholm // Copyright © 1996 - 2009, Roxen IS.
835c6c2001-06-17Martin Nilsson // // Roxen bootstrap program.
920f062013-02-05Build system // $Id$
fb23362001-12-04Martin Stjernholm 
79ca872000-11-24Per Hedbor #define LocaleString Locale.DeferredLocale|string
2a98981997-04-19Henrik Grubbström (Grubba) 
c2d7aa2004-04-13Martin Stjernholm mixed x = Calendar.Timezone; // #"!¤&"¤%/"&#¤!%#¤&#
6d6bc82001-06-24Martin Nilsson // #pragma strict_types
20bcc72000-03-13Martin Nilsson 
09ff051998-10-03Henrik Grubbström (Grubba) // Sets up the roxen environment. Including custom functions like spawne().
2a98981997-04-19Henrik Grubbström (Grubba) 
40dd281999-11-23Per Hedbor #include <stat.h>
5d98ea2012-01-07Martin Stjernholm #include <roxen.h>
e41c9d2017-04-21Henrik Grubbström (Grubba)  // --- Locale defines --- //<locale-token project="roxen_start"> LOC_S </locale-token> //<locale-token project="roxen_message"> LOC_M </locale-token> #define LOC_S(X,Y) _STR_LOCALE("roxen_start",X,Y) #define LOC_M(X,Y) _STR_LOCALE("roxen_message",X,Y) #define CALL_M(X,Y) _LOCALE_FUN("roxen_message",X,Y)
56881b1997-08-27Henrik Grubbström (Grubba) // // NOTE:
0ceeee1997-08-31Henrik Grubbström (Grubba) // This file uses replace_master(). This implies that the // master() efun when used in this file will return the old // master and not the new one.
56881b1997-08-27Henrik Grubbström (Grubba) //
fc40392008-08-15Martin Stjernholm private __builtin.__master new_master;
56881b1997-08-27Henrik Grubbström (Grubba) 
f2a5d92015-06-12Henrik Grubbström (Grubba) #if constant(spider) // This ancient module has been removed in Pike 8.1.
8f81d82001-01-03Per Hedbor constant s = spider; // compatibility
f2a5d92015-06-12Henrik Grubbström (Grubba) #endif
8f81d82001-01-03Per Hedbor 
1efb702006-08-16Henrik Grubbström (Grubba) // Enable decoding of wide string data from mysql.
a87a0d2006-11-17Martin Stjernholm // Disabled since it isn't compatible enough - has to be enabled on a // per-connection basis through the charset argument. /mast //#define ENABLE_MYSQL_UNICODE_MODE
1efb702006-08-16Henrik Grubbström (Grubba) 
8f81d82001-01-03Per Hedbor int remove_dumped;
74e3902000-12-30Per Hedbor string configuration_dir;
097e182009-12-09Martin Stjernholm int once_mode;
8f56cb2000-09-30Per Hedbor 
58a6431999-12-20Martin Nilsson #define werror roxen_perror
56881b1997-08-27Henrik Grubbström (Grubba) 
920f062013-02-05Build system constant cvs_version="$Id$";
2a98981997-04-19Henrik Grubbström (Grubba)  int pid = getpid();
8ad9292000-03-13Martin Nilsson Stdio.File stderr = Stdio.File("stderr");
2a98981997-04-19Henrik Grubbström (Grubba) 
8f81d82001-01-03Per Hedbor #if !constant(uname)
51ba6d2000-04-12Per Hedbor #ifdef __NT__ mapping uname() { return ([ "machine":"NT", "release":"unknown", "sysname":"NT", "nodename":gethostname(), "version":"unknown", ]); }
8f81d82001-01-03Per Hedbor #else mapping uname() { return ([ "machine":"unknown", "release":"unknown", "sysname":"unknown", "nodename":gethostname(), "version":"unknown", ]); } #endif
51ba6d2000-04-12Per Hedbor #endif
20bcc72000-03-13Martin Nilsson mapping(int:string) pwn=([]);
953ca31997-08-18Per Hedbor string pw_name(int uid)
3611e31997-04-26Per Hedbor {
c79b261998-02-05Johan Schön #if !constant(getpwuid) return "uid #"+uid; #else
3611e31997-04-26Per Hedbor  if(pwn[uid]) return pwn[uid];
20bcc72000-03-13Martin Nilsson  return pwn[uid]=([array(string)]getpwuid(uid)||((""+uid)/":"))[0];
c79b261998-02-05Johan Schön #endif } #if !constant(getppid)
8f81d82001-01-03Per Hedbor int getppid() { return -1; }
c79b261998-02-05Johan Schön #endif
2a98981997-04-19Henrik Grubbström (Grubba) 
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
342f4d1998-09-12Per Hedbor #define LOG_CONS (1<<0) #define LOG_NDELAY (1<<1) #define LOG_PERROR (1<<2) #define LOG_PID (1<<3) #define LOG_AUTH (1<<0) #define LOG_AUTHPRIV (1<<1) #define LOG_CRON (1<<2) #define LOG_DAEMON (1<<3) #define LOG_KERN (1<<4) #define LOG_LOCAL (1<<5) #define LOG_LOCAL1 (1<<6) #define LOG_LOCAL2 (1<<7) #define LOG_LOCAL3 (1<<8) #define LOG_LOCAL4 (1<<9) #define LOG_LOCAL5 (1<<10) #define LOG_LOCAL6 (1<<11) #define LOG_LOCAL7 (1<<12) #define LOG_LPR (1<<13) #define LOG_MAIL (1<<14) #define LOG_NEWS (1<<15) #define LOG_SYSLOG (1<<16) #define LOG_USER (1<<17) #define LOG_UUCP (1<<18) #define LOG_EMERG (1<<0) #define LOG_ALERT (1<<1) #define LOG_CRIT (1<<2) #define LOG_ERR (1<<3) #define LOG_WARNING (1<<4) #define LOG_NOTICE (1<<5) #define LOG_INFO (1<<6) #define LOG_DEBUG (1<<7) int use_syslog, loggingfield; #endif
cefd172011-12-27Martin Stjernholm //! The path to the server directory, without trailing slash. If //! available, this is the logical path without following symlinks (as //! opposed to what @[getcwd] returns).
de76592011-12-27Martin Stjernholm //! //! @note //! @[getcwd] should be used when the server directory is combined //! with a path that may contain "..". The main reason is to keep //! compatibility, and in extension for the sake of consistency.
cefd172011-12-27Martin Stjernholm string server_dir = lambda () { string cwd = getcwd(); #ifdef __NT__
bd23792012-02-08Jonas Wallden  cwd = replace (cwd, "\\", "/");
cefd172011-12-27Martin Stjernholm #endif if (has_suffix (cwd, "/")) report_warning ("Warning: Server directory is a root dir " "(or getcwd() misbehaves): %O\n", cwd); string check_dir (string d) { while (has_suffix (d, "/")) d = d[..<2]; #if constant (resolvepath) if (resolvepath (d) == cwd) return d; #else if (cd (d)) { if (getcwd() == cwd) return d; else cd (cwd); } #endif return 0; }; if (string env_pwd = getenv ("PWD")) if (string res = check_dir (env_pwd)) return res; if (string res = check_dir (combine_path (__FILE__, "../.."))) return res; return cwd; }();
6d6bc82001-06-24Martin Nilsson 
09ff051998-10-03Henrik Grubbström (Grubba) /* * Some efuns used by Roxen */
fc40392008-08-15Martin Stjernholm protected string last_id, last_from;
fb23362001-12-04Martin Stjernholm string get_cvs_id(string from) { if(last_from == from) return last_id; last_from=from; catch { object f = open(from,"r"); string id; id = f->read(1024);
d2d0f92010-10-27Martin Stjernholm  if (sscanf (id, "%*s$""Id: %s $", id) == 2) { if(sscanf(id, "%*s,v %[0-9.] %*s", string rev) == 3) return last_id=" (rev "+rev+")"; // cvs if (sscanf (id, "%[0-9a-z]%*c", id) == 1) return last_id = " (" + id[..7] + ")"; // git }
fb23362001-12-04Martin Stjernholm  }; last_id = ""; return ""; } void add_cvs_ids(mixed to) {
d3eaa42003-01-22Henrik Grubbström (Grubba)  if (arrayp(to) && sizeof(to) >= 2 && !objectp(to[1]) && arrayp(to[1]) || objectp(to) && to->is_generic_error)
fb23362001-12-04Martin Stjernholm  to = to[1];
d3eaa42003-01-22Henrik Grubbström (Grubba)  else if (!arrayp(to)) return;
fb23362001-12-04Martin Stjernholm  foreach(to, mixed q)
d3eaa42003-01-22Henrik Grubbström (Grubba)  if(arrayp(q) && sizeof(q) && stringp(q[0])) {
fb23362001-12-04Martin Stjernholm  string id = get_cvs_id(q[0]); catch (q[0] += id); } }
9c43e22010-05-06Fredrik Noring int num_describe_backtrace = 0; // For statistics
fb23362001-12-04Martin Stjernholm string describe_backtrace (mixed err, void|int linewidth) {
9c43e22010-05-06Fredrik Noring  num_describe_backtrace++;
b36cbb2010-11-01Martin Stjernholm  #ifdef RUN_SELF_TEST // Count this as a failure if it occurs during the self test. This // is somewhat blunt, but it should catch all the places (typically // in other threads) where we catch errors, log them, and continue. if (roxen) foreach (roxen->configurations, object/*(Configuration)*/ conf) if (object/*(RoxenModule)*/ mod = conf->get_provider ("roxen_test")) { mod->background_failure(); } #endif
fb23362001-12-04Martin Stjernholm  add_cvs_ids (err); return predef::describe_backtrace (err, 999999); }
b5e3b02010-05-19Fredrik Noring int co_num_call_out = 0; // For statistics int co_num_runs_001s = 0; int co_num_runs_005s = 0; int co_num_runs_015s = 0; int co_num_runs_05s = 0; int co_num_runs_1s = 0; int co_num_runs_5s = 0; int co_num_runs_15s = 0; int co_acc_time = 0; int co_acc_cpu_time = 0; mixed call_out(function f, float|int delay, mixed ... args) { return predef::call_out(class (function f) { int __hash() { return hash_value(f); } int `==(mixed g) { return f == g; } string _sprintf() { return sprintf("%O", f); } mixed `()(mixed ... args) {
7f9f082010-05-19Fredrik Noring  co_num_call_out++; mixed err, res;
b5e3b02010-05-19Fredrik Noring  int start_hrtime = gethrtime();
fb7e9c2010-05-25Henrik Grubbström (Grubba)  float co_vtime = gauge { err = catch { res = f && f(@args); }; };
b5e3b02010-05-19Fredrik Noring  float co_rtime = (gethrtime() - start_hrtime)/1E6; if (co_rtime > 0.01) co_num_runs_001s++; if (co_rtime > 0.05) co_num_runs_005s++; if (co_rtime > 0.15) co_num_runs_015s++; if (co_rtime > 0.50) co_num_runs_05s++; if (co_rtime > 1.00) co_num_runs_1s++; if (co_rtime > 5.00) co_num_runs_5s++; if (co_rtime > 15.00) co_num_runs_15s++; co_acc_cpu_time += (int)(1E6*co_vtime); co_acc_time += (int)(1E6*co_rtime); if (err) throw(err); return res; } }(f), delay, @args); }
edd8572017-01-19Jonas Walldén  protected int(2..2147483647) roxen_started = [int(2..2147483647)]time(); protected float roxen_started_flt = time(time()); protected int uptime_row_counter;
5097091999-08-06Per Hedbor string short_time() {
edd8572017-01-19Jonas Walldén  string up_str; if (uptime_row_counter) { up_str = " "; } else { float up = time(roxen_started) - roxen_started_flt; if (up > 3600) { up_str = sprintf( "%2dd%2dh%2dm", (int) up / 86400, (((int) up / 3600) % 24), ((int) up / 60) % 60); } else { up_str = sprintf( "%2dm%4.1fs ", ((int) up / 60) % 60, up % 60);
930ddd1999-08-06Per Hedbor  }
edd8572017-01-19Jonas Walldén  } uptime_row_counter = (uptime_row_counter + 1) % 5; mapping l = localtime(time()); return sprintf("%2d:%02d:%02d %s : ", l->hour, l->min, l->sec, up_str);
5097091999-08-06Per Hedbor }
edd8572017-01-19Jonas Walldén 
19924b2001-08-24Martin Nilsson //! @decl void werror(string format, mixed ... args) //! @appears werror //! @decl void roxen_perror(string format, mixed ... args) //! @appears roxen_perror
fc40392008-08-15Martin Stjernholm protected int last_was_nl = 1;
09ff051998-10-03Henrik Grubbström (Grubba) // Used to print error/debug messages
c423772009-03-24Henrik Grubbström (Grubba) void roxen_perror(sprintf_format format, sprintf_args ... args)
3cbd831997-04-26Per Hedbor {
58a6431999-12-20Martin Nilsson  if(sizeof(args))
4252de1999-08-09Henrik Grubbström (Grubba)  format=sprintf(format,@args);
c45b2a1999-12-09Martin Stjernholm  // "Delayed newlines": End a message with \b and start the next one // with \b to make them continue on the same line. If another
f353f31999-12-10Martin Stjernholm  // message gets in between, it still gets written on a new line.
c45b2a1999-12-09Martin Stjernholm  int delayed_nl; if (format == "\b") format = ""; else if (sizeof (format)) { if (format[0] == '\b') { if (last_was_nl == -1) last_was_nl = 0; format = format[1..]; } if (format[-1] == '\b') { delayed_nl = 1; format = format[..sizeof(format)-2]; } }
4252de1999-08-09Henrik Grubbström (Grubba)  if (!last_was_nl && (format != "")) { // Continuation line. int i = search(format, "\n"); if (i == -1) {
ff46292008-11-25Martin Stjernholm  stderr->write(string_to_utf8(format));
4252de1999-08-09Henrik Grubbström (Grubba)  format = "";
c45b2a1999-12-09Martin Stjernholm  if (delayed_nl) last_was_nl = -1;
4252de1999-08-09Henrik Grubbström (Grubba)  } else {
ff46292008-11-25Martin Stjernholm  stderr->write(string_to_utf8(format[..i]));
4252de1999-08-09Henrik Grubbström (Grubba)  format = format[i+1..]; last_was_nl = 1; } }
c45b2a1999-12-09Martin Stjernholm  if (sizeof(format)) {
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c9182f2009-12-20Martin Stjernholm  syslog_report (format, LOG_DEBUG);
ea803c2010-01-11Jonas Wallden #endif
5097091999-08-06Per Hedbor 
c45b2a1999-12-09Martin Stjernholm  if (last_was_nl == -1) stderr->write("\n"); last_was_nl = format[-1] == '\n';
4252de1999-08-09Henrik Grubbström (Grubba) 
eaa7992001-06-30Martin Stjernholm #ifdef RUN_SELF_TEST
ff46292008-11-25Martin Stjernholm  stderr->write( string_to_utf8( format ) );
eaa7992001-06-30Martin Stjernholm #else
c45b2a1999-12-09Martin Stjernholm  array(string) a = format/"\n"; int i;
4252de1999-08-09Henrik Grubbström (Grubba) 
ff46292008-11-25Martin Stjernholm  a = map( a, string_to_utf8 );
bde1251999-11-19Per Hedbor 
27afff2015-11-24Stefan Wallström #ifdef DEBUG_LOG_SHOW_USER string usr; catch { mixed rxml_ctx = all_constants()["_cur_rxml_context"]->get(); if(rxml_ctx) usr = rxml_ctx->user_get_var("user.username"); }; #endif
c45b2a1999-12-09Martin Stjernholm  for(i=0; i < sizeof(a)-1; i++) {
27afff2015-11-24Stefan Wallström #ifdef DEBUG_LOG_SHOW_USER if(usr) a[i] = usr + " : " + a[i]; #endif
c45b2a1999-12-09Martin Stjernholm  stderr->write(short_time() + a[i] + "\n"); } if (!last_was_nl) {
27afff2015-11-24Stefan Wallström #ifdef DEBUG_LOG_SHOW_USER if(usr) a[-1] = usr + " : " + a[-1]; #endif
c45b2a1999-12-09Martin Stjernholm  stderr->write(short_time() + a[-1]); }
eaa7992001-06-30Martin Stjernholm #endif
4252de1999-08-09Henrik Grubbström (Grubba)  }
c45b2a1999-12-09Martin Stjernholm  if (delayed_nl) last_was_nl = -1;
5281751997-11-26Henrik Grubbström (Grubba) }
eec9801997-04-01Per Hedbor 
19924b2001-08-24Martin Nilsson //! @appears mkdirhier //! Make a directory hierachy
8ef6ca1998-02-14Fredrik Noring int mkdirhier(string from, int|void mode)
eec9801997-04-01Per Hedbor {
8ef6ca1998-02-14Fredrik Noring  int r = 1;
2e30282000-10-10Martin Stjernholm  from = roxen_path( from + "x" ); // "x" keeps roxen_path from stripping trailing '/'.
20bcc72000-03-13Martin Nilsson  array(string) f=(from/"/"); string b="";
eec9801997-04-01Per Hedbor 
e30cf42000-03-13Per Hedbor 
20bcc72000-03-13Martin Nilsson  foreach(f[0..sizeof(f)-2], string a)
eec9801997-04-01Per Hedbor  {
9b62231999-06-21Martin Stjernholm  if (query_num_arg() > 1) { mkdir(b+a, mode);
850eda1997-09-06Henrik Grubbström (Grubba) #if constant(chmod)
7e9b452001-01-14Per Hedbor  Stdio.Stat stat = file_stat (b + a, 1);
9b62231999-06-21Martin Stjernholm  if (stat && stat[0] & ~mode)
73c22e2002-05-21Henrik Grubbström (Grubba)  // Race here. Not much we can do about it at this point. :/
6d6bc82001-06-24Martin Nilsson  catch (chmod (b+a, [int]stat[0] & mode));
9b62231999-06-21Martin Stjernholm #endif
850eda1997-09-06Henrik Grubbström (Grubba)  }
9b62231999-06-21Martin Stjernholm  else mkdir(b+a);
eec9801997-04-01Per Hedbor  b+=a+"/"; }
8ef6ca1998-02-14Fredrik Noring  if(!r) return (file_stat(from)||({0,0}))[1] == -2; return 1;
eec9801997-04-01Per Hedbor }
09ff051998-10-03Henrik Grubbström (Grubba) // Roxen itself
8f81d82001-01-03Per Hedbor 
19924b2001-08-24Martin Nilsson //! @ignore
6d6bc82001-06-24Martin Nilsson class Roxen { mixed query(string); void nwrite(string, int|void, int|void, void|mixed ...); }
19924b2001-08-24Martin Nilsson //! @endignore
6d6bc82001-06-24Martin Nilsson  Roxen roxen;
09ff051998-10-03Henrik Grubbström (Grubba)  // The function used to report notices/debug/errors etc.
20bcc72000-03-13Martin Nilsson function(string, int|void, int|void, void|mixed ...:void) nwrite;
22aeb61998-01-17Henrik Grubbström (Grubba) 
8b32892003-03-02Anders Johansson // Standin for nwrite until roxen is loaded. void early_nwrite(string s, int|void perr, int|void errtype, object|void mod, object|void conf) { report_debug(s); }
22aeb61998-01-17Henrik Grubbström (Grubba) 
09ff051998-10-03Henrik Grubbström (Grubba) /* * Code to get global configuration variable values from Roxen. */
22aeb61998-01-17Henrik Grubbström (Grubba) 
58a6431999-12-20Martin Nilsson mixed query(string arg)
22aeb61998-01-17Henrik Grubbström (Grubba) { if(!roxen) error("No roxen object!\n");
7ba70c2000-07-09Per Hedbor  return roxen->query( arg );
22aeb61998-01-17Henrik Grubbström (Grubba) }
a6ef1f2000-03-28Johan Sundström // used for debug messages. Sent to the administration interface and STDERR.
22aeb61998-01-17Henrik Grubbström (Grubba) void init_logger() {
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
22aeb61998-01-17Henrik Grubbström (Grubba)  int res; use_syslog = !! (query("LogA") == "syslog"); switch(query("LogST")) { case "Daemon": res = LOG_DAEMON; break;
58a6431999-12-20Martin Nilsson  case "Local 0": res = LOG_LOCAL; break;
22aeb61998-01-17Henrik Grubbström (Grubba)  case "Local 1": res = LOG_LOCAL1; break; case "Local 2": res = LOG_LOCAL2; break; case "Local 3": res = LOG_LOCAL3; break; case "Local 4": res = LOG_LOCAL4; break; case "Local 5": res = LOG_LOCAL5; break; case "Local 6": res = LOG_LOCAL6; break; case "Local 7": res = LOG_LOCAL7; break; case "User": res = LOG_USER; break; }
58a6431999-12-20Martin Nilsson 
22aeb61998-01-17Henrik Grubbström (Grubba)  loggingfield=0; switch(query("LogWH")) { /* Fallthrouh intentional */ case "All": loggingfield = loggingfield | LOG_INFO | LOG_NOTICE; case "Debug": loggingfield = loggingfield | LOG_DEBUG; case "Warnings": loggingfield = loggingfield | LOG_WARNING; case "Errors": loggingfield = loggingfield | LOG_ERR; case "Fatal": loggingfield = loggingfield | LOG_EMERG; } closelog();
20bcc72000-03-13Martin Nilsson  openlog([string]query("LogNA"), ([int]query("LogSP")*LOG_PID)|([int]query("LogCO")*LOG_CONS),
58a6431999-12-20Martin Nilsson  res);
22aeb61998-01-17Henrik Grubbström (Grubba) #endif }
c423772009-03-24Henrik Grubbström (Grubba) void report_debug(sprintf_format message, sprintf_args ... foo)
19924b2001-08-24Martin Nilsson //! @appears report_debug
2e38602000-07-14Johan Sundström //! Print a debug message in the server's debug log.
19924b2001-08-24Martin Nilsson //! Shares argument prototype with @[sprintf()].
22aeb61998-01-17Henrik Grubbström (Grubba) {
58a6431999-12-20Martin Nilsson  if( sizeof( foo ) )
23414a2000-07-21Andreas Lange  message = sprintf((string)message, @foo );
c5e0961999-10-04Per Hedbor  roxen_perror( message );
22aeb61998-01-17Henrik Grubbström (Grubba) }
e99fd41999-11-17Per Hedbor 
8ad9292000-03-13Martin Nilsson array(object) find_module_and_conf_for_log( array(array) q )
e99fd41999-11-17Per Hedbor { object conf, mod;
2dd6c12000-04-05Martin Stjernholm  for( int i = sizeof (q); i-- > 0; )
e99fd41999-11-17Per Hedbor  {
29c5a52000-03-24Per Hedbor  if(!functionp([function]q[i][2])) continue;
8ad9292000-03-13Martin Nilsson  object o = function_object( [function]q[i][2] );
29c5a52000-03-24Per Hedbor  if(!o) continue;
b69ee72000-03-09Martin Stjernholm  if( o->is_module ) {
37d8812000-02-24Per Hedbor  if( !mod ) mod = o;
b69ee72000-03-09Martin Stjernholm  if (!conf && functionp (mod->my_configuration))
8ad9292000-03-13Martin Nilsson  conf = ([function(void:object)]mod->my_configuration)();
b69ee72000-03-09Martin Stjernholm  } if( o->is_configuration ) { if( !conf ) conf = o; }
2dd6c12000-04-05Martin Stjernholm  if( conf )
37d8812000-02-24Per Hedbor  break;
e99fd41999-11-17Per Hedbor  } return ({ mod,conf }); }
1d6f412009-12-20Martin Stjernholm protected void syslog_report (string message, int level) {
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
1d6f412009-12-20Martin Stjernholm  if(use_syslog && (loggingfield&level))
c5b9512009-12-20Martin Stjernholm  foreach(message/"\n", message) syslog(level, replace(message+"\n", "%", "%%"));
1d6f412009-12-20Martin Stjernholm #endif }
e99fd41999-11-17Per Hedbor 
4dd3371999-11-23Per Hedbor #define MC @find_module_and_conf_for_log(backtrace())
e99fd41999-11-17Per Hedbor 
c423772009-03-24Henrik Grubbström (Grubba) void report_warning(LocaleString|sprintf_format message, sprintf_args ... foo)
19924b2001-08-24Martin Nilsson //! @appears report_warning
2e38602000-07-14Johan Sundström //! Report a warning message, that will show up in the server's debug log and //! in the event logs, along with the yellow exclamation mark warning sign.
19924b2001-08-24Martin Nilsson //! Shares argument prototype with @[sprintf()].
c5b9512009-12-20Martin Stjernholm //! //! @seealso //! @[report_warning_sparsely], @[report_warning_for]
22aeb61998-01-17Henrik Grubbström (Grubba) {
23414a2000-07-21Andreas Lange  if( sizeof( foo ) ) message = sprintf((string)message, @foo );
6d6bc82001-06-24Martin Nilsson  nwrite([string]message,0,2,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
1d6f412009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_WARNING);
ea803c2010-01-11Jonas Wallden #endif
22aeb61998-01-17Henrik Grubbström (Grubba) }
c423772009-03-24Henrik Grubbström (Grubba) void report_notice(LocaleString|sprintf_format message, sprintf_args ... foo)
19924b2001-08-24Martin Nilsson //! @appears report_notice
2e38602000-07-14Johan Sundström //! Report a status message of some sort for the server's debug log and event //! logs, along with the blue informational notification sign. Shares argument
19924b2001-08-24Martin Nilsson //! prototype with @[sprintf()].
c5b9512009-12-20Martin Stjernholm //! //! @seealso //! @[report_notice_for]
22aeb61998-01-17Henrik Grubbström (Grubba) {
23414a2000-07-21Andreas Lange  if( sizeof( foo ) ) message = sprintf((string)message, @foo );
6d6bc82001-06-24Martin Nilsson  nwrite([string]message,0,1,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
1d6f412009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_NOTICE);
ea803c2010-01-11Jonas Wallden #endif
22aeb61998-01-17Henrik Grubbström (Grubba) }
c423772009-03-24Henrik Grubbström (Grubba) void report_error(LocaleString|sprintf_format message, sprintf_args ... foo)
19924b2001-08-24Martin Nilsson //! @appears report_error
2e38602000-07-14Johan Sundström //! Report an error message, that will show up in the server's debug log and //! in the event logs, along with the red exclamation mark sign. Shares
19924b2001-08-24Martin Nilsson //! argument prototype with @[sprintf()].
c5b9512009-12-20Martin Stjernholm //! //! @seealso //! @[report_error_sparsely], @[report_error_for]
22aeb61998-01-17Henrik Grubbström (Grubba) {
23414a2000-07-21Andreas Lange  if( sizeof( foo ) ) message = sprintf((string)message, @foo );
6d6bc82001-06-24Martin Nilsson  nwrite([string]message,0,3,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
1d6f412009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_ERR);
ea803c2010-01-11Jonas Wallden #endif
22aeb61998-01-17Henrik Grubbström (Grubba) }
c423772009-03-24Henrik Grubbström (Grubba) void report_fatal(sprintf_format message, sprintf_args ... foo)
19924b2001-08-24Martin Nilsson //! @appears report_fatal //! Print a fatal error message.
c5b9512009-12-20Martin Stjernholm //! //! @seealso //! @[report_fatal_for]
22aeb61998-01-17Henrik Grubbström (Grubba) {
23414a2000-07-21Andreas Lange  if( sizeof( foo ) ) message = sprintf((string)message, @foo );
4dd3371999-11-23Per Hedbor  nwrite(message,0,3,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
1d6f412009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_EMERG);
ea803c2010-01-11Jonas Wallden #endif
22aeb61998-01-17Henrik Grubbström (Grubba) }
09ff051998-10-03Henrik Grubbström (Grubba) 
c5b9512009-12-20Martin Stjernholm void report_warning_for (object/*(Configuration|RoxenModule)*/ where, LocaleString|sprintf_format message, sprintf_args ... args) //! @appears report_warning_for //! See @[report_error_for]. { if (sizeof (args)) message = sprintf (message, @args); nwrite (message, 0, 2, where && where->is_module && where, where && where->is_configuration && where);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c5b9512009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_WARNING);
ea803c2010-01-11Jonas Wallden #endif
c5b9512009-12-20Martin Stjernholm } void report_notice_for (object/*(Configuration|RoxenModule)*/ where, LocaleString|sprintf_format message, sprintf_args ... args) //! @appears report_notice_for //! See @[report_error_for]. { if (sizeof (args)) message = sprintf (message, @args); nwrite (message, 0, 1, where && where->is_module && where, where && where->is_configuration && where);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c5b9512009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_NOTICE);
ea803c2010-01-11Jonas Wallden #endif
c5b9512009-12-20Martin Stjernholm } void report_error_for (object/*(Configuration|RoxenModule)*/ where, LocaleString|sprintf_format message, sprintf_args ... args) //! @appears report_error_for //! Like @[report_error], but logs the message for the given //! configuration or Roxen module @[where], or globally if @[where] is //! zero. @[report_error] searches the call stack to find that out, //! but this function is useful to specify it explicitly. { if (sizeof (args)) message = sprintf (message, @args); nwrite (message, 0, 3, where && where->is_module && where, where && where->is_configuration && where);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c5b9512009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_ERR);
ea803c2010-01-11Jonas Wallden #endif
c5b9512009-12-20Martin Stjernholm } void report_fatal_for (object/*(Configuration|RoxenModule)*/ where, LocaleString|sprintf_format message, sprintf_args ... args) //! @appears report_fatal_for //! See @[report_error_for]. { if (sizeof (args)) message = sprintf (message, @args); nwrite (message, 0, 3, where && where->is_module && where, where && where->is_configuration && where);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c5b9512009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_EMERG);
ea803c2010-01-11Jonas Wallden #endif
c5b9512009-12-20Martin Stjernholm }
fc40392008-08-15Martin Stjernholm protected mapping(string:int) sparsely_dont_log = (garb_sparsely_dont_log(), ([]));
b00dfe2001-02-05Martin Stjernholm 
fc40392008-08-15Martin Stjernholm protected void garb_sparsely_dont_log()
b00dfe2001-02-05Martin Stjernholm { if (sparsely_dont_log && sizeof (sparsely_dont_log)) { int now = time (1);
893cae2012-07-02Martin Stjernholm  foreach (sparsely_dont_log; string msg; int ts) if (ts < now) m_delete (sparsely_dont_log, msg);
b00dfe2001-02-05Martin Stjernholm  }
893cae2012-07-02Martin Stjernholm  call_out (garb_sparsely_dont_log, 20*60);
b00dfe2001-02-05Martin Stjernholm }
c423772009-03-24Henrik Grubbström (Grubba) void report_warning_sparsely (LocaleString|sprintf_format message, sprintf_args ... args)
19924b2001-08-24Martin Nilsson //! @appears report_warning_sparsely
b00dfe2001-02-05Martin Stjernholm //! Like @[report_warning], but doesn't repeat the same message if //! it's been logged in the last ten minutes. Useful in situations //! where an error can cause a warning message to be logged rapidly. { if( sizeof( args ) ) message = sprintf((string)message, @args ); int now = time (1); if (sparsely_dont_log[message] >= now) return; sparsely_dont_log[message] = now + 10*60;
6d6bc82001-06-24Martin Nilsson  nwrite([string]message,0,2,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c9182f2009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_WARNING);
ea803c2010-01-11Jonas Wallden #endif
b00dfe2001-02-05Martin Stjernholm }
c423772009-03-24Henrik Grubbström (Grubba) void report_error_sparsely (LocaleString|sprintf_format message, sprintf_args ... args)
19924b2001-08-24Martin Nilsson //! @appears report_error_sparsely
b00dfe2001-02-05Martin Stjernholm //! Like @[report_error], but doesn't repeat the same message if it's //! been logged in the last ten minutes. Useful in situations where an //! error can cause an error message to be logged rapidly. { if( sizeof( args ) ) message = sprintf((string)message, @args ); int now = time (1);
893cae2012-07-02Martin Stjernholm  if (sparsely_dont_log[message] >= now) return; sparsely_dont_log[message] = now + 10*60;
6d6bc82001-06-24Martin Nilsson  nwrite([string]message,0,3,MC);
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(syslog)
c9182f2009-12-20Martin Stjernholm  if (use_syslog) syslog_report (message, LOG_ERR);
ea803c2010-01-11Jonas Wallden #endif
b00dfe2001-02-05Martin Stjernholm }
19924b2001-08-24Martin Nilsson //! @appears popen //! Starts the specified process and returns a string //! with the result. Mostly a compatibility functions, uses
92ced82011-09-12Henrik Grubbström (Grubba) //! Process.Process
533be82009-02-17Martin Stjernholm //! //! If @[cmd] is a string then it's interpreted as a command line with //! glob expansion, argument splitting, etc according to the command //! shell rules on the system. If it's an array of strings then it's //! taken as processed argument list and is sent to
92ced82011-09-12Henrik Grubbström (Grubba) //! @[Process.Process] as-is.
533be82009-02-17Martin Stjernholm string popen(string|array(string) cmd, void|mapping env, int|void uid, int|void gid)
5e89211997-02-13Per Hedbor {
3e3bab2001-01-19Per Hedbor  Stdio.File f = Stdio.File(), p = f->pipe(Stdio.PROP_IPC);
fa13be1998-05-28Henrik Grubbström (Grubba) 
3e3bab2001-01-19Per Hedbor  if(!p) error("Popen failed. (could not create pipe)\n");
7e6d461998-01-20Henrik Grubbström (Grubba) 
20bcc72000-03-13Martin Nilsson  mapping(string:mixed) opts = ([
c79b261998-02-05Johan Schön  "env": (env || getenv()),
fa13be1998-05-28Henrik Grubbström (Grubba)  "stdout":p,
99bf7d1998-01-16Henrik Grubbström (Grubba)  ]);
22aeb61998-01-17Henrik Grubbström (Grubba) 
3e3bab2001-01-19Per Hedbor  if (!getuid()) { switch(query_num_arg()) {
fa13be1998-05-28Henrik Grubbström (Grubba)  case 4: opts->gid = gid; case 3: opts->uid = uid; break; } }
6e88541999-02-16Per Hedbor  opts->noinitgroups = 1;
533be82009-02-17Martin Stjernholm  if (stringp (cmd)) {
7f82482001-12-19Henrik Grubbström (Grubba) #if defined(__NT__) || defined(__amigaos__)
533be82009-02-17Martin Stjernholm  cmd = Process.split_quoted_string(cmd);
7f82482001-12-19Henrik Grubbström (Grubba) #else /* !__NT||__amigaos__ */
533be82009-02-17Martin Stjernholm  cmd = ({"/bin/sh", "-c", cmd});
7f82482001-12-19Henrik Grubbström (Grubba) #endif /* __NT__ || __amigaos__ */
533be82009-02-17Martin Stjernholm  } Process.Process proc = Process.Process (cmd, opts);
fa13be1998-05-28Henrik Grubbström (Grubba)  p->close();
3e3bab2001-01-19Per Hedbor  if( proc )
b796b51998-11-18Per Hedbor  {
3e3bab2001-01-19Per Hedbor  string t = f->read();
fa13be1998-05-28Henrik Grubbström (Grubba)  f->close(); destruct(f);
99bf7d1998-01-16Henrik Grubbström (Grubba)  return t; }
fa13be1998-05-28Henrik Grubbström (Grubba)  f->close(); destruct(f);
99bf7d1998-01-16Henrik Grubbström (Grubba)  return 0;
5e89211997-02-13Per Hedbor }
19924b2001-08-24Martin Nilsson //! @appears spawne //! Create a process
3e3bab2001-01-19Per Hedbor Process.Process spawne(string s, array(string) args, mapping|array env, Stdio.File stdin, Stdio.File stdout, Stdio.File stderr, void|string wd, void|array(int) uid)
5e89211997-02-13Per Hedbor {
8afc811998-02-04Per Hedbor  int u, g;
58a6431999-12-20Martin Nilsson  if(uid) { u = uid[0]; g = uid[1]; }
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(geteuid)
c5e0961999-10-04Per Hedbor  else { u=geteuid(); g=getegid(); }
c79b261998-02-05Johan Schön #endif
92ced82011-09-12Henrik Grubbström (Grubba)  return Process.Process(({s}) + (args || ({})), ([
99bf7d1998-01-16Henrik Grubbström (Grubba)  "toggle_uid":1, "stdin":stdin, "stdout":stdout, "stderr":stderr, "cwd":wd,
8afc811998-02-04Per Hedbor  "env":env, "uid":u, "gid":g,
99bf7d1998-01-16Henrik Grubbström (Grubba)  ]));
5e89211997-02-13Per Hedbor }
19924b2001-08-24Martin Nilsson //! @appears spawn_pike //! Start a new Pike process with the same configuration as the current one
3e3bab2001-01-19Per Hedbor Process.Process spawn_pike(array(string) args, void|string wd, Stdio.File|void stdin, Stdio.File|void stdout, Stdio.File|void stderr)
51ff831997-05-13Marcus Comstedt {
2b01a42009-01-09Martin Stjernholm  array(string) cmd = ({
06c5062000-06-29Fredrik Noring #ifndef __NT__
2b01a42009-01-09Martin Stjernholm  getcwd()+"/start",
06c5062000-06-29Fredrik Noring #else /* __NT__ */
2b01a42009-01-09Martin Stjernholm  getcwd()+"/../ntstart.exe",
06c5062000-06-29Fredrik Noring #endif /* __NT__ */
2b01a42009-01-09Martin Stjernholm  }); if (wd) cmd += ({"--cd", wd}); cmd += ({"--quiet","--program"}) + args;
92ced82011-09-12Henrik Grubbström (Grubba)  return Process.Process (cmd, (["toggle_uid":1, "stdin":stdin, "stdout":stdout, "stderr":stderr]));
51ff831997-05-13Marcus Comstedt }
09ff051998-10-03Henrik Grubbström (Grubba) // Add a few cache control related efuns
fc40392008-08-15Martin Stjernholm private object initiate_cache()
b1fca01996-11-12Per Hedbor { object cache;
82f5191997-03-02Per Hedbor  cache=((program)"base_server/cache")();
62b3c42000-08-12Per Hedbor  add_constant("http_decode_string", _Roxen.http_decode_string );
42c5a02007-09-06Henrik Grubbström (Grubba)  add_constant("cache_clear_deltas", cache->cache_clear_deltas);
425fc62000-09-21Per Hedbor  add_constant("cache_set", cache->cache_set);
b1fca01996-11-12Per Hedbor  add_constant("cache_lookup", cache->cache_lookup);
1353182009-11-12Martin Stjernholm  add_constant("cache_peek", cache->cache_peek);
b1fca01996-11-12Per Hedbor  add_constant("cache_remove", cache->cache_remove);
f6d62d1997-03-26Per Hedbor  add_constant("cache_expire", cache->cache_expire);
c938b32012-07-10Jonas Wallden  add_constant("cache_expire_by_prefix", cache->cache_expire_by_prefix);
425fc62000-09-21Per Hedbor  add_constant("cache_clear", cache->cache_expire);
8f23182009-12-09Martin Stjernholm  add_constant("cache_entries",cache->cache_entries);
425fc62000-09-21Per Hedbor  add_constant("cache_indices",cache->cache_indices);
79c3d72011-03-15Martin Stjernholm  add_constant("CacheEntry", cache->CacheEntry); // For cache_entries typing.
4d1c5f2001-07-26Martin Stjernholm  return cache;
b1fca01996-11-12Per Hedbor }
8ad9292000-03-13Martin Nilsson class _error_handler {
02a63f2000-09-05Per Hedbor  void compile_error(string a,int b,string c); void compile_warning(string a,int b,string c);
8ad9292000-03-13Martin Nilsson } array(_error_handler) compile_error_handlers = ({}); void push_compile_error_handler( _error_handler q )
40dd281999-11-23Per Hedbor {
6465b92000-09-27Per Hedbor  if( q->do_not_push )
ddb2d92000-11-13Per Hedbor  {
b86de82000-11-13Per Hedbor  master()->set_inhibit_compile_errors( q );
ddb2d92000-11-13Per Hedbor  compile_error_handlers = ({0})+compile_error_handlers; } else compile_error_handlers = ({q})+compile_error_handlers;
40dd281999-11-23Per Hedbor } void pop_compile_error_handler() {
8a54832004-05-14Martin Stjernholm  if( !compile_error_handlers[0] )
ddb2d92000-11-13Per Hedbor  { master()->set_inhibit_compile_errors(0);
b86de82000-11-13Per Hedbor  return;
ddb2d92000-11-13Per Hedbor  }
40dd281999-11-23Per Hedbor  compile_error_handlers = compile_error_handlers[1..]; } class LowErrorContainer
256d281999-11-04Henrik Grubbström (Grubba) { string d;
17d6d12000-03-30Per Hedbor  string errors="", warnings="";
b86de82000-11-13Per Hedbor  constant do_not_push = 0;
256d281999-11-04Henrik Grubbström (Grubba)  string get() { return errors; }
17d6d12000-03-30Per Hedbor  string get_warnings() { return warnings; } void got_error(string file, int line, string err, int|void is_warning)
256d281999-11-04Henrik Grubbström (Grubba)  {
cefd172011-12-27Martin Stjernholm  if (has_prefix (file, d)) file = file[sizeof(d)..]; if (has_prefix (file, server_dir)) file = file[sizeof(server_dir)..];
17d6d12000-03-30Per Hedbor  if( is_warning) warnings+= sprintf("%s:%s\t%s\n", file, line ? (string) line : "-", err); else errors += sprintf("%s:%s\t%s\n", file, line ? (string) line : "-", err);
256d281999-11-04Henrik Grubbström (Grubba)  } void compile_error(string file, int line, string err) { got_error(file, line, "Error: " + err); } void compile_warning(string file, int line, string err) {
17d6d12000-03-30Per Hedbor  got_error(file, line, "Warning: " + err, 1);
256d281999-11-04Henrik Grubbström (Grubba)  } void create() { d = getcwd();
40dd281999-11-23Per Hedbor  if (sizeof(d) && (d[-1] != '/') && (d[-1] != '\\'))
256d281999-11-04Henrik Grubbström (Grubba)  d += "/";
40dd281999-11-23Per Hedbor  } }
19924b2001-08-24Martin Nilsson //! @appears ErrorContainer
40dd281999-11-23Per Hedbor class ErrorContainer { inherit LowErrorContainer;
6465b92000-09-27Per Hedbor  constant do_not_push = 1;
40dd281999-11-23Per Hedbor  void compile_error(string file, int line, string err) { if( sizeof(compile_error_handlers) )
ddb2d92000-11-13Per Hedbor  (compile_error_handlers-({0}))->compile_error( file,line, err ); ::compile_error(file,line,err);
40dd281999-11-23Per Hedbor  } void compile_warning(string file, int line, string err) { if( sizeof(compile_error_handlers) )
ddb2d92000-11-13Per Hedbor  (compile_error_handlers-({0}))->compile_warning( file,line, err ); ::compile_warning(file,line,err);
40dd281999-11-23Per Hedbor  }
256d281999-11-04Henrik Grubbström (Grubba) }
19924b2001-08-24Martin Nilsson //! @decl int cd(string path) //! @appears cd //! Overloads the Pike cd function. //! Doesn't allow cd() unless we are in a forked child.
a4031a1997-09-17Henrik Grubbström (Grubba) class restricted_cd { int locked_pid = getpid(); int `()(string path) { if (locked_pid == getpid()) {
d673402002-01-28Martin Stjernholm  error ("Use of cd() is restricted.\n");
a4031a1997-09-17Henrik Grubbström (Grubba)  } return cd(path); } }
09ff051998-10-03Henrik Grubbström (Grubba) // Fallback efuns.
c79b261998-02-05Johan Schön #if !constant(getuid) int getuid(){ return 17; } int getgid(){ return 42; } #endif
f0e0e61998-03-20Per Hedbor 
6258202013-03-11Henrik Grubbström (Grubba) #if constant(Crypto.Password) // Pike 7.9 and later. constant verify_password = Crypto.Password.verify; constant crypt_password = Crypto.Password.hash; #else /* !Crypto.Password */
e240552013-03-08Henrik Grubbström (Grubba) //! @appears verify_password //! //! Verify a password against a hash. //! //! This function attempts to support most //! password hashing schemes. //! //! @returns //! Returns @expr{1@} on success, and @expr{0@} (zero) otherwise. //! //! @seealso //! @[hash_password()], @[predef::crypt()] int verify_password(string password, string hash) { if (hash == "") return 1; // Detect the password hashing scheme. // First check for an LDAP-style marker. string scheme = "crypt"; sscanf(hash, "{%s}%s", scheme, hash); // NB: RFC2307 proscribes lower case schemes, while // in practise they are usually in upper case. switch(lower_case(scheme)) { case "md5": // RFC 2307 case "smd5": hash = MIME.decode_base64(hash); password += hash[16..]; hash = hash[..15]; return Crypto.MD5.hash(password) == hash; case "sha": // RFC 2307 case "ssha": // SHA1 and Salted SHA1. hash = MIME.decode_base64(hash); password += hash[20..]; hash = hash[..19]; return Crypto.SHA1.hash(password) == hash; case "crypt": // RFC 2307 // First try the operating system's crypt(3C). if ((hash == "") || crypt(password, hash)) return 1; if (hash[0] != '$') { if (hash[0] == '_') { // FIXME: BSDI-style crypt(3C). } return 0; } // Then try our implementations. sscanf(hash, "$%s$%s$%s", scheme, string salt, string hash); int rounds = UNDEFINED; if (has_prefix(salt, "rounds=")) { sscanf(salt, "rounds=%d", rounds); sscanf(hash, "%s$%s", salt, hash); } switch(scheme) { case "1": // crypt_md5 return Nettle.crypt_md5(password, salt) == hash; case "2": // Blowfish (obsolete) case "2a": // Blowfish (possibly weak) case "2x": // Blowfish (weak) case "2y": // Blowfish (stronger) break; case "3": // MD4 NT LANMANAGER (FreeBSD) break; #if constant(Crypto.SHA256.crypt_hash) // cf http://www.akkadia.org/drepper/SHA-crypt.txt case "5": // SHA-256 return Crypto.SHA256.crypt_hash(password, salt, rounds) == hash; #endif #if constant(Crypto.SHA512.crypt_hash) case "6": // SHA-512 return Crypto.SHA512.crypt_hash(password, salt, rounds) == hash; #endif } break; } return 0; } //! @appears crypt_password //! //! Generate a hash of @[password] suitable for @[verify_password()]. //! //! @param password //! Password to hash. //! //! @param scheme //! Password hashing scheme. If not specified the strongest available //! will be used. //! //! If an unsupported scheme is specified an error will be thrown. //! //! @param rounds //! The number of rounds to use in parameterized schemes. If not //! specified the scheme specific default will be used. //! //! @returns //! Returns a string suitable for @[verify_password()]. //! //! @seealso //! @[verify_password], @[predef::crypt()], @[Nettle.crypt_md5()], //! @[Nettle.HashInfo()->crypt_hash()] string crypt_password(string password, string|void scheme, int|void rounds) { function(string, string, int:string) crypt_hash; int salt_size = 16; int default_rounds = 5000; switch(scheme) { case UNDEFINED: // FALL_THROUGH #if constant(Crypto.SHA512.crypt_hash) case "6": case "$6$": crypt_hash = Crypto.SHA512.crypt_hash; scheme = "6"; break; #endif #if constant(Crypto.SHA256.crypt_hash) case "5": case "$5$": crypt_hash = Crypto.SHA256.crypt_hash; scheme = "5"; break; #endif #if constant(Crypto.MD5.crypt_hash) case "1": case "$1$": crypt_hash = Crypto.MD5.crypt_hash; salt_size = 8; rounds = 1000; // Currently only 1000 rounds is supported. default_rounds = 1000; scheme = "1"; break; #endif case "": return crypt(password); // FIXME: Add support for SSHA? default: error("Unsupported hashing scheme: %O\n", scheme); } if (!rounds) rounds = default_rounds; // NB: The salt must be printable. string salt = MIME.encode_base64(Crypto.Random.random_string(salt_size))[..salt_size-1]; string hash = crypt_hash(password, salt, rounds); if (rounds != default_rounds) { salt = "rounds=" + rounds + "$" + salt; } return sprintf("$%s$%s$%s", scheme, salt, hash); }
6258202013-03-11Henrik Grubbström (Grubba) #endif /* !Crypto.Password */
e240552013-03-08Henrik Grubbström (Grubba) 
e41c9d2017-04-21Henrik Grubbström (Grubba) #ifdef THREADS // This mutex is used by Privs Thread.Mutex euid_egid_lock = Thread.Mutex(); #endif /* THREADS */ // Needed to get core dumps of seteuid()'ed processes on Linux. #if constant(System.dumpable) #define enable_coredumps(X) System.dumpable(X) #else #define enable_coredumps(X) #endif /* * The privilege changer. Works like a mutex lock, but changes the UID/GID * while held. Blocks all threads. * * Based on privs.pike,v 1.36. */ int privs_level; protected class Privs { #if constant(seteuid) int saved_uid; int saved_gid; int new_uid; int new_gid; #define LOGP (roxen->variables && roxen->variables->audit && roxen->variables->audit->query()) #if constant(geteuid) && constant(getegid) && constant(seteuid) && constant(setegid) #define HAVE_EFFECTIVE_USER #endif private string _getcwd() { if (catch{return(getcwd());}) { return("Unknown directory (no x-bit on current directory?)"); } } private string dbt(array t) { if(!arrayp(t) || (sizeof(t)<2)) return ""; return (((t[0]||"Unknown program")-(_getcwd()+"/"))-"base_server/")+":"+t[1]+"\n"; } #ifdef THREADS protected mixed mutex_key; // Only one thread may modify the euid/egid at a time. protected object threads_disabled; #endif /* THREADS */ int p_level; void create(string reason, int|string|void uid, int|string|void gid) { // No need for Privs if the uid has been changed permanently. if(getuid()) return; #ifdef PRIVS_DEBUG report_debug(sprintf("Privs(%O, %O, %O)\n" "privs_level: %O\n", reason, uid, gid, privs_level)); #endif /* PRIVS_DEBUG */ #ifdef HAVE_EFFECTIVE_USER array u; #ifdef THREADS if (euid_egid_lock) { if (mixed err = catch { mutex_key = euid_egid_lock->lock(); }) master()->handle_error (err); } threads_disabled = _disable_threads(); #endif /* THREADS */ p_level = privs_level++; /* Needs to be here since root-priviliges may be needed to * use getpw{uid,nam}. */ saved_uid = geteuid(); saved_gid = getegid(); seteuid(0); /* A string of digits? */ if(stringp(uid) && (replace(uid,"0123456789"/"",({""})*10)=="")) uid = (int)uid; if(stringp(gid) && (replace(gid, "0123456789"/"", ({"" })*10) == "")) gid = (int)gid; if(!stringp(uid)) u = getpwuid(uid); else { u = getpwnam(uid); if(u) uid = u[2]; } if(u && !gid) gid = u[3]; if(!u) { if (uid && (uid != "root")) { if (intp(uid) && (uid >= 60000)) { report_warning(sprintf("Privs: User %d is not in the password database.\n" "Assuming nobody.\n", uid)); // Nobody. gid = gid || uid; // Fake a gid also. u = ({ "fake-nobody", "x", uid, gid, "A real nobody", "/", "/sbin/sh" }); } else { error("Unknown user: "+uid+"\n"); } } else { u = ({ "root", "x", 0, gid, "The super-user", "/", "/sbin/sh" }); } } if(LOGP) report_notice(LOC_M(1, "Change to %s(%d):%d privs wanted (%s), from %s"), (string)u[0], (int)uid, (int)gid, (string)reason, (string)dbt(backtrace()[-2])); if (u[2]) { #if constant(cleargroups) if (mixed err = catch { cleargroups(); }) master()->handle_error (err); #endif /* cleargroups */ #if constant(initgroups) if (mixed err = catch { initgroups(u[0], u[3]); }) master()->handle_error (err); #endif } gid = gid || getgid(); int err = (int)setegid(new_gid = gid); if (err < 0) { report_warning(LOC_M(2, "Privs: WARNING: Failed to set the " "effective group id to %d!\n" "Check that your password database is correct " "for user %s(%d),\n and that your group " "database is correct.\n"), gid, (string)u[0], (int)uid); int gid2 = gid; #ifdef HPUX_KLUDGE if (gid >= 60000) { /* HPUX has doesn't like groups higher than 60000, * but has assigned nobody to group 60001 (which isn't even * in /etc/group!). * * HPUX's libc also insists on filling numeric fields it doesn't like * with the value 60001! */ report_debug("Privs: WARNING: Assuming nobody-group.\n" "Trying some alternatives...\n"); // Assume we want the nobody group, and try a couple of alternatives foreach(({ 60001, 65534, -2 }), gid2) { report_debug("%d... ", gid2); if (initgroups(u[0], gid2) >= 0) { if ((err = setegid(new_gid = gid2)) >= 0) { report_debug("Success!\n"); break; } } } } #endif /* HPUX_KLUDGE */ if (err < 0) { report_debug("Privs: Failed\n"); error ("Failed to set EGID to %d\n", gid); } report_debug("Privs: WARNING: Set egid to %d instead of %d.\n", gid2, gid); gid = gid2; } if(getgid()!=gid) setgid(gid||getgid()); seteuid(new_uid = uid); enable_coredumps(1); #endif /* HAVE_EFFECTIVE_USER */ } void destroy() { // No need for Privs if the uid has been changed permanently. if(getuid()) return; #ifdef PRIVS_DEBUG report_debug(sprintf("Privs->destroy()\n" "privs_level: %O\n", privs_level)); #endif /* PRIVS_DEBUG */ #ifdef HAVE_EFFECTIVE_USER /* Check that we don't increase the privs level */ if (p_level >= privs_level) { report_error(sprintf("Change back to uid#%d gid#%d from uid#%d gid#%d\n" "in wrong order! Saved level:%d Current level:%d\n" "Occurs in:\n%s\n", saved_uid, saved_gid, new_uid, new_gid, p_level, privs_level, describe_backtrace(backtrace()))); return(0); } if (p_level != privs_level-1) { report_error(sprintf("Change back to uid#%d gid#%d from uid#%d gid#%d\n" "Skips privs level. Saved level:%d Current level:%d\n" "Occurs in:\n%s\n", saved_uid, saved_gid, new_uid, new_gid, p_level, privs_level, describe_backtrace(backtrace()))); } privs_level = p_level; if(LOGP) { if (mixed err = catch { array bt = backtrace(); if (sizeof(bt) >= 2) { report_notice(LOC_M(3,"Change back to uid#%d gid#%d, from %s")+"\n", saved_uid, saved_gid, dbt(bt[-2])); } else { report_notice(LOC_M(4,"Change back to uid#%d gid#%d, " "from backend")+"\n", saved_uid, saved_gid); } }) master()->handle_error (err); } #ifdef PRIVS_DEBUG int uid = geteuid(); if (uid != new_uid) { report_debug("Privs: UID #%d differs from expected #%d\n" "%s\n", uid, new_uid, describe_backtrace(backtrace())); } int gid = getegid(); if (gid != new_gid) { report_debug("Privs: GID #%d differs from expected #%d\n" "%s\n", gid, new_gid, describe_backtrace(backtrace())); } #endif /* PRIVS_DEBUG */ seteuid(0); array u = getpwuid(saved_uid); #if constant(cleargroups) if (mixed err = catch { cleargroups(); }) master()->handle_error (err); #endif /* cleargroups */ if(u && (sizeof(u) > 3)) { if (mixed err = catch { initgroups(u[0], u[3]); }) master()->handle_error (err); } setegid(saved_gid); seteuid(saved_uid); enable_coredumps(1); #endif /* HAVE_EFFECTIVE_USER */ } #else /* constant(seteuid) */ void create(string reason, int|string|void uid, int|string|void gid){} #endif /* constant(seteuid) */ }
09ff051998-10-03Henrik Grubbström (Grubba) // Load Roxen for real
6d6bc82001-06-24Martin Nilsson Roxen really_load_roxen()
f0e0e61998-03-20Per Hedbor { int start_time = gethrtime();
0dd24b2003-03-06Jonas Wallden  report_debug("Loading Roxen ... \b");
6d6bc82001-06-24Martin Nilsson  Roxen res;
256d281999-11-04Henrik Grubbström (Grubba)  mixed err = catch {
8f81d82001-01-03Per Hedbor  res = ((program)"base_server/roxen.pike")();
256d281999-11-04Henrik Grubbström (Grubba)  };
40e1d62000-04-13Per Hedbor  if (err) {
56509c2001-06-30Martin Stjernholm  report_debug("\bERROR\n");
9478732000-03-06Martin Stjernholm  werror (describe_backtrace (err));
256d281999-11-04Henrik Grubbström (Grubba)  throw(err); }
56509c2001-06-30Martin Stjernholm  report_debug("\bDone [%.1fms]\n",
1d9cfb2000-02-14Per Hedbor  (gethrtime()-start_time)/1000.0);
256d281999-11-04Henrik Grubbström (Grubba) 
27942e1999-09-02Per Hedbor  res->start_time = start_time; res->boot_time = start_time;
4dd3371999-11-23Per Hedbor  nwrite = res->nwrite;
d3eaa42003-01-22Henrik Grubbström (Grubba) 
f0e0e61998-03-20Per Hedbor  return res; }
c79b261998-02-05Johan Schön 
09ff051998-10-03Henrik Grubbström (Grubba) // Debug function to trace calls to destruct().
139f4c1998-03-23Henrik Grubbström (Grubba) #ifdef TRACE_DESTRUCT void trace_destruct(mixed x)
19924b2001-08-24Martin Nilsson //! @appears destruct //! Overloads the Pike destruct function. If the webserver is //! started with the TRACE_DESTRUCT define set, all destruct //! calls will be logged in the debug log.
139f4c1998-03-23Henrik Grubbström (Grubba) {
58a6431999-12-20Martin Nilsson  report_debug("DESTRUCT(%O)\n%s\n", x, describe_backtrace(backtrace())):
139f4c1998-03-23Henrik Grubbström (Grubba)  destruct(x); } #endif /* TRACE_DESTRUCT */
c348db2003-09-15Martin Stjernholm void trace_exit (int exitcode) { catch (report_notice ("Exiting Roxen - exit(%d) called.\n", exitcode)); #ifdef TRACE_EXIT catch (report_debug (describe_backtrace (backtrace()))); #endif exit (exitcode); } constant real_exit = exit;
50b6972001-08-31Per Hedbor #define DC(X) add_dump_constant( X,nm_resolv(X) ) function add_dump_constant; mixed nm_resolv(string x ) { catch { return new_master->resolv( x ); }; return ([])[0]; };
09ff051998-10-03Henrik Grubbström (Grubba) // Set up efuns and load Roxen.
b1fca01996-11-12Per Hedbor void load_roxen() {
40e1d62000-04-13Per Hedbor // new_master->resolv("Roxen");
660eda2001-04-09Per Hedbor #if !constant( callablep ) add_constant( "callablep", lambda(mixed f){return functionp(f)||programp(f);}); #endif
a4031a1997-09-17Henrik Grubbström (Grubba)  add_constant("cd", restricted_cd());
c348db2003-09-15Martin Stjernholm  add_constant ("exit", trace_exit);
139f4c1998-03-23Henrik Grubbström (Grubba) #ifdef TRACE_DESTRUCT add_constant("destruct", trace_destruct); #endif /* TRACE_DESTRUCT */
c79b261998-02-05Johan Schön #if !constant(getppid) add_constant("getppid", getppid); #endif #if !constant(getuid) add_constant("getuid", getuid); add_constant("getgid", getgid); #endif #if !constant(gethostname) add_constant("gethostname", lambda() { return "localhost"; }); #endif
1c98e21999-10-11Martin Stjernholm  #ifndef OLD_PARSE_HTML // Temporary kludge to get wide string rxml parsing. add_constant("parse_html", parse_html); add_constant("parse_html_lines", parse_html_lines); #endif
58a6431999-12-20Martin Nilsson 
50b6972001-08-31Per Hedbor  DC( "Roxen" );
f0e0e61998-03-20Per Hedbor  roxen = really_load_roxen();
b1fca01996-11-12Per Hedbor }
1c98e21999-10-11Martin Stjernholm  #ifndef OLD_PARSE_HTML
fc40392008-08-15Martin Stjernholm protected int|string|array(string) compat_call_tag (
624dae2000-01-21Martin Stjernholm  Parser.HTML p, string str, mixed... extra) { string name = lower_case (p->tag_name()); if (string|function tag = p->m_tags[name])
20bcc72000-03-13Martin Nilsson  if (stringp (tag)) return ({[string]tag}); else return ([function(string,mapping,mixed...:string|array(string))]tag) (name, p->tag_args(), @extra);
624dae2000-01-21Martin Stjernholm  else if (string|function container = p->m_containers[name]) // A container has been added. p->add_container (name, compat_call_container); return 1; }
fc40392008-08-15Martin Stjernholm protected int|string|array(string) compat_call_container (
624dae2000-01-21Martin Stjernholm  Parser.HTML p, mapping(string:string) args, string content, mixed... extra) { string name = lower_case (p->tag_name()); if (string|function container = p->m_containers[name])
6d6bc82001-06-24Martin Nilsson  if (stringp (container)) return ({[string]container});
624dae2000-01-21Martin Stjernholm  else return container (name, args, content, @extra); else // The container has disappeared from the mapping. p->add_container (name, 0); return 1; }
9920831999-12-07Martin Stjernholm class ParseHtmlCompat
9836101999-11-23Per Hedbor {
9920831999-12-07Martin Stjernholm  inherit Parser.HTML;
9836101999-11-23Per Hedbor 
9920831999-12-07Martin Stjernholm  mapping(string:string|function) m_tags, m_containers;
9836101999-11-23Per Hedbor 
9920831999-12-07Martin Stjernholm  void create (mapping(string:string|function) tags, mapping(string:string|function) containers, mixed... extra)
9836101999-11-23Per Hedbor  {
9920831999-12-07Martin Stjernholm  m_tags = tags; m_containers = containers; add_containers (mkmapping (indices (m_containers),
624dae2000-01-21Martin Stjernholm  ({compat_call_container}) * sizeof (m_containers))); _set_tag_callback (compat_call_tag);
9920831999-12-07Martin Stjernholm  set_extra (@extra);
b215db1999-12-13Martin Stjernholm  case_insensitive_tag (1);
9920831999-12-07Martin Stjernholm  lazy_entity_end (1);
b215db1999-12-13Martin Stjernholm  match_tag (0); ignore_unknown (1);
9836101999-11-23Per Hedbor  } }
6d6bc82001-06-24Martin Nilsson string parse_html (string data, mapping(string:function|string) tags, mapping(string:function|string) containers,
9920831999-12-07Martin Stjernholm  mixed... args)
9836101999-11-23Per Hedbor {
9920831999-12-07Martin Stjernholm  return ParseHtmlCompat (tags, containers, @args)->finish (data)->read();
9836101999-11-23Per Hedbor }
fc40392008-08-15Martin Stjernholm protected int|string|array(string) compat_call_tag_lines (
624dae2000-01-21Martin Stjernholm  Parser.HTML p, string str, mixed... extra) { string name = lower_case (p->tag_name()); if (string|function tag = p->m_tags[name]) if (stringp (tag)) return ({tag}); else return tag (name, p->tag_args(), p->at_line(), @extra); else if (string|function container = p->m_containers[name]) // A container has been added. p->add_container (name, compat_call_container_lines); return 1; }
fc40392008-08-15Martin Stjernholm protected int|string|array(string) compat_call_container_lines (
624dae2000-01-21Martin Stjernholm  Parser.HTML p, mapping(string:string) args, string content, mixed... extra) { string name = lower_case (p->tag_name()); if (string|function container = p->m_containers[name])
6d6bc82001-06-24Martin Nilsson  if (stringp (container)) return ({[string]container});
624dae2000-01-21Martin Stjernholm  else return container (name, args, content, p->at_line(), @extra); else // The container has disappeared from the mapping. p->add_container (name, 0); return 1; }
9920831999-12-07Martin Stjernholm class ParseHtmlLinesCompat
9836101999-11-23Per Hedbor {
624dae2000-01-21Martin Stjernholm  inherit Parser.HTML;
9836101999-11-23Per Hedbor 
624dae2000-01-21Martin Stjernholm  mapping(string:string|function) m_tags, m_containers;
9920831999-12-07Martin Stjernholm 
624dae2000-01-21Martin Stjernholm  void create (mapping(string:string|function) tags, mapping(string:string|function) containers, mixed... extra)
9836101999-11-23Per Hedbor  {
624dae2000-01-21Martin Stjernholm  m_tags = tags; m_containers = containers; add_containers (mkmapping (indices (m_containers), ({compat_call_container_lines}) * sizeof (m_containers))); _set_tag_callback (compat_call_tag_lines); set_extra (@extra); case_insensitive_tag (1); lazy_entity_end (1); match_tag (0); ignore_unknown (1);
9836101999-11-23Per Hedbor  } }
1c98e21999-10-11Martin Stjernholm string parse_html_lines (string data, mapping tags, mapping containers, mixed... args) {
9920831999-12-07Martin Stjernholm  return ParseHtmlLinesCompat (tags, containers, @args)->finish (data)->read();
1c98e21999-10-11Martin Stjernholm } #endif
fc40392008-08-15Martin Stjernholm protected local mapping fd_marks = ([]);
19924b2001-08-24Martin Nilsson  //! @appears mark_fd
9eeb5c2000-05-22Per Hedbor mixed mark_fd( int fd, string|void with ) { if(!with) return fd_marks[ fd ]; fd_marks[fd] = with; }
1c98e21999-10-11Martin Stjernholm 
09ff051998-10-03Henrik Grubbström (Grubba) // Code to trace fd usage.
3235691998-03-26Per Hedbor #ifdef FD_DEBUG
5640d21998-03-26Per Hedbor class mf { inherit Stdio.File;
40a83a2004-08-18Henrik Grubbström (Grubba)  mixed open(string what, string mode, int|void perm)
5640d21998-03-26Per Hedbor  { int res;
40a83a2004-08-18Henrik Grubbström (Grubba)  res = ::open(what, mode, perm||0666);
5640d21998-03-26Per Hedbor  if(res) {
6a78782003-10-20Martin Stjernholm  array bt = backtrace(); string file = bt[-2][0]; int line = bt[-2][1];
40a83a2004-08-18Henrik Grubbström (Grubba)  mark_fd(query_fd(), sprintf("%s:%d open(%O, %O, 0%03o)",
4c0a7e2004-08-18Henrik Grubbström (Grubba)  file, line, what, mode, perm||0666));
5640d21998-03-26Per Hedbor  } return res; } void destroy() { catch { mark_fd(query_fd(),"CLOSED"); };
58a6431999-12-20Martin Nilsson  }
5640d21998-03-26Per Hedbor  int close(string|void what) { destroy();
112a251998-07-17Henrik Grubbström (Grubba)  if (what) { return ::close(what); } return ::close();
5640d21998-03-26Per Hedbor  } } #else constant mf = Stdio.File; #endif
e30cf42000-03-13Per Hedbor #include "../etc/include/version.h"
6aec6f2002-03-15Henrik Grubbström (Grubba) 
fc40392008-08-15Martin Stjernholm protected string release; protected string dist_version;
88edde2009-04-20Jonas Wallden protected string dist_os;
fc40392008-08-15Martin Stjernholm protected int roxen_is_cms; protected string roxen_product_name;
a01b5d2013-08-19Tobias Liin protected string roxen_product_code;
6aec6f2002-03-15Henrik Grubbström (Grubba) 
dd43892014-09-05Henrik Grubbström (Grubba) protected string mysql_product_name; protected string mysql_version; protected constant mysql_good_versions = ({ "5.5.*", "5.6.*" });
d4a26d2016-03-11Henrik Grubbström (Grubba) protected constant mariadb_good_versions = ({ "5.5.*", "10.0.*", "10.1.*" });
dd43892014-09-05Henrik Grubbström (Grubba) protected constant mysql_maybe_versions = ({ "5.*", "6.*" });
d4a26d2016-03-11Henrik Grubbström (Grubba) protected constant mariadb_maybe_versions = ({ "5.*", "10.*", "11.*" });
6aec6f2002-03-15Henrik Grubbström (Grubba) 
e30cf42000-03-13Per Hedbor string roxen_version()
19924b2001-08-24Martin Nilsson //! @appears roxen_version
e30cf42000-03-13Per Hedbor {
6aec6f2002-03-15Henrik Grubbström (Grubba)  // Note: roxen_release is usually "-cvs" at the time this is compiled.
bb1fc42008-06-24Martin Stjernholm  return roxen_ver+"."+roxen_build+(release||roxen_release);
e30cf42000-03-13Per Hedbor }
19924b2001-08-24Martin Nilsson //! @appears roxen_path //!
cefd172011-12-27Martin Stjernholm //! Expands the following paths in the given string and returns the //! result. If on Windows, also strips off trailing slashes.
19924b2001-08-24Martin Nilsson //! //! @string //! @value "$LOCALDIR"
2cc28b2010-01-13Jonas Wallden //! The local directory of the web server, Normally "../local",
19924b2001-08-24Martin Nilsson //! but it can be changed in by setting the environment //! variable LOCALDIR. //! @value "$LOGDIR"
2cc28b2010-01-13Jonas Wallden //! The log directory of the web server. Normally "../logs",
19924b2001-08-24Martin Nilsson //! but it can be changed in the configuration interface under //! global settings.
ae7fb42006-09-11Marcus Wellhardh //! @value "$LOGFILE"
2cc28b2010-01-13Jonas Wallden //! The debug log of the web server. Normally
ae7fb42006-09-11Marcus Wellhardh //! "../logs/debug/default.1", but it can be the name of the //! configuration directory if multiple instances are used.
19924b2001-08-24Martin Nilsson //! @value "$VARDIR"
2cc28b2010-01-13Jonas Wallden //! The web server's var directory. Normally "../var", but it can
19924b2001-08-24Martin Nilsson //! be changed by setting the environment variable VARDIR. //! @value "$VVARDIR"
2cc28b2010-01-13Jonas Wallden //! Same as $VARDIR, but with a server version specific subdirectory. //! @value "$SERVERDIR" //! Base path for the version-specific installation directory.
19924b2001-08-24Martin Nilsson //! @endstring
e30cf42000-03-13Per Hedbor string roxen_path( string filename ) {
2cc28b2010-01-13Jonas Wallden  filename = replace( filename, ({"$VVARDIR","$LOCALDIR","$LOGFILE","$SERVERDIR"}),
4f862f2000-03-21Martin Nilsson  ({"$VARDIR/"+roxen_version(),
ae7fb42006-09-11Marcus Wellhardh  getenv ("LOCALDIR") || "../local",
2cc28b2010-01-13Jonas Wallden  getenv ("LOGFILE") || "$LOGDIR/debug/default.1",
cefd172011-12-27Martin Stjernholm  server_dir }) );
7ba70c2000-07-09Per Hedbor  if( roxen ) filename = replace( filename, "$LOGDIR", [string]roxen->query("logdirprefix") );
e30cf42000-03-13Per Hedbor  else if( search( filename, "$LOGDIR" ) != -1 ) roxen_perror("Warning: mkdirhier with $LOGDIR before variable is available\n");
250a842000-06-23Martin Stjernholm  filename = replace( filename, "$VARDIR", getenv ("VARDIR") || "../var" );
5ddb292000-08-22Per Hedbor #ifdef __NT__ while( strlen(filename) && filename[-1] == '/' ) filename = filename[..strlen(filename)-2]; #endif
e30cf42000-03-13Per Hedbor  return filename; } int rm( string filename ) { return predef::rm( roxen_path(filename) ); } array(string) r_get_dir( string path )
2d3cd82011-12-28Martin Stjernholm //! @appears r_get_dir //! Like @[predef::get_dir], but processes the path with @[roxen_path].
e30cf42000-03-13Per Hedbor { return predef::get_dir( roxen_path( path ) ); } int mv( string f1, string f2 ) { return predef::mv( roxen_path(f1), roxen_path( f2 ) ); }
2d3cd82011-12-28Martin Stjernholm int r_cp( string f1, string f2 ) //! @appears r_cp //! Like @[Stdio.cp], but processes the paths with @[roxen_path]. { return Stdio.cp( roxen_path(f1), roxen_path( f2 ) ); }
7e9b452001-01-14Per Hedbor Stdio.Stat file_stat( string filename, int|void slinks )
e30cf42000-03-13Per Hedbor {
b883a72000-10-17Martin Nilsson  return predef::file_stat( roxen_path(filename), slinks );
e30cf42000-03-13Per Hedbor }
2d3cd82011-12-28Martin Stjernholm // Like the other wrappers above, the following get the "r_" prefix // when they're added as constants, so it makes no sense to have // different names for the real functions in this file. int r_is_file (string path) //! @appears r_is_file //! Like @[Stdio.is_file], but processes the path with @[roxen_path]. { return Stdio.is_file (roxen_path (path)); } int r_is_dir (string path) //! @appears r_is_dir //! Like @[Stdio.is_dir], but processes the path with @[roxen_path]. { return Stdio.is_dir (roxen_path (path)); } int r_is_link (string path) //! @appears r_is_link //! Like @[Stdio.is_link], but processes the path with @[roxen_path]. { return Stdio.is_link (roxen_path (path)); } int r_exist (string path) //! @appears r_exist //! Like @[Stdio.exist], but processes the path with @[roxen_path]. { return Stdio.exist (roxen_path (path)); } string r_read_bytes (string filename, mixed... args) //! @appears r_read_bytes //! Like @[Stdio.read_bytes], but processes the path with @[roxen_path]. { return Stdio.read_bytes (roxen_path (filename), @args); }
19924b2001-08-24Martin Nilsson //! @appears open
45e01b2011-12-28Martin Stjernholm //! Like @[Stdio.File.open] on a new file object, but processes the //! path with @[roxen_path]. Returns zero on open error.
850eda1997-09-06Henrik Grubbström (Grubba) object|void open(string filename, string mode, int|void perm)
b1fca01996-11-12Per Hedbor {
8ad9292000-03-13Martin Nilsson #ifdef FD_DEBUG mf o; #else Stdio.File o; #endif
5640d21998-03-26Per Hedbor  o=mf();
e30cf42000-03-13Per Hedbor  filename = roxen_path( filename );
8603581997-09-19Henrik Grubbström (Grubba)  if(!(o->open(filename, mode, perm||0666))) {
2bfae41997-12-04Henrik Grubbström (Grubba)  // EAGAIN, ENOMEM, ENFILE, EMFILE, EAGAIN(FreeBSD) if ((< 11, 12, 23, 24, 35 >)[o->errno()]) { // Let's see if the garbage-collector can free some fd's gc(); // Retry... if(!(o->open(filename, mode, perm||0666))) { destruct(o); return; }
0025051997-12-04Henrik Grubbström (Grubba)  } else {
2e08991997-12-04Henrik Grubbström (Grubba)  destruct(o);
0025051997-12-04Henrik Grubbström (Grubba)  return;
8603581997-09-19Henrik Grubbström (Grubba)  }
b1fca01996-11-12Per Hedbor  }
7ed1021998-01-28Henrik Grubbström (Grubba)  // FIXME: Might want to stat() here to check that we don't open // devices...
8603581997-09-19Henrik Grubbström (Grubba)  return o;
b1fca01996-11-12Per Hedbor }
b395ab2008-02-05Henrik Grubbström (Grubba) array(string) default_roxen_font_path = ({ "nfonts/", #ifdef __NT__ combine_path(replace(getenv("SystemRoot"), "\\", "/"), "fonts/") #else @((getenv("RX_FONTPATH") || "")/"," - ({""})) #endif });
3c55fe2013-11-26Anders Johansson array(string) package_module_path = ({ });
b395ab2008-02-05Henrik Grubbström (Grubba)  array(string) package_directories = ({ }); void add_package(string package_dir) {
45e01b2011-12-28Martin Stjernholm  string ver = r_read_bytes(combine_path(package_dir, "VERSION"));
b395ab2008-02-05Henrik Grubbström (Grubba)  if (ver && (ver != "")) {
01d6602012-01-03Martin Stjernholm  report_debug("Adding package %s (Version %s).\n", roxen_path (package_dir), ver - "\n");
b395ab2008-02-05Henrik Grubbström (Grubba)  } else {
01d6602012-01-03Martin Stjernholm  report_debug("Adding package %s.\n", roxen_path (package_dir));
b395ab2008-02-05Henrik Grubbström (Grubba)  }
d833772015-07-03Henrik Grubbström (Grubba)  package_directories += ({ package_dir });
45e01b2011-12-28Martin Stjernholm  string real_pkg_dir = roxen_path (package_dir); string sub_dir = combine_path(real_pkg_dir, "pike-modules");
b395ab2008-02-05Henrik Grubbström (Grubba)  if (Stdio.is_dir(sub_dir)) { master()->add_module_path(sub_dir); }
45e01b2011-12-28Martin Stjernholm  if (Stdio.is_dir(sub_dir = combine_path(real_pkg_dir, "include/"))) {
b395ab2008-02-05Henrik Grubbström (Grubba)  master()->add_include_path(sub_dir); }
45e01b2011-12-28Martin Stjernholm 
820c702015-07-07Henrik Grubbström (Grubba)  package_module_path += ({ combine_path(package_dir, "modules/") });
45e01b2011-12-28Martin Stjernholm  if (r_is_dir(sub_dir = combine_path(package_dir, "roxen-modules/"))) {
820c702015-07-07Henrik Grubbström (Grubba)  package_module_path += ({ sub_dir });
56c5cd2009-03-27Henrik Grubbström (Grubba)  }
45e01b2011-12-28Martin Stjernholm  if (r_is_dir(sub_dir = combine_path(package_dir, "fonts/"))) {
d833772015-07-03Henrik Grubbström (Grubba)  default_roxen_font_path += ({ sub_dir });
b395ab2008-02-05Henrik Grubbström (Grubba)  }
2480732018-02-27Karl Gustav Sterneberg #ifdef RUN_SELF_TEST if (r_is_dir(sub_dir = combine_path(package_dir, "test/modules/"))) { package_module_path += ({ sub_dir }); } #endif
b395ab2008-02-05Henrik Grubbström (Grubba) }
19924b2001-08-24Martin Nilsson //! @appears lopen
e30cf42000-03-13Per Hedbor object|void lopen(string filename, string mode, int|void perm) {
b395ab2008-02-05Henrik Grubbström (Grubba)  if( filename[0] != '/' ) { foreach(package_directories, string dir) { Stdio.File o;
ad9ac22015-07-03Henrik Grubbström (Grubba)  if (o = open(combine_path(roxen_path(dir), filename), mode, perm)) return o;
b395ab2008-02-05Henrik Grubbström (Grubba)  } } return open( filename, mode, perm ); } //! @appears lfile_stat object(Stdio.Stat) lfile_stat(string filename) { if (filename[0] != '/') { foreach(package_directories, string dir) { Stdio.Stat res;
ad9ac22015-07-03Henrik Grubbström (Grubba)  if (res = file_stat(combine_path(roxen_path(dir), filename))) return res;
b395ab2008-02-05Henrik Grubbström (Grubba)  } } return file_stat(filename);
e30cf42000-03-13Per Hedbor }
adbc522011-01-20Henrik Grubbström (Grubba) //! @appears lfile_path string lfile_path(string filename) { if (filename[0] != '/') { foreach(package_directories, string dir) {
ad9ac22015-07-03Henrik Grubbström (Grubba)  string path = combine_path(roxen_path(dir), filename);
adbc522011-01-20Henrik Grubbström (Grubba)  if (file_stat(path)) return path; } } return file_stat(filename) && filename; }
09ff051998-10-03Henrik Grubbström (Grubba) // Make a $PATH-style string
1e3d621997-02-18Niels Möller string make_path(string ... from)
d3602b1997-02-18Per Hedbor {
1590412000-02-16Per Hedbor  return map(from, lambda(string a, string b) {
2a98981997-04-19Henrik Grubbström (Grubba)  return (a[0]=='/')?combine_path("/",a):combine_path(b,a); //return combine_path(b,a);
cefd172011-12-27Martin Stjernholm  }, server_dir)*":";
d3602b1997-02-18Per Hedbor }
f685821997-09-19Henrik Grubbström (Grubba) 
19924b2001-08-24Martin Nilsson //! @appears isodate //! Returns a string with the given posix time @[t] formated as //! YYYY-MM-DD.
22c98c2001-08-13Per Hedbor string isodate( int t ) { mapping lt = localtime(t); return sprintf( "%d-%02d-%02d", lt->year+1900, lt->mon+1, lt->mday ); }
5097091999-08-06Per Hedbor void write_current_time() {
27942e1999-09-02Per Hedbor  if( !roxen ) { call_out( write_current_time, 10 ); return; }
9a002e2000-04-19Martin Nilsson  int t = time(1);
8ad9292000-03-13Martin Nilsson  mapping lt = localtime(t); report_debug("\n** "+sprintf("%02d-%02d-%02d %02d:%02d", lt->year+1900, lt->mon+1, lt->mday, lt->hour, lt->min)+
58a6431999-12-20Martin Nilsson  " pid: "+pid+" ppid: "+getppid()+
d4a3f52014-05-12Henrik Grubbström (Grubba) #if constant(geteuid)
26d7961999-09-25Martin Stjernholm  (geteuid()!=getuid()?" euid: "+pw_name(geteuid()):"")+ #endif
58a6431999-12-20Martin Nilsson  " uid: "+pw_name(getuid())+"\n\n");
26d7961999-09-25Martin Stjernholm  call_out( write_current_time, 3600 - t % 3600 );
5097091999-08-06Per Hedbor }
19924b2001-08-24Martin Nilsson //! @appears throw
f6ab4a2003-01-22Henrik Grubbström (Grubba) //! Overloads Pikes throw function. //! //! Exists for detection of code that throws non-errors.
4446d81999-12-07Henrik Grubbström (Grubba) void paranoia_throw(mixed err) {
20bcc72000-03-13Martin Nilsson  if ((arrayp(err) && ((sizeof([array]err) < 2) || !stringp(([array]err)[0]) || !arrayp(([array]err)[1]) || !(arrayp(([array(array)]err)[1][0])||stringp(([array(array)]err)[1][0])))) || (!arrayp(err) && (!objectp(err) || !([object]err)->is_generic_error))) {
58a6431999-12-20Martin Nilsson  report_debug(sprintf("Warning: throwing non-error: %O\n"
4446d81999-12-07Henrik Grubbström (Grubba)  "From: %s\n", err, describe_backtrace(backtrace()))); } throw(err); }
09ff051998-10-03Henrik Grubbström (Grubba) // Roxen bootstrap code.
af81b32000-02-15Henrik Grubbström (Grubba) int main(int argc, array(string) argv)
b1fca01996-11-12Per Hedbor {
dd90492002-01-18Martin Nilsson  Protocols.HTTP; // FIXME: Workaround for bug 2637.
02344e2001-06-24Per Hedbor 
c745112014-10-21Henrik Grubbström (Grubba) #if __VERSION__ < 8.0
02344e2001-06-24Per Hedbor  report_debug( #" ------- FATAL -------------------------------------------------
c745112014-10-21Henrik Grubbström (Grubba) Roxen 6.0 should be run with Pike 8.0 or newer.
02344e2001-06-24Per Hedbor --------------------------------------------------------------- ");
32d1a02005-03-10Henrik Grubbström (Grubba)  exit(1);
9a86b62001-06-12Per Hedbor #endif
0716b72001-06-11Per Hedbor 
32d1a02005-03-10Henrik Grubbström (Grubba)  // Check if IPv6 support is available.
0952532009-02-12Martin Stjernholm  if (mixed err = catch {
67f9f92005-03-10Henrik Grubbström (Grubba)  // Note: Attempt to open a port on the IPv6 loopback (::1) // rather than on IPv6 any (::), to make sure some // IPv6 support is actually configured. This is needed // since eg Solaris happily opens ports on :: even // if no IPv6 interfaces are configured.
8a19562006-05-31Henrik Grubbström (Grubba)  // Try IPv6 any (::) too for paranoia reasons.
0952532009-02-12Martin Stjernholm  string interface;
8a19562006-05-31Henrik Grubbström (Grubba)  Stdio.Port p = Stdio.Port();
0952532009-02-12Martin Stjernholm  if (p->bind(0, 0, interface = "::1") && p->bind(0, 0, interface = "::")) {
8a19562006-05-31Henrik Grubbström (Grubba)  add_constant("__ROXEN_SUPPORTS_IPV6__", 1); report_debug("Support for IPv6 enabled.\n"); }
0952532009-02-12Martin Stjernholm  else report_debug ("IPv6 support check failed: Could not bind %s: %s\n", interface, strerror (p->errno()));
5b23702006-05-31Henrik Grubbström (Grubba)  destruct(p);
0952532009-02-12Martin Stjernholm  }) report_debug ("IPv6 support check failed: %s", #ifdef DEBUG describe_backtrace (err) #else describe_error (err) #endif );
32d1a02005-03-10Henrik Grubbström (Grubba) 
c5b4912000-12-30Martin Nilsson  // (. Note: Optimal implementation. .)
baa9d52001-01-27Per Hedbor  array av = copy_value( argv );
74e3902000-12-30Per Hedbor  configuration_dir =
baa9d52001-01-27Per Hedbor  Getopt.find_option(av, "d",({"config-dir","configuration-directory" }),
74e3902000-12-30Per Hedbor  ({ "ROXEN_CONFIGDIR", "CONFIGURATIONS" }), "../configurations");
baa9d52001-01-27Per Hedbor 
74e3902000-12-30Per Hedbor  remove_dumped =
92d2022001-08-14Henrik Grubbström (Grubba)  Getopt.find_option(av, "remove-dumped",({"remove-dumped", }), 0 );
74e3902000-12-30Per Hedbor 
baa9d52001-01-27Per Hedbor  if( configuration_dir[-1] != '/' ) configuration_dir+="/";
6aec6f2002-03-15Henrik Grubbström (Grubba)  // Get the release version. if (release = Stdio.read_bytes("RELEASE")) { // Only the first line is interresting. release = (replace(release, "\r", "\n")/"\n")[0]; }
baa9d52001-01-27Per Hedbor 
5a272a2002-05-07Jonas Wallden  // Get product package version if (dist_version = Stdio.read_bytes("VERSION.DIST")) dist_version = (replace(dist_version, "\r", "\n") / "\n")[0]; else
03f9112002-10-28Jonas Wallden  dist_version = roxen_version();
5a272a2002-05-07Jonas Wallden 
88edde2009-04-20Jonas Wallden  // Get build OS for dist
fa64422009-04-30Jonas Wallden  dist_os = (replace(Stdio.read_bytes("OS") || "src dist", "\r", "\n") / "\n")[0];
88edde2009-04-20Jonas Wallden 
b395ab2008-02-05Henrik Grubbström (Grubba)  // Get package directories.
45e01b2011-12-28Martin Stjernholm  add_package("$LOCALDIR");
b395ab2008-02-05Henrik Grubbström (Grubba)  foreach(package_directories + ({ "." }), string dir) { dir = combine_path(dir, "packages");
6c086f2015-03-29Henrik Grubbström (Grubba)  foreach(sort(get_dir(roxen_path(dir)) || ({})), string fname) {
b395ab2008-02-05Henrik Grubbström (Grubba)  if (fname == "CVS") continue; fname = combine_path(dir, fname);
6c086f2015-03-29Henrik Grubbström (Grubba)  if (Stdio.is_dir(roxen_path(fname))) {
b395ab2008-02-05Henrik Grubbström (Grubba)  add_package(fname); } } }
56abfd2013-03-21Henrik Grubbström (Grubba)  roxen_is_cms = !!lfile_stat("modules/sitebuilder") || !!lfile_stat("packages/sitebuilder");
cdddcb2002-04-08Johan Schön 
56abfd2013-03-21Henrik Grubbström (Grubba)  if(roxen_is_cms) { if (lfile_stat("modules/print") || lfile_stat("packages/print")) { roxen_product_name="Roxen EP";
a01b5d2013-08-19Tobias Liin  roxen_product_code = "rep";
56abfd2013-03-21Henrik Grubbström (Grubba)  } else { roxen_product_name="Roxen CMS";
a01b5d2013-08-19Tobias Liin  roxen_product_code = "cms";
56abfd2013-03-21Henrik Grubbström (Grubba)  } } else {
cdddcb2002-04-08Johan Schön  roxen_product_name="Roxen WebServer";
a01b5d2013-08-19Tobias Liin  roxen_product_code = "webserver";
56abfd2013-03-21Henrik Grubbström (Grubba)  }
cdddcb2002-04-08Johan Schön 
62290c2011-09-12Henrik Grubbström (Grubba) #if defined(ROXEN_USE_FORKD) && constant(Process.set_forkd_default) report_debug("Enabling use of forkd daemon.\n"); Process.set_forkd_default(1); #endif
baa9d52001-01-27Per Hedbor  // The default (internally managed) mysql path string defpath =
bedb022001-02-02Tomas Nilsson #ifdef __NT__
a1d2e52001-11-15Tomas Nilsson  // Use pipes with a name created from the config dir
83c5b72013-02-18Henrik Grubbström (Grubba)  "mysql://%user%@.:" + query_mysql_socket() + "/%db%";
bedb022001-02-02Tomas Nilsson #else
83c5b72013-02-18Henrik Grubbström (Grubba)  "mysql://%user%@localhost:" + query_mysql_socket() + "/%db%";
bedb022001-02-02Tomas Nilsson #endif
baa9d52001-01-27Per Hedbor  my_mysql_path = Getopt.find_option(av, "m",({"mysql-url", }), 0,defpath); if( my_mysql_path != defpath ) { werror( " : ----------------------------------------------------------\n"
8a79f82003-02-05Jonas Wallden  "Notice: Not using the built-in MySQL\n" "MySQL path is "+my_mysql_path+"\n"
baa9d52001-01-27Per Hedbor  ); mysql_path_is_remote = 1; }
5574b22002-05-06Martin Stjernholm 
74e3902000-12-30Per Hedbor  nwrite = lambda(mixed ... ){};
af81b32000-02-15Henrik Grubbström (Grubba)  call_out( do_main_wrapper, 0, argc, argv );
87d06d2000-02-09Per Hedbor  // Get rid of the _main and main() backtrace elements.. return -1; }
af81b32000-02-15Henrik Grubbström (Grubba) // Wrapper to make sure we die if loading fails. void do_main_wrapper(int argc, array(string) argv) { mixed err = catch { do_main(argc, argv); return; }; catch { if (err) {
e7c2d42000-04-03Per Hedbor  werror(sprintf("Roxen loader failed:\n" "%s\n", describe_backtrace(err)));
af81b32000-02-15Henrik Grubbström (Grubba)  } };
c348db2003-09-15Martin Stjernholm  trace_exit(1);
af81b32000-02-15Henrik Grubbström (Grubba) }
fb07162009-02-06Jonas Wallden 
4008002009-07-27Martin Stjernholm protected mapping(string:string) cached_mysql_location; //! Returns a mapping with the following MySQL-related paths: //! //! @code //! ([
05cbc32013-02-15Henrik Grubbström (Grubba) //! "basedir" : <absolute path to MySQL server directory> //! "mysqld" : <absolute path to mysqld[-nt.exe]> //! "myisamchk" : <absolute path to myisamchk[.exe]> //! "mysqldump" : <absolute path to mysqldump[.exe]> //! "mysql_upgrade" : <absolute path to mysql_upgrade[.exe]>
4008002009-07-27Martin Stjernholm //! ]) //! @endcode //! //! If a path cannot be resolved it will be set to 0. //! //! The paths are read from "mysql-location.txt" in the server-x.y.z //! directory. If that file doesn't exist then default values based //! on the server-x.y.z/mysql/ subdirectory will be substituted. //! //! @note //! Don't be destructive on the returned mapping. mapping(string:string) mysql_location()
74e3902000-12-30Per Hedbor {
4008002009-07-27Martin Stjernholm  if (cached_mysql_location) return cached_mysql_location;
7dfd2e2009-02-06Jonas Wallden  string check_paths(array(string) paths) { foreach(paths, string p) if (file_stat(p)) return p; return 0; };
74aa182009-02-12Jonas Wallden  multiset(string) valid_keys = // NOTE: "mysqladmin" not used but listed here since NT starter // looks for it.
05cbc32013-02-15Henrik Grubbström (Grubba)  (< "basedir", "mysqld", "myisamchk", "mysqladmin", "mysqldump", "mysql_upgrade", >);
7dfd2e2009-02-06Jonas Wallden 
fb07162009-02-06Jonas Wallden  // If the path file is missing we fall back on the traditional // /mysql/ subdirectory. The file should contain lines on this // format:
7dfd2e2009-02-06Jonas Wallden  // // # comment // key1 = value // key2 = value // // All non-absolute paths will be interpreted relative to server-x.y.z. mapping res = ([ "basedir" : combine_path(server_dir, "mysql/") ]); string mysql_loc_file = combine_path(server_dir, "mysql-location.txt"); if (string data = Stdio.read_bytes(mysql_loc_file)) { data = replace(replace(data, "\r\n", "\n"), "\r", "\n"); foreach(data / "\n", string line) { line = String.trim_whites((line / "#")[0]); if (sizeof(line)) {
b23a632009-02-12Martin Stjernholm  sscanf(line, "%[^ \t=]%*[ \t]=%*[ \t]%s", string key, string val);
7dfd2e2009-02-06Jonas Wallden  if (key && val && sizeof(val)) { // Check for valid key key = lower_case(key);
74aa182009-02-12Jonas Wallden  if (!valid_keys[key]) {
7dfd2e2009-02-06Jonas Wallden  report_warning("mysql-location.txt: Unknown key '%s'.\n", key); continue; } // Convert to absolute path and check for existence
74aa182009-02-12Jonas Wallden  if (val[0] == '"' || val[0] == '\'') val = val[1..]; if (sizeof(val)) if (val[-1] == '"' || val[-1] == '\'') val = val[..sizeof(val) - 2];
7dfd2e2009-02-06Jonas Wallden  string path = combine_path(server_dir, val); if (check_paths( ({ path }) )) { res[key] = path; } else { report_warning("mysql-location.txt: " "Ignoring non-existing path for key '%s': %s\n", key, path); } } } } } // Find specific paths derived from the MySQL base directory if (res->basedir) { // Locate mysqld if (!res->mysqld) { #ifdef __NT__ string binary = "mysqld-nt.exe"; #else string binary = "mysqld"; #endif res->mysqld = check_paths( ({ combine_path(res->basedir, "libexec", binary), combine_path(res->basedir, "bin", binary), combine_path(res->basedir, "sbin", binary) }) ); } // Locate myisamchk if (!res->myisamchk) { #ifdef __NT__ string binary = "myisamchk.exe"; #else string binary = "myisamchk"; #endif res->myisamchk = check_paths( ({ combine_path(res->basedir, "libexec", binary), combine_path(res->basedir, "bin", binary), combine_path(res->basedir, "sbin", binary) }) ); }
7ebd012009-05-13Henrik Grubbström (Grubba)  // Locate mysqldump if (!res->mysqldump) { #ifdef __NT__ string binary = "mysqldump.exe"; #else string binary = "mysqldump"; #endif res->mysqldump = check_paths( ({ combine_path(res->basedir, "libexec", binary), combine_path(res->basedir, "bin", binary), combine_path(res->basedir, "sbin", binary) }) ); }
05cbc32013-02-15Henrik Grubbström (Grubba)  // Locate mysql_upgrade if (!res->mysql_upgrade) { #ifdef __NT__ string binary = "mysql_upgrade.exe"; #else string binary = "mysql_upgrade"; #endif res->mysql_upgrade = check_paths( ({ combine_path(res->basedir, "libexec", binary), combine_path(res->basedir, "bin", binary), combine_path(res->basedir, "sbin", binary) }) ); }
7dfd2e2009-02-06Jonas Wallden  }
4008002009-07-27Martin Stjernholm  return cached_mysql_location = res;
74e3902000-12-30Per Hedbor }
4008002009-07-27Martin Stjernholm mapping(string:string) parse_mysql_location() // Compatibility alias. { return mysql_location(); }
fb07162009-02-06Jonas Wallden 
cd5f542005-12-21Fredrik Noring string query_mysql_data_dir() { string old_dir = combine_path(getcwd(), query_configuration_dir(), "_mysql"); string new_dir, datadir = getenv("ROXEN_DATADIR"); if(datadir) new_dir = combine_path(getcwd(), datadir, "mysql"); if(new_dir && Stdio.exist(new_dir)) return new_dir; if(Stdio.exist(old_dir)) return old_dir; if(new_dir) return new_dir; return old_dir; }
83c5b72013-02-18Henrik Grubbström (Grubba) string query_mysql_socket() { #ifdef __NT__ return replace(combine_path(query_mysql_data_dir(), "pipe"), ":", "_"); #else return combine_path(query_mysql_data_dir(), "socket"); #endif }
a7c75e2001-02-01Per Hedbor string my_mysql_path;
74e3902000-12-30Per Hedbor  string query_configuration_dir() { return configuration_dir; }
fc40392008-08-15Martin Stjernholm protected mapping(string:array(SQLTimeout)) sql_free_list = ([ ]); protected Thread.Local sql_reuse_in_thread = Thread.Local();
a31e392006-09-18Martin Stjernholm mapping(string:int) sql_active_list = ([ ]);
7045822001-09-03Per Hedbor 
a5044b2001-09-05Henrik Grubbström (Grubba) #ifdef DB_DEBUG
5d98ea2012-01-07Martin Stjernholm #ifdef OBJ_COUNT_DEBUG
a5044b2001-09-05Henrik Grubbström (Grubba) mapping(int:string) my_mysql_last_user = ([]);
5d98ea2012-01-07Martin Stjernholm #endif
1efb702006-08-16Henrik Grubbström (Grubba) multiset(Sql.Sql) all_wrapped_sql_objects = set_weak_flag( (<>), 1 );
1f546c2001-09-06Per Hedbor #endif /* DB_DEBUG */
abe2432001-09-06Per Hedbor 
d8b9d52001-09-27Henrik Grubbström (Grubba)  //! @appears clear_connect_to_my_mysql_cache void clear_connect_to_my_mysql_cache( ) { sql_free_list = ([]); }
f70bb72006-05-23Jonas Wallden // Helper function for DB status tab in Admin interface mapping(string:int) get_sql_free_list_status() { return map(sql_free_list, sizeof); }
f2729a2011-05-23Martin Stjernholm #ifndef DB_CONNECTION_TIMEOUT // 1 minute timeout by default. #define DB_CONNECTION_TIMEOUT 60 #endif
fc40392008-08-15Martin Stjernholm protected class SQLTimeout(protected Sql.Sql real)
6ab3522001-11-08Henrik Grubbström (Grubba) {
f2729a2011-05-23Martin Stjernholm  protected int timeout = time(1) + DB_CONNECTION_TIMEOUT;
6ab3522001-11-08Henrik Grubbström (Grubba) 
fc40392008-08-15Martin Stjernholm  protected int(0..1) `!()
6ab3522001-11-08Henrik Grubbström (Grubba)  { if (timeout < time(1)) { real = 0; } return !real; } Sql.Sql get() { if (timeout < time(1)) { real = 0; }
8a2ce42011-08-29Henrik Grubbström (Grubba)  if (timeout - time(1) < (DB_CONNECTION_TIMEOUT - 10)) { // Idle more than 10 seconds. // - Check that the connection still is alive. if (real->ping()) real = 0; } else { // Idle less than 10 seconds. // - Just check that the connection hasn't been closed. if (!real->is_open()) real = 0; }
6ab3522001-11-08Henrik Grubbström (Grubba)  Sql.Sql res = real; real = 0; return res; } }
d8b9d52001-09-27Henrik Grubbström (Grubba) 
f1690f2012-02-29Henrik Grubbström (Grubba) //!
fc40392008-08-15Martin Stjernholm protected class SQLResKey
d8b9d52001-09-27Henrik Grubbström (Grubba) {
fc40392008-08-15Martin Stjernholm  protected Sql.sql_result real; protected SQLKey key;
8c84642005-09-23Martin Stjernholm 
f1690f2012-02-29Henrik Grubbström (Grubba)  //! @ignore
5d98ea2012-01-07Martin Stjernholm  DECLARE_OBJ_COUNT;
f1690f2012-02-29Henrik Grubbström (Grubba)  //! @endignore
5d98ea2012-01-07Martin Stjernholm 
fc40392008-08-15Martin Stjernholm  protected void create (Sql.sql_result real, SQLKey key)
8c84642005-09-23Martin Stjernholm  { this_program::real = real; this_program::key = key; }
d8b9d52001-09-27Henrik Grubbström (Grubba)  // Proxy functions:
8c84642005-09-23Martin Stjernholm  // Why are these needed? /mast
fc40392008-08-15Martin Stjernholm  protected int num_rows()
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return real->num_rows(); }
fc40392008-08-15Martin Stjernholm  protected int num_fields()
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return real->num_fields(); }
fc40392008-08-15Martin Stjernholm  protected int eof()
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return real->eof(); }
fc40392008-08-15Martin Stjernholm  protected array(mapping(string:mixed)) fetch_fields()
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return real->fetch_fields(); }
fc40392008-08-15Martin Stjernholm  protected void seek(int skip)
d8b9d52001-09-27Henrik Grubbström (Grubba)  { real->seek(skip); }
fc40392008-08-15Martin Stjernholm  protected int|array(string|int) fetch_row()
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return real->fetch_row(); }
a2e9b12014-08-15Henrik Grubbström (Grubba)  protected int|string fetch_json_result()
74a97f2009-08-26Fredrik Noring  { return real->fetch_json_result(); }
d8b9d52001-09-27Henrik Grubbström (Grubba) 
fc40392008-08-15Martin Stjernholm  protected int(0..1) `!()
ca7b412001-11-07Henrik Grubbström (Grubba)  { return !real; }
c0a8d92011-05-23Martin Stjernholm  // Iterator copied from Sql.sql_result. It's less hassle to // implement our own than to wrap the real one. class _get_iterator { protected int|array(string|int) row = fetch_row(); protected int pos = 0; int index() { return pos; } int|array(string|int) value() { return row; } int(0..1) next() { pos++; return !!(row = fetch_row()); } this_program `+=(int steps) { if(!steps) return this; if(steps<0) error("Iterator must advance a positive number of steps.\n"); if(steps>1) { pos += steps-1; seek(steps-1); } next(); return this; } int(0..1) `!() { return eof(); } int _sizeof() { return num_fields(); } }
fc40392008-08-15Martin Stjernholm  protected mixed `[]( string what )
d8b9d52001-09-27Henrik Grubbström (Grubba)  { return `->( what ); }
fc40392008-08-15Martin Stjernholm  protected mixed `->(string what )
d8b9d52001-09-27Henrik Grubbström (Grubba)  { switch( what ) {
74a97f2009-08-26Fredrik Noring  case "real": return real; case "num_rows": return num_rows; case "num_fields": return num_fields; case "eof": return eof; case "fetch_fields": return fetch_fields; case "seek": return seek; case "fetch_row": return fetch_row;
c0a8d92011-05-23Martin Stjernholm  case "_get_iterator": return _get_iterator;
74a97f2009-08-26Fredrik Noring  case "fetch_json_result": return fetch_json_result;
d8b9d52001-09-27Henrik Grubbström (Grubba)  } return real[what]; }
fc40392008-08-15Martin Stjernholm  protected string _sprintf(int type)
d8b9d52001-09-27Henrik Grubbström (Grubba)  {
5d98ea2012-01-07Martin Stjernholm  return sprintf( "SQLResKey(%O)" + OBJ_COUNT, real );
d8b9d52001-09-27Henrik Grubbström (Grubba)  }
94d7b02001-10-15Henrik Grubbström (Grubba) 
fc40392008-08-15Martin Stjernholm  protected void destroy()
94d7b02001-10-15Henrik Grubbström (Grubba)  {
8c84642005-09-23Martin Stjernholm  if (key->reuse_in_thread) {
39e91c2008-02-13Martin Stjernholm  // FIXME: This won't work well; destroy() might get called from // any thread when an object is refcount garbed.
8c84642005-09-23Martin Stjernholm  mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get(); if (!dbs_for_thread[key->db_name]) dbs_for_thread[key->db_name] = key->real; } #if 0
94d7b02001-10-15Henrik Grubbström (Grubba)  werror("Destroying %O\n", this_object());
8c84642005-09-23Martin Stjernholm #endif
94d7b02001-10-15Henrik Grubbström (Grubba)  }
d8b9d52001-09-27Henrik Grubbström (Grubba) }
f1690f2012-02-29Henrik Grubbström (Grubba) //!
fc40392008-08-15Martin Stjernholm protected class SQLKey
7045822001-09-03Per Hedbor {
fc40392008-08-15Martin Stjernholm  protected Sql.Sql real; protected string db_name; protected int reuse_in_thread;
abe2432001-09-06Per Hedbor 
fc40392008-08-15Martin Stjernholm  protected int `!( ) { return !real; }
8f57052001-09-06Per Hedbor 
036c7b2011-05-24Martin Stjernholm  protected void handle_db_error (mixed err)
8f57052001-09-06Per Hedbor  {
036c7b2011-05-24Martin Stjernholm  // FIXME: Ugly way of recognizing connect errors. If these errors // happen the connection is not welcome back to the pool. string errmsg = describe_error (err); if (has_prefix (errmsg, "Mysql.mysql(): Couldn't connect ") ||
3581962011-10-07Martin Stjernholm  has_prefix (errmsg, "Mysql.mysql(): Couldn't reconnect ") || has_suffix (errmsg, "(MySQL server has gone away)\n")) {
8c84642005-09-23Martin Stjernholm  if (reuse_in_thread) { mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get(); if (dbs_for_thread[db_name] == real) m_delete (dbs_for_thread, db_name); }
036c7b2011-05-24Martin Stjernholm  real = 0;
8c84642005-09-23Martin Stjernholm  }
036c7b2011-05-24Martin Stjernholm  throw (err); } array(mapping) query( string f, mixed ... args ) { mixed err = catch { return real->query( f, @args ); }; handle_db_error (err); } Sql.sql_result big_query( string f, mixed ... args ) { Sql.sql_result o; if (mixed err = catch (o = real->big_query( f, @args ))) handle_db_error (err); if (reuse_in_thread) { mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get(); if (dbs_for_thread[db_name] == real) m_delete (dbs_for_thread, db_name); } return [object(Sql.sql_result)] (object) SQLResKey (o, this);
8f57052001-09-06Per Hedbor  }
5d98ea2012-01-07Martin Stjernholm 
f1690f2012-02-29Henrik Grubbström (Grubba)  //! @ignore
5d98ea2012-01-07Martin Stjernholm  DECLARE_OBJ_COUNT;
f1690f2012-02-29Henrik Grubbström (Grubba)  //! @endignore
a5044b2001-09-05Henrik Grubbström (Grubba) #ifdef DB_DEBUG
fc40392008-08-15Martin Stjernholm  protected string bt;
abe2432001-09-06Per Hedbor #endif
fc40392008-08-15Martin Stjernholm  protected void create( Sql.Sql real, string db_name, int reuse_in_thread)
abe2432001-09-06Per Hedbor  {
8c84642005-09-23Martin Stjernholm  this_program::real = real; this_program::db_name = db_name; this_program::reuse_in_thread = reuse_in_thread; if (reuse_in_thread) { mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get(); if (!dbs_for_thread) sql_reuse_in_thread->set (dbs_for_thread = ([])); if (!dbs_for_thread[db_name]) dbs_for_thread[db_name] = real; }
1f546c2001-09-06Per Hedbor #ifdef DB_DEBUG
1efb702006-08-16Henrik Grubbström (Grubba)  if( !real )
5c794b2001-09-06Per Hedbor  error("Creating SQL with empty real sql\n");
a5044b2001-09-05Henrik Grubbström (Grubba) 
1efb702006-08-16Henrik Grubbström (Grubba)  foreach( (array)all_wrapped_sql_objects, Sql.Sql sql )
5c794b2001-09-06Per Hedbor  {
1efb702006-08-16Henrik Grubbström (Grubba)  if( sql ) if( sql == real )
8c84642005-09-23Martin Stjernholm  error("Fatal: This database connection is already used!\n");
1efb702006-08-16Henrik Grubbström (Grubba)  else if( sql->master_sql == real->master_sql )
5c794b2001-09-06Per Hedbor  error("Fatal: Internal share error: master_sql equal!\n"); }
a366a52001-09-06Per Hedbor 
1efb702006-08-16Henrik Grubbström (Grubba)  all_wrapped_sql_objects[real] = 1; #if 0 // Disabled, since it seems to have bad side-effects :-(
5d98ea2012-01-07Martin Stjernholm #ifdef OBJ_COUNT_DEBUG bt=(my_mysql_last_user[__object_count] = describe_backtrace(backtrace())); #endif
1efb702006-08-16Henrik Grubbström (Grubba) #endif
abe2432001-09-06Per Hedbor #endif /* DB_DEBUG */ }
fc40392008-08-15Martin Stjernholm  protected void destroy()
7045822001-09-03Per Hedbor  {
d8b9d52001-09-27Henrik Grubbström (Grubba)  // FIXME: Ought to be abstracted to an sq_cache_free().
1f546c2001-09-06Per Hedbor #ifdef DB_DEBUG
1efb702006-08-16Henrik Grubbström (Grubba)  all_wrapped_sql_objects[real]=0;
5c794b2001-09-06Per Hedbor #endif
d8b9d52001-09-27Henrik Grubbström (Grubba) 
8c84642005-09-23Martin Stjernholm  if (reuse_in_thread) {
39e91c2008-02-13Martin Stjernholm  // FIXME: This won't work well; destroy() might get called from // any thread when an object is refcount garbed.
fc40392008-08-15Martin Stjernholm  mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get();
8c84642005-09-23Martin Stjernholm  if (dbs_for_thread[db_name] == real) { m_delete (dbs_for_thread, db_name); if (!sizeof (dbs_for_thread)) sql_reuse_in_thread->set (0); } }
036c7b2011-05-24Martin Stjernholm  if (!real) return;
33d8e62001-09-06Per Hedbor #ifndef NO_DB_REUSE
d8b9d52001-09-27Henrik Grubbström (Grubba)  mixed key; catch { key = sq_cache_lock(); };
7045822001-09-03Per Hedbor #ifdef DB_DEBUG
5d98ea2012-01-07Martin Stjernholm  werror("%O added to free list\n", this ); #ifdef OBJ_COUNT_DEBUG m_delete(my_mysql_last_user, __object_count); #endif
a7c75e2001-02-01Per Hedbor #endif
8c84642005-09-23Martin Stjernholm  if( !--sql_active_list[db_name] ) m_delete( sql_active_list, db_name ); sql_free_list[ db_name ] = ({ SQLTimeout(real) }) + (sql_free_list[ db_name ]||({}));
7045822001-09-03Per Hedbor  if( `+( 0, @map(values( sql_free_list ),sizeof ) ) > 20 )
4f74c82001-08-09Per Hedbor  {
7045822001-09-03Per Hedbor #ifdef DB_DEBUG werror("Free list too large. Cleaning.\n" ); #endif clear_connect_to_my_mysql_cache();
4f74c82001-08-09Per Hedbor  }
b566202001-10-05Per Hedbor #else // Slow'R'us call_out(gc,0);
33d8e62001-09-06Per Hedbor #endif
7045822001-09-03Per Hedbor  }
fc40392008-08-15Martin Stjernholm  protected mixed `[]( string what )
7045822001-09-03Per Hedbor  {
abe2432001-09-06Per Hedbor  return `->( what );
7045822001-09-03Per Hedbor  }
fc40392008-08-15Martin Stjernholm  protected mixed `->(string what )
7045822001-09-03Per Hedbor  {
8f57052001-09-06Per Hedbor  switch( what ) {
a366a52001-09-06Per Hedbor  case "real": return real;
8c84642005-09-23Martin Stjernholm  case "db_name": return db_name; case "reuse_in_thread": return reuse_in_thread;
a366a52001-09-06Per Hedbor  case "query": return query;
8f57052001-09-06Per Hedbor  case "big_query": return big_query; }
7045822001-09-03Per Hedbor  return real[what]; }
fc40392008-08-15Martin Stjernholm  protected string _sprintf(int type)
7045822001-09-03Per Hedbor  {
c978f12015-08-03Henrik Grubbström (Grubba)  string display_name = db_name || ""; if (has_suffix(display_name, ":-")) { // Unmangle the mangling from DBManager.sql_cache_get(). display_name = replace(display_name[..<2], ";", ":"); } array(string) a = display_name/"://";
3c86582015-03-11Henrik Grubbström (Grubba)  string prot = a[0]; string host = a[1..] * "://"; a = host/"@"; if (sizeof(a) > 1) { host = a[-1]; a = (a[..<1] * "@")/":"; string user = a[0]; if (sizeof(a) > 1) { display_name = prot + "://" + user + ":CENSORED@" + host; } } return sprintf( "SQLKey(%O, %O)" + OBJ_COUNT, display_name, real );
7045822001-09-03Per Hedbor  }
4f74c82001-08-09Per Hedbor }
fc40392008-08-15Martin Stjernholm protected Thread.Mutex mt = Thread.Mutex();
8c84642005-09-23Martin Stjernholm Thread.MutexKey sq_cache_lock()
16d09e2001-09-06Per Hedbor { return mt->lock(); }
fc40392008-08-15Martin Stjernholm protected mapping(program:string) default_db_charsets = ([]);
a31e392006-09-18Martin Stjernholm 
9f7f662017-03-14Henrik Grubbström (Grubba) //! Get a cached connection to an SQL database. //! //! @param db_name //! SQL-URL for the connection. //! //! @param reuse_in_thread //! Use a thread-dedicated cache.
f919e42011-05-23Martin Stjernholm Sql.Sql sq_cache_get( string db_name, void|int reuse_in_thread)
4f74c82001-08-09Per Hedbor {
a31e392006-09-18Martin Stjernholm  Sql.Sql db;
9f7f662017-03-14Henrik Grubbström (Grubba)  Thread.MutexKey key = sq_cache_lock();
a31e392006-09-18Martin Stjernholm 
8c84642005-09-23Martin Stjernholm  if (reuse_in_thread) {
fc40392008-08-15Martin Stjernholm  mapping(string:Sql.Sql) dbs_for_thread = sql_reuse_in_thread->get();
a31e392006-09-18Martin Stjernholm  db = dbs_for_thread && dbs_for_thread[db_name];
8c84642005-09-23Martin Stjernholm  }
a31e392006-09-18Martin Stjernholm  else {
9f7f662017-03-14Henrik Grubbström (Grubba)  while(sizeof(sql_free_list[db_name] || ({})))
a31e392006-09-18Martin Stjernholm  {
7045822001-09-03Per Hedbor #ifdef DB_DEBUG
a31e392006-09-18Martin Stjernholm  werror("%O found in free list\n", db_name );
7045822001-09-03Per Hedbor #endif
a31e392006-09-18Martin Stjernholm  SQLTimeout res = sql_free_list[db_name][0]; if( sizeof( sql_free_list[ db_name ] ) > 1) sql_free_list[ db_name ] = sql_free_list[db_name][1..]; else m_delete( sql_free_list, db_name );
9f7f662017-03-14Henrik Grubbström (Grubba)  if (res) { destruct(key); // NB: Release the lock during connection validation. Cf [WS-28]. if ((db = res->get()) && db->is_open()) { key = sq_cache_lock(); sql_active_list[db_name]++; break; } key = sq_cache_lock();
a31e392006-09-18Martin Stjernholm  }
8c84642005-09-23Martin Stjernholm  }
7045822001-09-03Per Hedbor  }
a31e392006-09-18Martin Stjernholm 
f919e42011-05-23Martin Stjernholm  if (db) return [object(Sql.Sql)] (object) SQLKey (db, db_name, reuse_in_thread); return 0; }
68145f2011-05-18Martin Stjernholm 
f919e42011-05-23Martin Stjernholm Sql.Sql fix_connection_charset (Sql.Sql db, string charset) {
956ae92012-01-09Martin Stjernholm  if (object master_sql = db->master_sql) { if (mixed err = catch { if (master_sql->set_charset) { if (!charset) charset = default_db_charsets[object_program (master_sql)]; if ((charset == "unicode" || charset == "broken-unicode") && master_sql->get_unicode_encode_mode) { // Unicode mode requested and the sql backend seems to // support it (a better recognition flag would be nice). // Detect if it's already enabled through // get_unicode_encode_mode and get_unicode_decode_mode. It's // enabled iff both return true. if (!(master_sql->get_unicode_encode_mode() && master_sql->get_unicode_decode_mode())) master_sql->set_charset (charset); }
a31e392006-09-18Martin Stjernholm 
956ae92012-01-09Martin Stjernholm  else { if (master_sql->set_unicode_decode_mode && master_sql->get_unicode_decode_mode()) // Ugly special case for mysql: The set_charset call does // not reset this state. master_sql->set_unicode_decode_mode (0); if (charset != master_sql->get_charset()) master_sql->set_charset (charset); } } }) { // Since SQLKey (currently) doesn't wrap master_sql, be careful // to destroy the wrapper object on errors above so we don't // risk getting an object with a strange charset state in the cache. if (db) destruct (db); throw (err);
f919e42011-05-23Martin Stjernholm  }
956ae92012-01-09Martin Stjernholm  }
f919e42011-05-23Martin Stjernholm  return db;
16d09e2001-09-06Per Hedbor }
22d2672008-11-26Martin Stjernholm #define FIX_CHARSET_FOR_NEW_SQL_CONN(SQLOBJ, CHARSET) do { \ if (object master_sql = SQLOBJ->master_sql) \ if (master_sql->set_charset) { \ if (zero_type (default_db_charsets[object_program (master_sql)])) \ default_db_charsets[object_program (master_sql)] = \ SQLOBJ->get_charset(); \ if (CHARSET) SQLOBJ->set_charset (CHARSET); \ } \
a31e392006-09-18Martin Stjernholm  } while (0) Sql.Sql sq_cache_set( string db_name, Sql.Sql res, void|int reuse_in_thread, void|string charset)
5197df2007-05-03Martin Stjernholm // Should only be called with a "virgin" Sql.Sql object that has never // been used or had its charset changed.
16d09e2001-09-06Per Hedbor { if( res )
7045822001-09-03Per Hedbor  {
22d2672008-11-26Martin Stjernholm  FIX_CHARSET_FOR_NEW_SQL_CONN (res, charset);
9f7f662017-03-14Henrik Grubbström (Grubba)  Thread.MutexKey key = sq_cache_lock();
8c84642005-09-23Martin Stjernholm  sql_active_list[ db_name ]++; return [object(Sql.Sql)] (object) SQLKey( res, db_name, reuse_in_thread);
7045822001-09-03Per Hedbor  }
3e53192001-08-10Per Hedbor }
a366a52001-09-06Per Hedbor /* Not to be documented. This is a low-level function that should be * avoided by normal users. */
8c84642005-09-23Martin Stjernholm Sql.Sql connect_to_my_mysql( string|int ro, void|string db,
a31e392006-09-18Martin Stjernholm  void|int reuse_in_thread, void|string charset)
16d09e2001-09-06Per Hedbor {
8c84642005-09-23Martin Stjernholm #if 0
1f546c2001-09-06Per Hedbor #ifdef DB_DEBUG
5c794b2001-09-06Per Hedbor  gc(); #endif
8c84642005-09-23Martin Stjernholm #endif
9f7f662017-03-14Henrik Grubbström (Grubba)  string i = db+":"+(intp(ro)?(ro&&"ro")||"rw":ro); Sql.Sql res;
5aaf5b2002-02-06Henrik Grubbström (Grubba)  if (catch {
9f7f662017-03-14Henrik Grubbström (Grubba)  res = sq_cache_get(i, reuse_in_thread); }) {
5aaf5b2002-02-06Henrik Grubbström (Grubba)  // Threads disabled.
a31e392006-09-18Martin Stjernholm  // This can occur if we are called from the compiler.
9f7f662017-03-14Henrik Grubbström (Grubba)  // NB: This is probably dead code with Pike 8.0 and later, // as the compiler no longer disables all threads.
a31e392006-09-18Martin Stjernholm  Sql.Sql res = low_connect_to_my_mysql(ro, db);
22d2672008-11-26Martin Stjernholm  FIX_CHARSET_FOR_NEW_SQL_CONN (res, charset);
a31e392006-09-18Martin Stjernholm  return res;
5aaf5b2002-02-06Henrik Grubbström (Grubba)  }
f919e42011-05-23Martin Stjernholm  if (res) { return fix_connection_charset (res, charset); }
93d4362006-07-14Henrik Grubbström (Grubba)  if (res = low_connect_to_my_mysql( ro, db )) {
9f7f662017-03-14Henrik Grubbström (Grubba)  return sq_cache_set(i, res, reuse_in_thread, charset);
93d4362006-07-14Henrik Grubbström (Grubba)  } return 0;
16d09e2001-09-06Per Hedbor }
fc40392008-08-15Martin Stjernholm protected mixed low_connect_to_my_mysql( string|int ro, void|string db )
3e53192001-08-10Per Hedbor {
4f74c82001-08-09Per Hedbor  object res;
a6e1fa2001-08-10Per Hedbor #ifdef DB_DEBUG werror("Requested %O for %O DB\n", db, ro ); #endif
7045822001-09-03Per Hedbor 
a7c75e2001-02-01Per Hedbor  if( !db ) db = "mysql";
6f11ba2001-01-08Per Hedbor 
c43d0f2008-12-20Martin Stjernholm  mixed err = catch
74e3902000-12-30Per Hedbor  {
baa9d52001-01-27Per Hedbor  if( intp( ro ) ) ro = ro?"ro":"rw";
22c98c2001-08-13Per Hedbor  int t = gethrtime(); res = Sql.Sql( replace( my_mysql_path,({"%user%", "%db%" }),
8a2ce42011-08-29Henrik Grubbström (Grubba)  ({ ro, db })), ([ "reconnect":0 ]));
1efb702006-08-16Henrik Grubbström (Grubba) #ifdef ENABLE_MYSQL_UNICODE_MODE
22d2672008-11-26Martin Stjernholm  if (res && res->master_sql && res->master_sql->set_unicode_decode_mode) {
222f1b2006-08-17Henrik Grubbström (Grubba)  // NOTE: The following code only works on Mysql servers 4.1 and later.
a87a0d2006-11-17Martin Stjernholm  mixed err2 = catch {
4670e52006-08-22Henrik Grubbström (Grubba)  res->master_sql->set_unicode_decode_mode(1);
1efb702006-08-16Henrik Grubbström (Grubba) #ifdef DB_DEBUG
4670e52006-08-22Henrik Grubbström (Grubba)  werror("Unicode decode mode enabled.\n");
1efb702006-08-16Henrik Grubbström (Grubba) #endif };
a87a0d2006-11-17Martin Stjernholm #ifdef DB_DEBUG if (err2) werror ("Failed to enable unicode decode mode: %s", describe_error (err2)); #endif
1efb702006-08-16Henrik Grubbström (Grubba)  } #endif /* ENABLE_MYSQL_UNICODE_MODE */
22c98c2001-08-13Per Hedbor #ifdef DB_DEBUG werror("Connect took %.2fms\n", (gethrtime()-t)/1000.0 ); #endif
7045822001-09-03Per Hedbor  return res;
c43d0f2008-12-20Martin Stjernholm  }; if( db == "mysql" || // Yep, this is ugly.. has_value (describe_error (err), "Access denied")) throw( err ); if (mixed err_2 = catch { low_connect_to_my_mysql( 0, "mysql" ) ->query( "CREATE DATABASE "+ db ); }) { report_warning ("Attempt to autocreate database %O failed: %s", db, describe_error (err_2)); throw (err); }
16d09e2001-09-06Per Hedbor  return low_connect_to_my_mysql( ro, db );
74e3902000-12-30Per Hedbor }
4f74c82001-08-09Per Hedbor 
fc40392008-08-15Martin Stjernholm protected mapping tailf_info = ([]); protected void do_tailf( int loop, string file )
bed50e2001-01-21Per Hedbor { string mysqlify( string what ) {
5dee022001-08-08Per Hedbor  string res = ""; foreach( (what/"\n"), string line )
bed50e2001-01-21Per Hedbor  {
5dee022001-08-08Per Hedbor  if( sscanf( line, "%*sAborted connection%*s" ) == 2 ) continue;
bed50e2001-01-21Per Hedbor  if( line == "" ) return res+"\n"; res += "\n";
2698fd2002-08-20Anders Johansson  res += "mysql: "+line;
bed50e2001-01-21Per Hedbor  } return res; };
5020d42008-05-09Martin Stjernholm  int os, si;
8b32892003-03-02Anders Johansson  if( tailf_info[file] ) os = tailf_info[file];
bed50e2001-01-21Per Hedbor  do {
8b32892003-03-02Anders Johansson  Stdio.Stat s = file_stat( file );
2c241c2003-03-03Anders Johansson  if(!s) { os = tailf_info[ file ] = 0;
6a1f502008-02-06Fredrik Noring  sleep(1);
2c241c2003-03-03Anders Johansson  continue; }
bed50e2001-01-21Per Hedbor  si = s[ ST_SIZE ];
2c241c2003-03-03Anders Johansson  if( zero_type( tailf_info[ file ] ) ) os = tailf_info[ file ] = si;
bed50e2001-01-21Per Hedbor  if( os != si ) {
8b32892003-03-02Anders Johansson  Stdio.File f = Stdio.File( file, "r" );
bed50e2001-01-21Per Hedbor  if(!f) return; if( os < si ) { f->seek( os ); report_debug( mysqlify( f->read( si - os ) ) ); } else report_debug( mysqlify( f->read( si ) ) );
8b32892003-03-02Anders Johansson  os = tailf_info[ file ] = si;
bed50e2001-01-21Per Hedbor  }
510bea2001-08-09Per Hedbor  if( loop ) sleep( 1 );
bed50e2001-01-21Per Hedbor  } while( loop ); }
7dfd2e2009-02-06Jonas Wallden protected void low_check_mysql(string myisamchk, string datadir,
fc40392008-08-15Martin Stjernholm  array(string) args, void|Stdio.File errlog)
7573ab2008-02-06Fredrik Noring { array(string) files = ({}); foreach(get_dir(datadir) || ({}), string dir) { foreach(get_dir(combine_path(datadir, dir)) || ({}), string file) if(!file || !glob("*.myi", lower_case(file), )) continue; else files += ({ combine_path(datadir, dir, file) }); } if(!sizeof(files)) return;
39e91c2008-02-13Martin Stjernholm  Stdio.File devnull #ifndef __NT__ = Stdio.File( "/dev/null", "w" ) #endif ;
7573ab2008-02-06Fredrik Noring  report_debug("Checking MySQL tables with %O...\n", args*" "); mixed err = catch {
92ced82011-09-12Henrik Grubbström (Grubba)  Process.Process(({ myisamchk }) + args + sort(files), ([ "stdin":devnull, "stdout":errlog, "stderr":errlog ]))->wait();
7573ab2008-02-06Fredrik Noring  }; if(err) werror(describe_backtrace(err)); }
825cb92001-01-31Per Hedbor void low_start_mysql( string datadir,
c5e97b2009-06-25Martin Stjernholm  string uid, void|int log_queries_to_stdout)
825cb92001-01-31Per Hedbor {
3363a02007-12-07Martin Jonsson  void rotate_log(string path) { rm(path+".5"); for(int i=4; i>0; i--) mv(path+"."+(string)i, path+"."+(string)(i+1)); };
7dfd2e2009-02-06Jonas Wallden  // Get mysql base directory and binary paths
4008002009-07-27Martin Stjernholm  mapping mysql_location = this_program::mysql_location();
7dfd2e2009-02-06Jonas Wallden  if (!mysql_location->mysqld) { report_debug("\nNo MySQL found in "+ mysql_location->basedir + "!\n"); exit(1);
825cb92001-01-31Per Hedbor  }
2ddbde2009-02-11Jonas Wallden  // Start by verifying the mysqld version string version_fatal_error = 0;
b771de2014-09-30Henrik Grubbström (Grubba)  string version = popen(({ mysql_location->mysqld, "--version", "--no-defaults", }));
2ddbde2009-02-11Jonas Wallden  if (!version) { version_fatal_error = sprintf("Unable to determine MySQL version with this command:\n\n"
b771de2014-09-30Henrik Grubbström (Grubba)  " %s --version --no-defaults\n\n",
2ddbde2009-02-11Jonas Wallden  mysql_location->mysqld); } else { // Parse version string
bffd562009-02-11Jonas Wallden  string orig_version = version;
dd43892014-09-05Henrik Grubbström (Grubba)  string trailer;
533be82009-02-17Martin Stjernholm  if (has_prefix (version, mysql_location->mysqld)) // mysqld puts $0 first in the version string. Cut it off to // avoid possible false matches. version = version[sizeof (mysql_location->mysqld)..];
dd43892014-09-05Henrik Grubbström (Grubba)  if (sscanf(lower_case(version), "%*s ver %[0-9.]%s", mysql_version, trailer) < 2) {
2ddbde2009-02-11Jonas Wallden  version_fatal_error =
62c9092011-11-10Martin Stjernholm  sprintf("Failed to parse MySQL version string - got %q from:\n" "%O\n\n", version, orig_version);
dd43892014-09-05Henrik Grubbström (Grubba) #ifndef YES_I_KNOW_WHAT_I_AM_DOING
2ddbde2009-02-11Jonas Wallden  } else {
dd43892014-09-05Henrik Grubbström (Grubba)  array(string) good_versions = mysql_good_versions; array(string) maybe_versions = mysql_maybe_versions; mysql_product_name = "MySQL"; if (has_prefix(trailer, "-mariadb")) { mysql_product_name = "MariaDB"; good_versions = mariadb_good_versions; maybe_versions = mariadb_maybe_versions; }
2ddbde2009-02-11Jonas Wallden  // Determine if version is acceptable
dd43892014-09-05Henrik Grubbström (Grubba)  if (has_value(glob(good_versions[*], mysql_version), 1)) {
2ddbde2009-02-11Jonas Wallden  // Everything is fine
dd43892014-09-05Henrik Grubbström (Grubba)  } else if (has_value(glob(maybe_versions[*], mysql_version), 1)) {
2ddbde2009-02-11Jonas Wallden  // Don't allow unless user gives special define #ifdef ALLOW_UNSUPPORTED_MYSQL report_debug("\nWARNING: Forcing Roxen to run with unsupported "
dd43892014-09-05Henrik Grubbström (Grubba)  "%s version (%s).\n", mysql_product_name, mysql_version);
2ddbde2009-02-11Jonas Wallden #else version_fatal_error =
dd43892014-09-05Henrik Grubbström (Grubba)  sprintf("This version of %s (%s) is not officially supported "
2ddbde2009-02-11Jonas Wallden  "with Roxen.\n" "If you want to override this restriction, use this " "option:\n\n" " -DALLOW_UNSUPPORTED_MYSQL\n\n",
dd43892014-09-05Henrik Grubbström (Grubba)  mysql_product_name, mysql_version);
2ddbde2009-02-11Jonas Wallden #endif } else { // Version not recognized (maybe too old or too new) so bail out version_fatal_error =
dd43892014-09-05Henrik Grubbström (Grubba)  sprintf("%s version %s detected:\n\n" " %s\n", mysql_product_name, mysql_version, orig_version);
2ddbde2009-02-11Jonas Wallden  }
8005a72016-10-10Anders Johansson #endif
970b022011-11-10Martin Stjernholm #ifdef RUN_SELF_TEST if (version_fatal_error) { report_debug ("\n%s" "Continuing anyway in self test mode.\n\n", version_fatal_error); version_fatal_error = 0; } #endif
2ddbde2009-02-11Jonas Wallden  } } if (version_fatal_error) { report_debug("\n%s" "Roxen cannot run unknown/unsupported versions for data\n" "integrity reasons and will therefore terminate.\n\n", version_fatal_error); exit(1); }
7062432009-02-13Martin Stjernholm 
825cb92001-01-31Per Hedbor  string pid_file = datadir + "/mysql_pid"; string err_log = datadir + "/error_log";
3363a02007-12-07Martin Jonsson  string slow_query_log; // If the LOGFILE environment variable is set, the logfile will be written // to the same directory as the debug log. Otherwise, it will be written // to the mysql data directory (i.e. configurations/_mysql/). if(getenv("LOGFILE")) slow_query_log = dirname(roxen_path("$LOGFILE")) + "/slow_query_log"; else slow_query_log = datadir + "/slow_query_log";
825cb92001-01-31Per Hedbor 
2ed8872008-02-06Martin Jonsson  slow_query_log = combine_path(getcwd(), slow_query_log);
7e7ea82008-02-06Martin Jonsson 
01ff7b2002-02-05Henrik Grubbström (Grubba)  // Default arguments.
6d6bc82001-06-24Martin Nilsson  array(string) args = ({
8edc672001-07-31Per Hedbor  "--defaults-file="+datadir+"/my.cfg",
4e64912001-11-14Tomas Nilsson #ifdef __NT__
bedb022001-02-02Tomas Nilsson  // Use pipes with default name "MySQL" unless --socket is set
a1d2e52001-11-15Tomas Nilsson  "--socket="+replace(datadir, ":", "_") + "/pipe",
a04f242003-12-12Jonas Wallden  "--enable-named-pipe",
bedb022001-02-02Tomas Nilsson #else
825cb92001-01-31Per Hedbor  "--socket="+datadir+"/socket",
4e64912001-11-14Tomas Nilsson  "--pid-file="+pid_file,
825cb92001-01-31Per Hedbor #endif
920f062013-02-05Build system  has_prefix(version, "5.1.")? "--skip-locking":"--skip-external-locking",
1d6a5e2002-02-27Henrik Grubbström (Grubba)  "--skip-name-resolve",
7dfd2e2009-02-06Jonas Wallden  "--basedir=" + mysql_location->basedir,
825cb92001-01-31Per Hedbor  "--datadir="+datadir,
6d6bc82001-06-24Martin Nilsson  });
825cb92001-01-31Per Hedbor 
01ff7b2002-02-05Henrik Grubbström (Grubba)  // Set up the environment variables, and // enable mysql networking if necessary. mapping env = getenv(); env->MYSQL_UNIX_PORT = datadir+"/socket";
3cd0582002-04-05Henrik Grubbström (Grubba)  if ((int)env->ROXEN_MYSQL_TCP_PORT) { env->MYSQL_TCP_PORT = env->ROXEN_MYSQL_TCP_PORT;
01ff7b2002-02-05Henrik Grubbström (Grubba)  args += ({ "--port="+env->MYSQL_TCP_PORT }); if (!env->MYSQL_HOST) { env->MYSQL_HOST = "127.0.0.1"; } } else { args += ({ "--skip-networking" }); env->MYSQL_HOST = "127.0.0.1"; env->MYSQL_TCP_PORT = "0"; }
0b22822014-09-05Henrik Grubbström (Grubba)  string normalized_mysql_version = map(mysql_version/".", lambda(string d) { return ("000" + d)[<2..]; }) * ".";
3363a02007-12-07Martin Jonsson  if(!env->ROXEN_MYSQL_SLOW_QUERY_LOG || env->ROXEN_MYSQL_SLOW_QUERY_LOG != "0") { rotate_log(slow_query_log);
0b22822014-09-05Henrik Grubbström (Grubba)  if (normalized_mysql_version > "005.006.") {
ab8e0b2014-08-26Henrik Grubbström (Grubba)  args += ({ "--slow-query-log-file="+slow_query_log+".1", "--slow-query-log", }); } else { // NB: Deprecated in MySQL 5.1.29 and removed in MySQL 5.6.1. args += ({ "--log-slow-queries="+slow_query_log+".1" }); }
a4d88d2007-12-22Jonas Wallden  report_debug("Setting MySQL's slow query log to \"%s.1\"\n", slow_query_log);
3363a02007-12-07Martin Jonsson  }
ab8e0b2014-08-26Henrik Grubbström (Grubba)  if (log_queries_to_stdout) {
0b22822014-09-05Henrik Grubbström (Grubba)  if (normalized_mysql_version > "005.006.") {
ab8e0b2014-08-26Henrik Grubbström (Grubba)  args += ({ "--general-log-file=/dev/stdout", "--general-log", }); } else { // NB: Deprecated in MySQL 5.1.29 and removed in MySQL 5.6.1. args += ({"--log=/dev/stdout"}); } }
c5e97b2009-06-25Martin Stjernholm 
01ff7b2002-02-05Henrik Grubbström (Grubba)  // Create the configuration file.
dab5a02013-02-14Henrik Grubbström (Grubba)  int force = !file_stat( datadir+"/my.cfg" ); string cfg_file = (Stdio.read_bytes(datadir + "/my.cfg") || "[mysqld]\n"
f300672013-12-10Henrik Grubbström (Grubba)  "max_allowed_packet = 128M\n"
920f062013-02-05Build system  "net_buffer_length = 8K\n"
89cef92007-08-27Fredrik Noring  "query-cache-type = 2\n" "query-cache-size = 32M\n"
38a0ec2014-09-02Henrik Grubbström (Grubba)  "default-storage-engine = MYISAM\n"
1b5e902014-09-26Henrik Grubbström (Grubba)  "innodb-data-file-path=ibdata1:10M:autoextend\n"
e4a4432002-03-22Jonas Wallden #ifndef UNSAFE_MYSQL
9e29fc2002-03-15Henrik Grubbström (Grubba)  "local-infile = 0\n"
e4a4432002-03-22Jonas Wallden #endif
1d6a5e2002-02-27Henrik Grubbström (Grubba)  "skip-name-resolve\n"
8139652013-02-18Henrik Grubbström (Grubba)  "character-set-server=latin1\n" "collation-server=latin1_swedish_ci\n"
cae2242004-10-19Martin Stjernholm  "bind-address = "+env->MYSQL_HOST+"\n" + (uid ? "user = " + uid : "") + "\n");
1d6a5e2002-02-27Henrik Grubbström (Grubba) 
72de912014-09-26Henrik Grubbström (Grubba)  string normalized_cfg_file = replace(cfg_file, "_", "-");
dab5a02013-02-14Henrik Grubbström (Grubba)  // Check if we need to update the contents of the config file. // // NB: set-variable became optional after MySQL 4.0.2, // and was deprecated in MySQL 5.5.
72de912014-09-26Henrik Grubbström (Grubba)  if (has_value(normalized_cfg_file, "set-variable=") || has_value(normalized_cfg_file, "set-variable =")) {
dab5a02013-02-14Henrik Grubbström (Grubba)  report_debug("Repairing pre Mysql 4.0.2 syntax in %s/my.cfg.\n", datadir); cfg_file = replace(cfg_file, ({ "set-variable=",
72de912014-09-26Henrik Grubbström (Grubba)  "set-variable = ", "set-variable =", "set_variable=", "set_variable = ", "set_variable =", }), ({ "", "", "", "", "", "", }));
dab5a02013-02-14Henrik Grubbström (Grubba)  force = 1; }
1b5e902014-09-26Henrik Grubbström (Grubba)  if ((normalized_mysql_version > "005.000.") && !has_value(normalized_cfg_file, "innodb-data-file-path")) { // It seems the defaults for this variable have changed // from "ibdata1:10M:autoextend" to "ibdata1:12M:autoextend". // For some reason InnoDB doesn't always auto-detect correctly. // cf [bug 7264]. array a = cfg_file/"[mysqld]"; if (sizeof(a) > 1) { report_debug("Adding innodb-data-file-path to %s/my.cfg.\n", datadir); int initial = 10; // 10 MB -- The traditional setting. int bytes = Stdio.file_size(datadir + "/ibdata1"); if (bytes) { // ibdata1 grows in increments of 8 MB. // Assumes that the initial default size won't grow to 18 MB.
c54d662014-09-26Anders Johansson  initial = ((bytes / (1024 * 1024)) % 8) + 8;
1b5e902014-09-26Henrik Grubbström (Grubba)  if (initial < 10) initial += 8; } report_debug("%O\n", "ibdata1:" + initial + "M:autoextend"); a[1] = "\n" "innodb-data-file-path=ibdata1:" + initial + "M:autoextend" + a[1];
c54d662014-09-26Anders Johansson  cfg_file = a * "[mysqld]";
1b5e902014-09-26Henrik Grubbström (Grubba)  force = 1; } else { report_warning("Mysql configuration file %s/my.cfg lacks\n" "InnoDB data file path entry, " "and automatic repairer failed.\n", datadir); } }
0b22822014-09-05Henrik Grubbström (Grubba)  if ((normalized_mysql_version > "005.002.") &&
72de912014-09-26Henrik Grubbström (Grubba)  !has_value(normalized_cfg_file, "character-set-server")) {
8139652013-02-18Henrik Grubbström (Grubba)  // The default character set was changed sometime // during the MySQL 5.x series. We need to set // the default to latin1 to avoid breaking old // internal tables (like eg roxen/dbs) where fields // otherwise shrink to a third. array a = cfg_file/"[mysqld]"; if (sizeof(a) > 1) { report_debug("Adding default character set entries to %s/my.cfg.\n", datadir); a[1] = "\n" "character-set-server=latin1\n" "collation-server=latin1_swedish_ci" + a[1]; cfg_file = a * "[mysqld]"; force = 1; } else { report_warning("Mysql configuration file %s/my.cfg lacks\n" "character set entry, and automatic repairer failed.\n", datadir); }
38a0ec2014-09-02Henrik Grubbström (Grubba)  }
0b22822014-09-05Henrik Grubbström (Grubba)  if ((normalized_mysql_version > "005.005.") &&
72de912014-09-26Henrik Grubbström (Grubba)  !has_value(normalized_cfg_file, "default-storage-engine")) {
38a0ec2014-09-02Henrik Grubbström (Grubba)  // The default storage engine was changed to InnoDB in MySQL 5.5. // We need to set the default to MyISAM to avoid breaking old code // due to different parameter limits (eg key lengths). array a = cfg_file/"[mysqld]"; if (sizeof(a) > 1) { report_debug("Adding default storage engine entry to %s/my.cfg.\n", datadir); a[1] = "\n" "default-storage-engine = MYISAM" + a[1]; cfg_file = a * "[mysqld]"; force = 1; } else { report_warning("Mysql configuration file %s/my.cfg lacks\n" "storage engine entry, and automatic repairer failed.\n", datadir); }
8139652013-02-18Henrik Grubbström (Grubba)  }
92b6fc2018-03-13Henrik Grubbström (Grubba)  if ((normalized_mysql_version > "010.002.003") && !has_value(normalized_cfg_file, "sql_mode")) { // Since MariaDB 10.2.4, SQL_MODE is by default set to NO_AUTO_CREATE_USER, // NO_ENGINE_SUBSTITUTION, STRICT_TRANS_TABLES, ERROR_FOR_DIVISION_BY_ZERO. // In earlier versions of MariaDB 10.2, and since MariaDB 10.1.7, SQL_MODE // is by default set to NO_ENGINE_SUBSTITUTION, NO_AUTO_CREATE_USER. // For earlier versions of MariaDB 10.1, and MariaDB 10.0 and before, no // default is set. // // This change in 10.2 can cause queries to fail, complaining about // no default values: // // big_query(): Query failed (Field 'x' doesn't have a default value) // // cf: // https://www.slickdev.com/2017/09/05/mariadb-10-2-field-xxxxxxx-doesnt-default-value-error/ array a = cfg_file/"[mysqld]"; if (sizeof(a) > 1) { report_debug("Adding sql_mode entry to %s/my.cfg.\n", datadir); a[1] = "\n" "sql_mode = NO_ENGINE_SUBSTITUTION" + a[1]; cfg_file = a * "[mysqld]"; force = 1; } else { report_warning("Mysql configuration file %s/my.cfg lacks\n" "sql_mode entry, and automatic repairer failed.\n", datadir); } }
1d6a5e2002-02-27Henrik Grubbström (Grubba) #ifdef __NT__
8139652013-02-18Henrik Grubbström (Grubba)  cfg_file = replace(cfg_file, ({ "\r\n", "\n" }), ({ "\r\n", "\r\n" }));
1d6a5e2002-02-27Henrik Grubbström (Grubba) #endif /* __NT__ */
dab5a02013-02-14Henrik Grubbström (Grubba)  if(force)
8545172002-12-11Mattias Andersson  catch(Stdio.write_file(datadir+"/my.cfg", cfg_file));
097e182009-12-09Martin Stjernholm  // Keep mysql's logging to stdout and stderr when running in --once // mode, to get it more synchronous. Stdio.File errlog = !once_mode && Stdio.File( err_log, "wct" );
39e91c2008-02-13Martin Stjernholm 
7573ab2008-02-06Fredrik Noring  string mysql_table_check = Stdio.read_file(combine_path(query_configuration_dir(), "_mysql_table_check")); if(!mysql_table_check) mysql_table_check = "--force --silent --fast\n" "--myisam-recover=QUICK,FORCE\n"; sscanf(mysql_table_check, "%s\n%s\n", string myisamchk_args, string mysqld_extra_args);
7dfd2e2009-02-06Jonas Wallden  if(myisamchk_args && sizeof(myisamchk_args)) { if (string myisamchk = mysql_location->myisamchk) low_check_mysql(myisamchk, datadir, (myisamchk_args / " ") - ({ "" }), errlog); else { report_warning("No myisamchk found in %s. Tables not checked.\n", mysql_location->basedir); } }
39e91c2008-02-13Martin Stjernholm 
7573ab2008-02-06Fredrik Noring  if(mysqld_extra_args && sizeof(mysqld_extra_args)) args += (mysqld_extra_args/" ") - ({ "" });
7dfd2e2009-02-06Jonas Wallden  args = ({ mysql_location->mysqld }) + args;
825cb92001-01-31Per Hedbor  Stdio.File devnull #ifndef __NT__ = Stdio.File( "/dev/null", "w" ) #endif ;
7062432009-02-13Martin Stjernholm #ifdef DEBUG report_debug ("MySQL server command: %s%{\n %s%}\n", args[0], args[1..]); #else report_debug ("MySQL server executable: %s\n", args[0]); #endif
29ac052012-01-18Henrik Grubbström (Grubba)  rm(pid_file);
92ced82011-09-12Henrik Grubbström (Grubba)  Process.Process p = Process.Process( args, ([ "environment":env, "stdin":devnull, "stdout":errlog, "stderr":errlog ]) );
4e64912001-11-14Tomas Nilsson #ifdef __NT__ if (p)
29ac052012-01-18Henrik Grubbström (Grubba)  Stdio.write_file(pid_file, p->pid() + "\n");
4e64912001-11-14Tomas Nilsson #endif
825cb92001-01-31Per Hedbor }
baa9d52001-01-27Per Hedbor int mysql_path_is_remote;
c5e97b2009-06-25Martin Stjernholm void start_mysql (void|int log_queries_to_stdout)
74e3902000-12-30Per Hedbor {
850c282001-01-10Per Hedbor  Sql.Sql db;
baa9d52001-01-27Per Hedbor  int st = gethrtime();
cd5f542005-12-21Fredrik Noring  string mysqldir = query_mysql_data_dir();
8b32892003-03-02Anders Johansson  string err_log = mysqldir+"/error_log"; string pid_file = mysqldir+"/mysql_pid"; int do_tailf_threaded = 0; #ifdef THREADS // Linux pthreads hangs in mutex handling if uid is changed // permanently and there are threads already running. if (uname()->sysname != "Linux") do_tailf_threaded = 1; #endif
baa9d52001-01-27Per Hedbor  void assure_that_base_tables_exists( )
74e3902000-12-30Per Hedbor  { // 1: Create the 'ofiles' database.
22c98c2001-08-13Per Hedbor  if( mixed err = catch( db->query( "SELECT id from local.precompiled_files WHERE id=''" ) ) )
74e3902000-12-30Per Hedbor  {
22c98c2001-08-13Per Hedbor  db->query( "CREATE DATABASE IF NOT EXISTS local" ); connect_to_my_mysql(0,"local") ->query( "CREATE TABLE precompiled_files ("
0c0e362001-01-01Martin Nilsson  "id CHAR(30) NOT NULL PRIMARY KEY, " "data MEDIUMBLOB NOT NULL, " "mtime INT UNSIGNED NOT NULL)" );
22c98c2001-08-13Per Hedbor  // At this moment new_master does not exist, and // DBManager can not possibly compile. :-) call_out( lambda(){ new_master->resolv("DBManager.is_module_table") ( 0, "local", "precompiled_files", "Contains binary object code for .pike files. " "This information is used to shorten the " "boot time of Roxen by keeping the compiled " "data instead of recompiling it every time."); }, 1 );
74e3902000-12-30Per Hedbor  }
9593822017-10-18Henrik Grubbström (Grubba)  // At this moment new_master does not exist, and // DBManager can not possibly compile. :-) call_out( lambda(){ // Inhibit backups of the precompiled_files table. new_master->resolv("DBManager.inhibit_backups") ("local", "precompiled_files"); }, 1 );
74e3902000-12-30Per Hedbor  if( remove_dumped ) {
0c0e362001-01-01Martin Nilsson  report_notice("Removing precompiled files\n");
b00dfe2001-02-05Martin Stjernholm  if (mixed err = catch
5238512001-01-22Per Hedbor  {
22c98c2001-08-13Per Hedbor  db->query( "DELETE FROM local.precompiled_files" );
92e6222001-09-04Per Hedbor  db->query( "DELETE FROM local.compiled_formats" );
4491d72002-09-17Martin Stjernholm  // Clear the modules cache too since it currently doesn't // depend on the module path properly. db->query( "DELETE FROM local.modules" );
b00dfe2001-02-05Martin Stjernholm  }) { #ifdef MYSQL_CONNECT_DEBUG werror ("Error removing dumped files: %s", describe_error (err)); #endif }
74e3902000-12-30Per Hedbor  } };
baa9d52001-01-27Per Hedbor  void connected_ok(int was) { string version = db->query( "SELECT VERSION() AS v" )[0]->v;
56509c2001-06-30Martin Stjernholm  report_debug("\b%s %s [%.1fms]\n",
baa9d52001-01-27Per Hedbor  (was?"Was running":"Done"), version, (gethrtime()-st)/1000.0); if( (float)version < 3.23 )
8a79f82003-02-05Jonas Wallden  report_debug( "Warning: This is a very old MySQL. "
f0c9912004-04-26Henrik Grubbström (Grubba)  "Please use 3.23.* or later.\n");
baa9d52001-01-27Per Hedbor 
d084092006-08-21Henrik Grubbström (Grubba)  if ((float)version > 4.0) { // UTF8 and explicit character set markup was added in Mysql 4.1.x. add_constant("ROXEN_MYSQL_SUPPORTS_UNICODE", 1); }
097e182009-12-09Martin Stjernholm  if( !do_tailf_threaded && !once_mode ) do_tailf(0, err_log );
baa9d52001-01-27Per Hedbor  assure_that_base_tables_exists(); };
2c241c2003-03-03Anders Johansson  void start_tailf() { if( do_tailf_threaded ) { thread_create( do_tailf, 1, err_log ); sleep(0.1);
e1f8142015-04-28Jonas Walldén  } else {
2c241c2003-03-03Anders Johansson  do_tailf(0, err_log ); void do_do_tailf( ) { call_out( do_do_tailf, 1 ); do_tailf( 0, err_log ); }; call_out( do_do_tailf, 0 ); } };
8a79f82003-02-05Jonas Wallden  report_debug( "Starting MySQL ... \b");
baa9d52001-01-27Per Hedbor 
b00dfe2001-02-05Martin Stjernholm  if( mixed err = catch( db = connect_to_my_mysql( 0, "mysql" ) ) ) { #ifdef MYSQL_CONNECT_DEBUG
8a79f82003-02-05Jonas Wallden  werror ("Error connecting to local MySQL: %s", describe_error (err));
b00dfe2001-02-05Martin Stjernholm #endif } else {
097e182009-12-09Martin Stjernholm  if (!once_mode) start_tailf();
74e3902000-12-30Per Hedbor  connected_ok(1); return; }
baa9d52001-01-27Per Hedbor  if( mysql_path_is_remote ) { report_debug( "******************** FATAL ******************\n"
8a79f82003-02-05Jonas Wallden  "Cannot connect to the specified MySQL server\n"
baa9d52001-01-27Per Hedbor  " Aborting\n" "******************** FATAL ******************\n" ); exit(1); }
786a222012-01-19Henrik Grubbström (Grubba)  mkdirhier( mysqldir+"/mysql/" );
29ac052012-01-18Henrik Grubbström (Grubba) #ifndef __NT__ if (!Stdio.exist(pid_file)) sleep(0.1); if (Stdio.exist(pid_file)) { int pid; int prev_pid = -1; int cnt; for (cnt = 0; cnt < 600; cnt++) { // Check if the mysqld process is running (it could eg be starting up). pid = pid || (int)String.trim_all_whites(Stdio.read_bytes(pid_file)||""); if (pid) { if (!kill(pid, 0) && errno() == System.ESRCH) { // The process has gone away.
0be6472012-01-18Henrik Grubbström (Grubba)  if (prev_pid == pid) { // The pid_file is stale. rm(pid_file); }
29ac052012-01-18Henrik Grubbström (Grubba)  prev_pid = pid; pid = 0; // Reread the pid file. cnt = 0; sleep(0.1); continue; } } else if (prev_pid) { // A new process might be taking over, give it some more time... prev_pid = 0; sleep(0.1); continue; } else { // No active process is claiming the pid file. break; } report_debug("Retrying to connect to local MySQL (pid: %d).\n", pid); if( mixed err = catch( db = connect_to_my_mysql( 0, "mysql" ) ) ) { #ifdef MYSQL_CONNECT_DEBUG werror ("Error connecting to local MySQL: %s", describe_error (err)); #endif } else { if (!once_mode) start_tailf(); connected_ok(1); return; } sleep(0.1); } if (pid && (cnt >= 600)) { report_error("Process %d is claiming to be MySQLd (pid file: %O),\n" "but doesn't answer to connection attempts.\n", pid, pid_file); exit(1); }
786a222012-01-19Henrik Grubbström (Grubba)  }
29ac052012-01-18Henrik Grubbström (Grubba) #endif // Steal the mysqld pid_file, and claim that we are mysqld // until we actually start mysqld. Stdio.write_file(pid_file, getpid()+"\n");
8b32892003-03-02Anders Johansson  rm( err_log );
0870292009-12-10Martin Stjernholm  if (!once_mode) start_tailf();
baa9d52001-01-27Per Hedbor 
10732c2001-01-10Per Hedbor  if( !file_stat( mysqldir+"/mysql/user.MYD" ) || !file_stat( mysqldir+"/mysql/host.MYD" ) || !file_stat( mysqldir+"/mysql/db.MYD" ) )
74e3902000-12-30Per Hedbor  {
7107532001-01-31Per Hedbor #ifdef DEBUG
8a79f82003-02-05Jonas Wallden  report_debug("MySQL data directory does not exist -- copying template\n");
7107532001-01-31Per Hedbor #endif
73c22e2002-05-21Henrik Grubbström (Grubba)  if (!file_stat(mysqldir)) { #ifdef DEBUG report_debug("Creating directory %O\n", mysqldir); #endif /* DEBUG */ mkdirhier(combine_path(mysqldir, "../")); mkdir(mysqldir, 0750); }
15e5c22001-01-22Per Hedbor  Filesystem.System tar = Filesystem.Tar( "etc/mysql-template.tar" );
74e3902000-12-30Per Hedbor  foreach( tar->get_dir( "mysql" ), string f ) {
7107532001-01-31Per Hedbor #ifdef DEBUG
74e3902000-12-30Per Hedbor  report_debug("copying "+f+" ... ");
7107532001-01-31Per Hedbor #endif
74e3902000-12-30Per Hedbor  Stdio.File to = Stdio.File( mysqldir+f, "wct" ); Stdio.File from = tar->open( f, "r" ); to->write( from->read() );
7107532001-01-31Per Hedbor #ifdef DEBUG
74e3902000-12-30Per Hedbor  report_debug("\n");
7107532001-01-31Per Hedbor #endif
74e3902000-12-30Per Hedbor  } }
bed50e2001-01-21Per Hedbor 
7dfd2e2009-02-06Jonas Wallden  low_start_mysql( mysqldir,
baa9d52001-01-27Per Hedbor #if constant(getpwuid)
c5e97b2009-06-25Martin Stjernholm  (getpwuid(getuid()) || ({0}))[ 0 ],
825cb92001-01-31Per Hedbor #else /* Ignored by the start_mysql script */
c5e97b2009-06-25Martin Stjernholm  0,
baa9d52001-01-27Per Hedbor #endif
c5e97b2009-06-25Martin Stjernholm  log_queries_to_stdout);
bed50e2001-01-21Per Hedbor 
74e3902000-12-30Per Hedbor  int repeat; while( 1 ) {
510bea2001-08-09Per Hedbor  sleep( 0.1 );
ed50962009-02-17Jonas Wallden  if( repeat++ > 200 )
74e3902000-12-30Per Hedbor  {
097e182009-12-09Martin Stjernholm  if( !do_tailf_threaded && !once_mode ) do_tailf(0, err_log );
8a79f82003-02-05Jonas Wallden  report_fatal("\nFailed to start MySQL. Aborting\n");
74e3902000-12-30Per Hedbor  exit(1); }
b00dfe2001-02-05Martin Stjernholm  if( mixed err = catch( db = connect_to_my_mysql( 0, "mysql" ) ) ) { #ifdef MYSQL_CONNECT_DEBUG
8a79f82003-02-05Jonas Wallden  werror ("Error connecting to local MySQL: %s", describe_error (err));
b00dfe2001-02-05Martin Stjernholm #endif }
bd35502006-08-23Anders Johansson  else if (db)
510bea2001-08-09Per Hedbor  {
74e3902000-12-30Per Hedbor  connected_ok(0); return; } } }
c423772009-03-24Henrik Grubbström (Grubba) int low_dump( string file, program|void p )
8f81d82001-01-03Per Hedbor {
2cff132008-08-08Martin Stjernholm #ifdef ENABLE_DUMPING
8f81d82001-01-03Per Hedbor  if( file[0] != '/' )
cefd172011-12-27Martin Stjernholm  file = server_dir +"/"+ file;
8f81d82001-01-03Per Hedbor #ifdef __NT__ file = normalize_path( file ); #endif if(!p) p = new_master->programs[ replace(file, "//", "/" ) ]; #ifdef __NT__ if( !p ) { if( sscanf( file, "%*s:/%s", file ) ) { file = "/"+file; p = new_master->programs[ replace(file, "//", "/" ) ]; } } #endif array q; #ifdef MUCHU_DUMP_DEBUG # define DUMP_DEBUG #endif if(!p) { #ifdef DUMP_DEBUG werror(file+" not loaded, and thus cannot be dumped.\n"); #endif return 0; } if( new_master->has_set_on_load[ file ] == 1 ) {
3bcf392001-02-23Per Hedbor  m_delete( new_master->has_set_on_load, file );
8f81d82001-01-03Per Hedbor  if( q = catch( new_master->dump_program( file, p ) ) ) { #ifdef DUMP_DEBUG
080af72001-03-29Per Hedbor  report_debug("** Cannot encode "+file+": "+describe_error(q)+"\n");
8f81d82001-01-03Per Hedbor #else array parts = replace(file, "//", "/") / "/"; if (sizeof(parts) > 3) parts = parts[sizeof(parts)-3..]; report_debug("Notice: Dumping failed for " + parts*"/"+" (not a bug)\n"); #endif return -1; } #ifdef DUMP_DEBUG werror( file+" dumped successfully\n" ); #endif return 1; } #ifdef MUCHO_DUMP_DEBUG werror(file+" already dumped (and up to date)\n"); #endif
2cff132008-08-08Martin Stjernholm #endif // ENABLE_DUMPING
8f81d82001-01-03Per Hedbor  return 0; }
c423772009-03-24Henrik Grubbström (Grubba) int dump( string file, program|void p ) { // int t = gethrtime(); int res = low_dump(file, p); // werror("dump(%O, %O): %.1fms\n", file, p, (gethrtime()-t)/1000.0); return res; }
3e3bab2001-01-19Per Hedbor object(Stdio.Stat)|array(int) da_Stat_type;
79ca872000-11-24Per Hedbor LocaleString da_String_type;
af81b32000-02-15Henrik Grubbström (Grubba) void do_main( int argc, array(string) argv )
87d06d2000-02-09Per Hedbor {
8ad9292000-03-13Martin Nilsson  array(string) hider = argv;
7339a02000-02-10Per Hedbor  argv = 0;
097e182009-12-09Martin Stjernholm  catch (once_mode = (int)Getopt.find_option(hider + ({}), "o", "once"));
8a869b2003-09-15Martin Stjernholm #ifdef GC_TRACE
bdc5ae2009-11-20Martin Stjernholm  trace (GC_TRACE, "gc");
8a869b2003-09-15Martin Stjernholm #endif
8b32892003-03-02Anders Johansson  nwrite = early_nwrite;
8f81d82001-01-03Per Hedbor  add_constant( "connect_to_my_mysql", connect_to_my_mysql );
4f74c82001-08-09Per Hedbor  add_constant( "clear_connect_to_my_mysql_cache", clear_connect_to_my_mysql_cache );
e1f8142015-04-28Jonas Walldén  #if !constant(thread_create) report_debug(#" ------ FATAL ---------------------------------------------------- Roxen requires Pike with thread support. ----------------------------------------------------------------- "); exit(-1); #endif
ed3d532000-10-30Per Hedbor #ifdef SECURITY #if !constant(__builtin.security.Creds)
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
ed3d532000-10-30Per Hedbor ------ FATAL ---------------------------------------------------- SECURITY defined (the internal security system in roxen), but the pike binary has not been compiled --with-security. This makes it impossible for roxen to have any internal security at all. -----------------------------------------------------------------
84fff72014-08-29Henrik Grubbström (Grubba) 
ed3d532000-10-30Per Hedbor "); exit(-1); #endif #endif
1768d32000-03-09Per Hedbor  if( (-1&0xffffffff) < 0 ) {
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
234e792000-09-23Henrik Grubbström (Grubba) ------- WARNING -----------------------------------------------
f0c9912004-04-26Henrik Grubbström (Grubba) Roxen requires bignum support in Pike since version 2.4.
8a79f82003-02-05Jonas Wallden Please recompile Pike with gmp / bignum support to run Roxen.
1768d32000-03-09Per Hedbor 
8a79f82003-02-05Jonas Wallden It might still be possible to start Roxen, but the functionality will be affected, and stange errors might occur.
234e792000-09-23Henrik Grubbström (Grubba) ---------------------------------------------------------------
1768d32000-03-09Per Hedbor 
84fff72014-08-29Henrik Grubbström (Grubba) 
1768d32000-03-09Per Hedbor "); }
23c6421999-11-29Per Hedbor #ifdef NOT_INSTALLED
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
ae46e92000-09-23Per Hedbor ------- WARNING -----------------------------------------------
8a79f82003-02-05Jonas Wallden You are running with an un-installed Pike binary.
23c6421999-11-29Per Hedbor 
58a6431999-12-20Martin Nilsson Please note that this is unsupported, and might stop working at
23c6421999-11-29Per Hedbor any time, since some things are done differently in uninstalled
8a79f82003-02-05Jonas Wallden Pikes, as an example the module search paths are different, and
23c6421999-11-29Per Hedbor some environment variables are ignored.
ae46e92000-09-23Per Hedbor ---------------------------------------------------------------
23c6421999-11-29Per Hedbor 
84fff72014-08-29Henrik Grubbström (Grubba) 
23c6421999-11-29Per Hedbor "); #endif
c745112014-10-21Henrik Grubbström (Grubba) #if __VERSION__ < 8.0
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
23c6421999-11-29Per Hedbor 
58a6431999-12-20Martin Nilsson ******************************************************
c745112014-10-21Henrik Grubbström (Grubba) Roxen " + roxen_ver + #" requires Pike 8.0 or newer.
234e792000-09-23Henrik Grubbström (Grubba) Please install a newer version of Pike.
58a6431999-12-20Martin Nilsson ******************************************************
23c6421999-11-29Per Hedbor  ");
af81b32000-02-15Henrik Grubbström (Grubba)  _exit(0); /* 0 means stop start script looping */
c745112014-10-21Henrik Grubbström (Grubba) #endif /* __VERSION__ < 8.0 */
1dc04b2001-08-24Martin Stjernholm  #if !constant (Mysql.mysql) report_debug (#" ******************************************************
f0c9912004-04-26Henrik Grubbström (Grubba) Roxen requires MySQL support in Pike since version 2.4.
1dc04b2001-08-24Martin Stjernholm Your Pike has been compiled without support for MySQL. Please install MySQL client libraries and reconfigure
b23a632009-02-12Martin Stjernholm and rebuild Pike from source.
1dc04b2001-08-24Martin Stjernholm ****************************************************** "); _exit(0); // 0 means stop start script looping #endif // !constant (Mysql.mysql)
23c6421999-11-29Per Hedbor 
e2468a2012-11-14Stefan Wallström #if !constant (Regexp.PCRE) report_debug (#" ****************************************** Roxen requires Regexp.PCRE support in Pike ****************************************** "); _exit(0); // 0 means stop start script looping #endif // !constant (Regexp.PCRE)
d5c8522016-06-29Henrik Grubbström (Grubba)  string s; if (!catch(s = _Roxen->make_http_headers((["a\r\n":"b\r\n"]), 1)) && (sizeof(s/"\r\n") > 2)) {
16bb3e2005-10-28Henrik Grubbström (Grubba)  add_constant("HAVE_OLD__Roxen_make_http_headers", 1); report_debug(#" ------- WARNING ----------------------------------------------- Old or broken _Roxen.make_http_headers() detected.
81d0e72016-07-01Henrik Grubbström (Grubba) Roxen 6.0 prefers Pike 8.0.270 or later.
16bb3e2005-10-28Henrik Grubbström (Grubba) Roxen will still work, but at lower performance. Please install a newer version of Pike. --------------------------------------------------------------- "); }
99da852005-11-14Henrik Grubbström (Grubba)  Stdio.Stat stat = file_stat("etc/include/version.h"); if (stat && (stat->mtime > time())) { report_debug(#" ------- WARNING ----------------------------------------------- System time is incorrect. System time: %s Check time: %s This may cause unreliable operation. Please set the correct system time. --------------------------------------------------------------- ", ctime(stat->mtime), ctime(time(1))); }
af81b32000-02-15Henrik Grubbström (Grubba)  int start_time = gethrtime();
1e3d621997-02-18Niels Möller  string path = make_path("base_server", "etc/include", ".");
930ddd1999-08-06Per Hedbor  last_was_nl = 1;
4f8bbe2003-03-25Jonas Wallden  mapping un = uname(); string hostinfo = (un->sysname || "") + " " + (un->release || "") + (un->machine ? (" (" + un->machine + ")") : "");
99da852005-11-14Henrik Grubbström (Grubba)  string pike_ver = version(); if ((__REAL_MAJOR__ != __MAJOR__) || (__REAL_MINOR__ != __MINOR__)) { pike_ver += sprintf(" (in Pike %d.%d compat mode)", __MAJOR__, __MINOR__); }
4f8bbe2003-03-25Jonas Wallden  report_debug("-" * 65 + "\n"
99da852005-11-14Henrik Grubbström (Grubba)  "Pike version: " + pike_ver + "\n"
4f8bbe2003-03-25Jonas Wallden  "Product version: " + roxen_product_name + " " + roxen_version() + "\n" "Operating system: " + hostinfo + "\n");
1e3d621997-02-18Niels Möller  master()->putenv("PIKE_INCLUDE_PATH", path);
f6250b1998-03-28Henrik Grubbström (Grubba)  foreach(path/":", string p) { add_include_path(p);
b796b51998-11-18Per Hedbor  add_program_path(p);
f6250b1998-03-28Henrik Grubbström (Grubba)  }
8cb7831999-03-27Henrik Grubbström (Grubba) 
07e2cc2001-12-04Martin Stjernholm  add_constant ("get_cvs_id", get_cvs_id); add_constant ("add_cvs_ids", add_cvs_ids); add_constant ("describe_backtrace", describe_backtrace);
b5e3b02010-05-19Fredrik Noring  add_constant ("call_out", call_out);
07e2cc2001-12-04Martin Stjernholm 
4446d81999-12-07Henrik Grubbström (Grubba) #ifdef INTERNAL_ERROR_DEBUG add_constant("throw", paranoia_throw); #endif /* INTERNAL_ERROR_DEBUG */
9eeb5c2000-05-22Per Hedbor  add_constant( "mark_fd", mark_fd );
22c98c2001-08-13Per Hedbor  add_constant( "isodate", isodate );
9eeb5c2000-05-22Per Hedbor 
79ca872000-11-24Per Hedbor  add_constant( "LocaleString", typeof(da_String_type) );
3e3bab2001-01-19Per Hedbor  add_constant( "Stat", typeof(da_Stat_type) );
79ca872000-11-24Per Hedbor 
af81b32000-02-15Henrik Grubbström (Grubba)  mixed err;
8f81d82001-01-03Per Hedbor  add_constant("open", open); add_constant("roxen_path", roxen_path);
e30cf42000-03-13Per Hedbor  add_constant("roxen_version", roxen_version);
5a272a2002-05-07Jonas Wallden  add_constant("roxen_dist_version", dist_version);
88edde2009-04-20Jonas Wallden  add_constant("roxen_dist_os", dist_os);
93963e2002-03-19Martin Stjernholm  add_constant("roxen_release", release || roxen_release);
cdddcb2002-04-08Johan Schön  add_constant("roxen_is_cms", roxen_is_cms); add_constant("roxen_product_name", roxen_product_name);
a01b5d2013-08-19Tobias Liin  add_constant("roxen_product_code", roxen_product_code);
8f81d82001-01-03Per Hedbor  add_constant("lopen", lopen);
b395ab2008-02-05Henrik Grubbström (Grubba)  add_constant("lfile_stat", lfile_stat);
adbc522011-01-20Henrik Grubbström (Grubba)  add_constant("lfile_path", lfile_path);
e30cf42000-03-13Per Hedbor  add_constant("report_notice", report_notice);
8f81d82001-01-03Per Hedbor  add_constant("report_debug", report_debug); add_constant("report_warning",report_warning); add_constant("report_error", report_error); add_constant("report_fatal", report_fatal);
c5b9512009-12-20Martin Stjernholm  add_constant("report_notice_for", report_notice_for); add_constant("report_warning_for", report_warning_for); add_constant("report_error_for", report_error_for); add_constant("report_fatal_for", report_fatal_for);
8daece2001-02-05Martin Stjernholm  add_constant("report_warning_sparsely", report_warning_sparsely); add_constant("report_error_sparsely", report_error_sparsely);
8f81d82001-01-03Per Hedbor  add_constant("werror", roxen_perror);
d673402002-01-28Martin Stjernholm  add_constant("perror", roxen_perror); // For compatibility.
8f81d82001-01-03Per Hedbor  add_constant("roxen_perror", roxen_perror); add_constant("roxenp", lambda() { return roxen; }); add_constant("ST_MTIME", ST_MTIME ); add_constant("ST_CTIME", ST_CTIME ); add_constant("ST_SIZE", ST_SIZE ); add_constant("mkdirhier", mkdirhier ); #if !constant(uname)
51ba6d2000-04-12Per Hedbor  add_constant( "uname", uname );
8f81d82001-01-03Per Hedbor #endif #ifdef __NT__
51ba6d2000-04-12Per Hedbor  add_constant( "getuid", lambda(){ return 0; } ); add_constant( "getgid", lambda(){ return 0; } ); add_constant( "geteuid", lambda(){ return 0; } ); add_constant( "getegid", lambda(){ return 0; } ); #endif
8f81d82001-01-03Per Hedbor  add_constant("r_rm", rm); add_constant("r_mv", mv);
2d3cd82011-12-28Martin Stjernholm  add_constant("r_cp", r_cp);
8f81d82001-01-03Per Hedbor  add_constant("r_get_dir", r_get_dir); add_constant("r_file_stat", file_stat);
2d3cd82011-12-28Martin Stjernholm  add_constant("r_is_file", r_is_file); add_constant("r_is_dir", r_is_dir); add_constant("r_is_link", r_is_link); add_constant("r_exist", r_exist); add_constant("r_read_bytes", r_read_bytes);
8f81d82001-01-03Per Hedbor  add_constant("roxenloader", this_object()); add_constant("ErrorContainer", ErrorContainer);
e41c9d2017-04-21Henrik Grubbström (Grubba) #ifdef THREADS add_constant("euid_egid_lock", euid_egid_lock); #endif #ifndef __NT__ if(!getuid()) add_constant("Privs", Privs); else #endif /* !__NT__ */ add_constant("Privs", class { void create(string reason, int|string|void uid, int|string|void gid) {} });
3c6d942001-06-25Martin Stjernholm  add_constant("_cur_rxml_context", Thread.Local());
846a912017-09-29Henrik Grubbström (Grubba)  int mysql_only_mode = (int)Getopt.find_option(hider, "mysql-only", ({ "mysql-only" })); if (mysql_only_mode) { // Force --once mode. // // This avoids starting eg the tailf thread. once_mode = 1; }
c5e97b2009-06-25Martin Stjernholm  if (has_value (hider, "--mysql-log-queries")) { hider -= ({"--mysql-log-queries"}); argc = sizeof (hider); start_mysql (1); } else start_mysql (0);
74e3902000-12-30Per Hedbor 
846a912017-09-29Henrik Grubbström (Grubba)  if (mysql_only_mode) { exit(0); }
af81b32000-02-15Henrik Grubbström (Grubba)  if (err = catch {
342c0f2001-09-03Marcus Comstedt  if(master()->relocate_module) add_constant("PIKE_MODULE_RELOC", 1);
8ad9292000-03-13Martin Nilsson  replace_master(new_master=[object(__builtin.__master)](((program)"etc/roxen_master.pike")()));
af81b32000-02-15Henrik Grubbström (Grubba)  }) {
ed3d532000-10-30Per Hedbor  werror("Initialization of Roxen's master failed:\n" "%s\n", describe_backtrace(err));
af81b32000-02-15Henrik Grubbström (Grubba)  exit(1); }
5e89211997-02-13Per Hedbor 
6ba1c02010-05-06Henrik Grubbström (Grubba)  // Restore describe_backtrace(), which was zapped by the new master. add_constant ("describe_backtrace", describe_backtrace);
8f81d82001-01-03Per Hedbor 
5c27a22000-09-23Per Hedbor #if constant( Gz.inflate )
6465b92000-09-27Per Hedbor  add_constant("grbz",lambda(string d){return Gz.inflate()->inflate(d);});
5c27a22000-09-23Per Hedbor #else
6465b92000-09-27Per Hedbor  add_constant("grbz",lambda(string d){return d;});
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
b7c64a2000-09-23Per Hedbor ------- WARNING ----------------------------------------- The Gz (zlib) module is not available. The default builtin font will not be available. To get zlib support, install zlib from ftp://ftp.freesoftware.com/pub/infozip/zlib/zlib.html and recompile pike, after removing the file 'config.cache' ----------------------------------------------------------
84fff72014-08-29Henrik Grubbström (Grubba) 
b7c64a2000-09-23Per Hedbor ");
5c27a22000-09-23Per Hedbor #endif
e3ad9c1997-04-11Peter Bortas  add_constant("spawne",spawne);
51ff831997-05-13Marcus Comstedt  add_constant("spawn_pike",spawn_pike);
e3ad9c1997-04-11Peter Bortas  add_constant("popen",popen);
8c26b71998-07-13Henrik Grubbström (Grubba)  add_constant("roxen_popen",popen);
b1fca01996-11-12Per Hedbor  add_constant("init_logger", init_logger);
19924b2001-08-24Martin Nilsson  add_constant("capitalize", String.capitalize);
40dd281999-11-23Per Hedbor 
68e2e22000-02-02Martin Stjernholm  // It's currently tricky to test for Image.TTF correctly with a // preprocessor directive, so let's add a constant for it. #if constant (Image.TTF) if (sizeof (indices (Image.TTF)))
61c0ef2000-02-16Per Hedbor  {
68e2e22000-02-02Martin Stjernholm  add_constant ("has_Image_TTF", 1);
61c0ef2000-02-16Per Hedbor  add_constant( "Image.TTF", Image.TTF );
425fc62000-09-21Per Hedbor  // We can load the builtin font. add_constant("__rbf", "font_handlers/rbf" );
39ba6c2004-06-24Henrik Grubbström (Grubba)  } else #endif {
d6216d2001-05-07Per Hedbor #if constant(Image.FreeType.Face)
39ba6c2004-06-24Henrik Grubbström (Grubba)  // We can load the builtin font. add_constant("__rbf", "font_handlers/rbf" );
d6216d2001-05-07Per Hedbor #else
84fff72014-08-29Henrik Grubbström (Grubba)  report_debug(#"
b7c64a2000-09-23Per Hedbor ------- WARNING ----------------------------------------------
f0c9912004-04-26Henrik Grubbström (Grubba) Neither the Image.TTF nor the Image.FreeType module is available. True Type fonts and the default font will not be available. To get True Type support, download a Freetype package from
b7c64a2000-09-23Per Hedbor 
f0c9912004-04-26Henrik Grubbström (Grubba) http://freetype.sourceforge.net/download.html
b7c64a2000-09-23Per Hedbor 
5c27a22000-09-23Per Hedbor Install it, and then remove config.cache in pike and recompile. If this was a binary release of Roxen, there should be no need
b7c64a2000-09-23Per Hedbor to recompile the pike binary, since the one included should already have the FreeType interface module, installing the library should be enough. --------------------------------------------------------------
84fff72014-08-29Henrik Grubbström (Grubba) 
b7c64a2000-09-23Per Hedbor " );
68e2e22000-02-02Martin Stjernholm #endif
39ba6c2004-06-24Henrik Grubbström (Grubba)  }
4d36bb2000-01-25Per Hedbor 
7339a02000-02-10Per Hedbor  if( search( hider, "--long-error-file-names" ) != -1 )
1e9e091999-12-21Per Hedbor  {
7339a02000-02-10Per Hedbor  hider -= ({ "--long-error-file-names" }); argc = sizeof(hider);
1e9e091999-12-21Per Hedbor  new_master->putenv("LONG_PIKE_ERRORS", "yup"); }
c676b12015-04-21Henrik Grubbström (Grubba)  array(string) patches = get_dir("patches"); if (patches && sizeof(patches)) { report_debug("Installed patches:\n"); foreach(sort(patches), string patch) { report_debug(" %s\n", patch); } report_debug("\n"); }
1d9cfb2000-02-14Per Hedbor  // These are here to allow dumping of roxen.pike to a .o file.
8a79f82003-02-05Jonas Wallden  report_debug("Loading Pike modules ... \b");
1590412000-02-16Per Hedbor 
50b6972001-08-31Per Hedbor  add_dump_constant = new_master->add_dump_constant;
1590412000-02-16Per Hedbor  int t = gethrtime();
080af72001-03-29Per Hedbor 
a366a52001-09-06Per Hedbor  DC("Thread.Thread"); DC("Thread.Local"); DC("Thread.Mutex"); DC("Thread.MutexKey"); DC("Thread.Condition"); DC("thread_create"); DC( "Thread.Queue" );
b566202001-10-05Per Hedbor  DC("Sql"); DC("Sql.mysql");
5574b22002-05-06Martin Stjernholm  DC ("String.Buffer");
b566202001-10-05Per Hedbor 
94d7b02001-10-15Henrik Grubbström (Grubba) #if constant(Oracle.oracle)
b566202001-10-05Per Hedbor  DC("Sql.oracle"); #endif
94d7b02001-10-15Henrik Grubbström (Grubba) #if constant(Odbc.odbc)
b566202001-10-05Per Hedbor  DC("Sql.odbc"); #endif
5860ed2001-09-06Per Hedbor 
0b6ae02001-09-06Jonas Wallden  DC( "_Roxen.HeaderParser" );
a366a52001-09-06Per Hedbor  DC( "Protocols.HTTP" ); DC( "Protocols.HTTP.Query" );
59c6ff2001-08-09Per Hedbor 
a366a52001-09-06Per Hedbor  DC( "Calendar.ISO" ); DC( "Calendar.ISO.Second" );
59c6ff2001-08-09Per Hedbor 
080af72001-03-29Per Hedbor  DC( "Stdio.Stat" );
e7c2d42000-04-03Per Hedbor 
080af72001-03-29Per Hedbor  DC( "Regexp" );
1d9cfb2000-02-14Per Hedbor 
080af72001-03-29Per Hedbor  DC( "Pipe.pipe" );
1d9cfb2000-02-14Per Hedbor 
080af72001-03-29Per Hedbor  foreach( ({ "ANY", "XCF", "PSD", "PNG", "BMP", "TGA", "PCX", "XBM", "XPM", "TIFF", "ILBM", "PS", "PVR", "GIF", "JPEG", "XWD", "PNM", "RAS", "DSI", "TIM", "HRZ", "AVS", "WBF", "WBMP", "XFace" }), string x ) DC("Image."+x);
a366a52001-09-06Per Hedbor  DC( "Image.Image" ); DC( "Image.Font" ); DC( "Image.Colortable" ); DC( "Image.Layer" ); DC( "Image.lay" ); DC( "Image.Color" ); DC( "Image.Color.Color" );DC("Image._PSD" ); DC("Image._XCF" );
5574b22002-05-06Martin Stjernholm  DC ("Image.Color.black");
a366a52001-09-06Per Hedbor  DC( "Image._XPM" ); DC( "Image" ); if( DC("Image.GIF.encode") ) DC( "Image.GIF.encode_trans" );
080af72001-03-29Per Hedbor  DC( "Stdio.File" ); DC( "Stdio.UDP" ); DC( "Stdio.Port" ); DC( "Stdio.read_bytes" ); DC( "Stdio.read_file" ); DC( "Stdio.write_file" );
50b6972001-08-31Per Hedbor 
080af72001-03-29Per Hedbor  DC( "Stdio.sendfile" ); DC( "Stdio.stderr" ); DC( "Stdio.stdin" ); DC( "Stdio.stdout" ); DC( "Parser.HTML" );
e554ad2015-06-17Henrik Grubbström (Grubba)  if( DC("SSL.File" ) )
080af72001-03-29Per Hedbor  { DC( "SSL.context" ); DC( "Tools.PEM.pem_msg" );
fc40392008-08-15Martin Stjernholm  DC( "Crypto.Random.random_string" );
080af72001-03-29Per Hedbor  DC( "Standards.PKCS.RSA.parse_private_key");
fc40392008-08-15Martin Stjernholm  DC( "Crypto.RSA" );
080af72001-03-29Per Hedbor  DC( "Tools.X509.decode_certificate" ); DC( "Standards.PKCS.DSA.parse_private_key" ); DC( "SSL.cipher.dh_parameters" ); } if( DC( "HTTPLoop.prog" ) ) DC( "HTTPLoop.Loop" ); if( DC( "Image.FreeType" ) ) DC( "Image.FreeType.Face" ); DC( "Process.create_process" );
a366a52001-09-06Per Hedbor  DC( "MIME.Message" ); DC( "MIME.encode_base64" );
080af72001-03-29Per Hedbor  DC( "MIME.decode_base64" );
50aa162015-04-28Jonas Walldén  DC( "Locale" ); DC( "Charset" );
080af72001-03-29Per Hedbor 
56509c2001-06-30Martin Stjernholm  report_debug("\bDone [%.1fms]\n", (gethrtime()-t)/1000.0);
1d9cfb2000-02-14Per Hedbor 
1590412000-02-16Per Hedbor  add_constant( "hsv_to_rgb", nm_resolv("Colors.hsv_to_rgb") ); add_constant( "rgb_to_hsv", nm_resolv("Colors.rgb_to_hsv") ); add_constant( "parse_color", nm_resolv("Colors.parse_color") ); add_constant( "color_name", nm_resolv("Colors.color_name") ); add_constant( "colors", nm_resolv("Colors") );
7ba70c2000-07-09Per Hedbor 
e240552013-03-08Henrik Grubbström (Grubba)  add_constant("verify_password", verify_password); add_constant("crypt_password", crypt_password);
c423772009-03-24Henrik Grubbström (Grubba)  // report_debug("Loading prototypes ... \b"); // t = gethrtime();
080af72001-03-29Per Hedbor  // Load prototypes (after the master is replaces, thus making it // possible to dump them to a .o file (in the mysql)) object prototypes = (object)"base_server/prototypes.pike"; dump( "base_server/prototypes.pike", object_program( prototypes ) );
8cedaa2004-05-07Martin Stjernholm  foreach (indices (prototypes), string id) if (!prototypes->ignore_identifiers[id]) add_constant (id, prototypes[id]);
c423772009-03-24Henrik Grubbström (Grubba)  // report_debug("\bDone [%.1fms]\n", (gethrtime()-t)/1000.0); // report_debug("Resolving Roxen ... \b"); // t = gethrtime();
c2d7aa2004-04-13Martin Stjernholm  prototypes->Roxen = master()->resolv ("Roxen");
c423772009-03-24Henrik Grubbström (Grubba)  // report_debug("\bDone [%.1fms]\n", (gethrtime()-t)/1000.0);
c2d7aa2004-04-13Martin Stjernholm 
c423772009-03-24Henrik Grubbström (Grubba)  // report_debug("Initiating cache system ... \b"); // t = gethrtime();
4d1c5f2001-07-26Martin Stjernholm  object cache = initiate_cache();
c423772009-03-24Henrik Grubbström (Grubba)  // report_debug("\bDone [%.1fms]\n", (gethrtime()-t)/1000.0);
b1fca01996-11-12Per Hedbor  load_roxen();
5574b22002-05-06Martin Stjernholm 
7339a02000-02-10Per Hedbor  int retval = roxen->main(argc,hider);
4d1c5f2001-07-26Martin Stjernholm  cache->init_call_outs();
1590412000-02-16Per Hedbor  report_debug("-- Total boot time %2.1f seconds ---------------------------\n",
f0e0e61998-03-20Per Hedbor  (gethrtime()-start_time)/1000000.0);
26d7961999-09-25Martin Stjernholm  write_current_time();
87d06d2000-02-09Per Hedbor  if( retval > -1 )
c348db2003-09-15Martin Stjernholm  trace_exit( retval );
87d06d2000-02-09Per Hedbor  return;
b1fca01996-11-12Per Hedbor }
6533f22001-08-23Martin Nilsson 
19924b2001-08-24Martin Nilsson //! @decl int(0..1) callablep(mixed f) //! @appears callablep //! @decl roxen roxenp() //! @appears roxenp //! @decl int(0..1) r_rm(string f) //! @appears r_rm
2d3cd82011-12-28Martin Stjernholm //! Like @[predef::rm], but processes the path with @[roxen_path].
19924b2001-08-24Martin Nilsson  //! @decl int(0..1) r_mv(string from, string to) //! @appears r_mv
2d3cd82011-12-28Martin Stjernholm //! Like @[predef::mv], but processes the paths with @[roxen_path].
19924b2001-08-24Martin Nilsson  //! @decl Stdio.Stat r_file_stat(string path, void|int(0..1) symlink) //! @appears r_file_stat
2d3cd82011-12-28Martin Stjernholm //! Like @[predef::file_stat], but processes the path with @[roxen_path].
19924b2001-08-24Martin Nilsson  //! @decl string capitalize(string text) //! @appears capitalize //! Alias for String.capitalize. //! @decl array(int) hsv_to_rgb(array(int) hsv) //! @decl array(int) hsv_to_rgb(int h, int s, int v) //! @appears hsv_to_rgb //! Alias for Colors.hsv_to_rgb. //! @decl array(int) rgb_to_hsv(array(int) rgb) //! @decl array(int) rgb_to_hsv(int r, int g, int b) //! @appears rgb_to_hsv //! Alias for Colors.rgb_to_hsv //! @decl array(int) parse_color(string name) //! @appears parse_color //! Alias for Colors.parse_color // @module colors // @appears colors // Alias for Colors // @endmodule