################################################################################ # WeBWorK # # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester # All rights reserved # # $Id$ ################################################################################ ################################### ## Begin Global ################################### package Global; # The variables defined in this package set defaults and parameters for # the whole weBWorK system. Defaults can be over ridden for individual # courses by redefining variables in the individual course # webworkCourse.ph file. For example the default SYSTEM feedback address # set below as: $feedbackAddress = 'webwork@math.rochester.edu'; can (and # should) be over ridden for an individual course by entering e.g. # $Global::feedbackAdress = 'apizer@math.rochester.edu, # gage@math.rochester.edu'; in the individual course webworkCourse.ph # file. Of course you should really enter the email address(es) of the # professors teaching the course. # The system_webwork_setup.pl script also creates the file webworkConfig.pm # in the lib directory. This file contains a cgiDebugMode parameter than can # be set to aid in the debugging of WeBWorK scripts. ################################ # Local configuration settings # ################################ # $legalAddress defines destination addresses which are accepted for use in # scripts that send mail. it is a perl regular expression. $legalAddress = '^[^@]+@([-\w]+\.)+[A-Za-z]{2,4}$'; #$legalAddress = '^[^@]+@([-\w]+\.)+rochester.edu$'; # These define the default addresses to which will be used by the system. $webmaster = 'webwork@math.rochester.edu'; $feedbackAddress = $webmaster; # should be redefined for each course in webworkCourse.ph $defaultFrom = $webmaster; # should be redefined for each course in webworkCourse.ph $defaultReply = $webmaster; # should be redefined for each course in webworkCourse.ph $smtpSender = $webmaster; # should be redefined for each course in webworkCourse.ph # $smtpServer is the address of the sendmail server. If you are running sendmail on the # same machine as webwork, use "localhost" $smtpServer = 'mail.math.rochester.edu'; # $dirDelim is the delimiter used in pathnames on your system. $dirDelim = '/'; ########################### # Local external programs # ########################### # tth is used by the formatted-text display mode. $externalTTHPath = "/usr/local/bin/tth"; # latex2html is used my the typeset display mode. WeBWorK supports version 96.1 # and version 98.1p1 (or later). Specify either 96.1 or 98.1p1 for # $externalLaTeX2HTMLVersion -- this will effect the syntax used when calling # latex2html. $externalLaTeX2HTMLInit should point to a latex2html init file # that matches the version of latex2html specified. $externalLaTeX2HTMLPath = "/usr/local/bin/latex2html"; $externalLaTeX2HTMLVersion = "98.1p1"; $externalLaTeX2HTMLInit = "${mainDirectory}lib/latex2html.init.$externalLaTeX2HTMLVersion"; # LaTeX2HTML calls TeX utilities without using their full pathnames. Thus, # if the path to the binaries is not in the environment under which CGI # scripts are called (usually /bin:/usr/bin), you will have to specify it # here, so that it can be added before calling LaTeX2HTML. This path # should contain the 'latex' binary. $externalLaTeX2HTMLSupportPath = "/usr/local/bin"; # latex, dvips, and gs are programs used to generate problem set hard copy # output in various formats (DVI, PostScript, PDF). $externalLatexPath = "/usr/local/bin/latex"; $externalDvipsPath = "/usr/local/bin/dvips"; $externalGsPath = "/usr/local/bin/gs"; ##################### # Internal settings # ##################### # The access log is stored in the logs/ directory under the system directory # in a file called "access_log". It contains information about virtually # every action committed by users, including all answers submitted. # Usually this information is unneccessary, and the file becomes # large very quickly, so this log is ordinarily turned off. However, the # information it contains might be useful if, for example, a student wants an # extension and claims not to have viewed the correct answers. Set to 1 to # enable the access log; set to 0 to disable. $logAccessData = 0; # the number of digits in each PSVN controls how many unique PSVNs can be # created. For a PSVN of n digits, the range of available PSVNs will be # [10^(n-1),10^n-1]. The number of available PSVNs must be more than # number_of_students*number_of_problem_sets for any given course. $psvn_digits = 5; # The default rendering mode for onscreen problem display: # 'HTML' = raw TeX source # 'HTML_tth' = HTML formatted with TTH # 'Latex2HTML' = Images generated by LaTeX2HTML $htmlModeDefault = 'HTML'; ## Change DBtie_file only if you want to change the default database. The script ## db_tie.pl uses DB_File (the Berkeley DB) and gdbm_tie.pl uses GDBM_File. This ## setting can be changed for an individual course in the webworkCourse.ph file. For ## some other database, you will have to write your own database tie-file. Such ## files reside in the scripts directory. #$DBtie_file = 'db_tie.pl'; $DBtie_file = 'gdbm_tie.pl'; #################################################################################### ########### There should be no need to customize after this point ################# #################################################################################### use sigtrap; use diagnostics; use webworkConfig; use PGtranslator; # this is so that PGtranslator->evalute_macros is available when webworkCourse.ph is processed. require 5.000; require Exporter; @ISA = qw(Exporter); @EXPORT = qw( getWebworkScriptDirectory getWebworkCgiURL getCourseMOTDFile getSystemMOTDFile getCourseDatabaseDirectory getCourseDatabaseTieFile getCourseLogsDirectory getCourseTemplateDirectory getCourseURL getCourseScoringDirectory getCourseScriptsDirectory getCourseMacroDirectory getCourseHtmlDirectory getCourseEmailDirectory getCourseTempDirectory getCourseTempURL getCourseClasslistFile getCourseEnvironment getCourseKeyFile getCoursePasswordFile getCoursePermissionsFile getCourseDatabaseFile getCourseHtmlURL getCoursel2hDirectory getCoursel2hURL getDirDelim getDelim getScoreFilePrefix getScoring_log getDash getDat getBbext getStatusDrop convertPath getNumRelPercentTolDefault getNumZeroLevelDefault getNumZeroLevelTolDefault getNumAbsTolDefault getNumFormatDefault getFunctRelPercentTolDefault getFunctZeroLevelDefault getFunctZeroLevelTolDefault getFunctAbsTolDefault getFunctNumOfPoints getFunctVarDefault getFunctLLimitDefault getFunctULimitDefault getFunctMaxConstantOfIntegration getLoginURL getWebworkLogsDirectory wwerror getAllowDestroyRebuildProbSets ); ## URL's derived from webworkConfig.pm $loginURL = "${cgiWebworkURL}login.pl"; $imagesURL = "${htmlWebworkURL}images/"; $helpURL = "${htmlWebworkURL}helpFiles/"; $webworkDocsURL = 'http://webwork.math.rochester.edu/docs/docs/'; $appletsURL = "${htmlWebworkURL}applets/"; ## practice users $practiceUser = 'practice'; # name of password-less "practice" user $practiceKey = 'practice'; # a dummy key for this user, can be anything ## The database handle for using mSQL: $dbh = 0; ## various gifs $helpGifUrl = "${imagesURL}ww_help.gif"; $logoutGifUrl = "${imagesURL}ww_logout.gif"; $feedbackGifUrl = "${imagesURL}ww_feedback.gif"; $currentImgUrl = "${imagesURL}ww_curr.gif"; $previousImgUrl = "${imagesURL}ww_prev.gif"; $nextImgUrl = "${imagesURL}ww_next.gif"; $problistImgUrl = "${imagesURL}ww_problist.gif"; $upImgUrl = "${imagesURL}ww_up.gif"; $bluesquareImgUrl = "${imagesURL}ww_bluesq.gif"; $headerImgUrl = "${imagesURL}webwork.gif"; # image to include at top of pages $squareWebworkGif = "${imagesURL}square_webwork.gif"; # image to include at top of pages ## backgrounds gifs for HTML documents $background_plain_url = "${imagesURL}white.gif"; $background_okay_url = "${imagesURL}green.gif"; $background_warn_url = "${imagesURL}red.gif"; $bg_color = '#EFEFEF'; #background color for processProblem ## Directories $coursesDirectory = convertPath("${mainDirectory}courses/"); $scriptDirectory = convertPath("${mainDirectory}scripts/"); $cgiDirectory = convertPath("${mainDirectory}cgi/"); #$tempDirectory = convertPath("/tmp/"); $authDirectory = convertPath(".auth/"); $courseScriptsDirectory = convertPath("${mainDirectory}courseScripts/"); $macroDirectory = convertPath("${mainDirectory}courseScripts/"); $classDirectory = ''; #This must be defined in webworkCourse.ph $webworkLogsDirectory = "${mainDirectory}/logs/"; ## File names $coursesFilename = 'courses-list'; $coursesFile = "${coursesDirectory}$coursesFilename"; $classlistFilename = 'classlist.lst'; $keyFilename = 'keys'; $passwordFilename = 'password'; $permissionsFilename = 'permissions'; $database = 'webwork-database'; $CL_Database = 'classlist-database'; $tipsFilename = 'tips.txt'; $system_motd_filename = 'motd.txt'; $course_motd_filename = 'motd.txt'; $tipsFile = "${mainDirectory}$tipsFilename"; # CGI script calls $login_CGI = "${cgiWebworkURL}login.pl"; $logout_CGI = "${cgiWebworkURL}logout.pl"; $welcome_CGI = "${cgiWebworkURL}welcome.pl"; $welcomeAction_CGI = "${cgiWebworkURL}welcomeAction.pl"; $processProblem_CGI = "${cgiWebworkURL}processProblem8.pl"; $feedback_CGI = "${cgiWebworkURL}feedback.pl"; $problemEditor_CGI = "${cgiWebworkURL}problemEditor.pl"; ## The following items control how the whole problem set is typeset by downloadPS.pl. ## The files (e.g. "tex_set_ptramble.tex") are found in the .../templates directory ## Note that the system dependent latex and dvips programs are defined in the file ## makePS which is in the .../scripts directory. makePS must be edited to call ## the correct programs. ## ## This is the tex preamble file used by downloadPS.pl in typeseting the whole problem set. ## E.g. loads AMS latex and graphics packages, some macro definitions. $TEX_SET_PREAMBLE = 'texSetPreamble.tex'; ## This is the tex header file used by downloadPS.pl in typeseting the whole problem set ## E.g. loads two column format, macro definitions. $TEX_SET_HEADER = ''; ## This is the header file used by downloadPS.pl to enter preliminary verbiage for the ## whole problem set. E.g. Course name, student name, problem set number,instructions, due date. $SET_HEADER = 'paperSetHeader.pg'; ## This is the tex footer file used by downloadPS.pl in typeseting the whole problem set $TEX_SET_FOOTER = 'texSetFooter.tex'; ## The following items control how an individual problem is typeset by processProblem.pl ## and l2h. Note that the system dependent latex2html program is defined in processProblem.pl. It ## should really be in a seperate file like makeps. ## This is the tex preamble file used by processProblem.pl typeseting an individual problem ## Usually very similar to $TEX_SET_PREAMBLE $TEX_PROB_PREAMBLE = 'texProbPreamble.tex'; ## This is the tex header file used by processProblem.pl typeseting an individual problem $TEX_PROB_HEADER = ''; ## This is the header file used by probSet.pl to enter preliminary verbiage on the prob set ## page. E.g. Instructions, due date. $PROB_HEADER = 'screenSetHeader.pg'; ## This is the tex footer file processProblem.pl typeseting an individual problem $TEX_PROB_FOOTER = 'texProbFooter.tex'; $courseEnvironmentFile = 'webworkCourse.ph'; #$webworkCourse_ph = 'webworkCourse.ph'; $DBglue_pl = 'DBglue8.pl'; $HTMLglue_pl = 'HTMLglue.pl'; $classlist_DBglue_pl = 'classlist_DBglue.pl'; $FILE_pl = 'FILE.pl'; $displayMacros_pl = 'displayMacros.pl'; $scoring_log = 'scoring.log'; #####$probSetHeader = 'probSetHeader'; $SCRtools_pl = 'pScSet6.pl'; $buildProbSetTools = 'proceduresForBuildProbSetDB.pl'; ## File and Directory permissions ## e.g. S1-1521.sco in (base course directory)/DATA $sco_files_permission = 0660; ## tie permissions (used in tie commands) ## The database, password, and permissions files ## always take their permissions from the Global ## vaiables below. The important keys file ## takes its permission from $restricted_tie_permission. $restricted_tie_permission = 0600; $standard_tie_permission = 0660; ## webwork-database in (base course directory)/DATA $webwork_database_permission = 0660; ## password in (base course directory)/DATA/.auth $password_permission = 0660; ## permissions in (base course directory)/DATA/.auth $permissions_permission = 0660; ## e.g. s1ful.csv in (base course directory)/scoring $scoring_files_permission = 0660; ## e.g. s1bak1.csv in (base course directory)/scoring $scoring_bak_files_permission = 0440; ## e.g. 8587l2h.log in (base course directory)/html/tmp/l2h $l2h_logs_permission = 0660; ## e.g. set1/ in (base course directory)/html/tmp/l2h $l2h_set_directory_permission = 0770; ## e.g. 1-1082/ in (base course directory)/html/tmp/l2h/set1 $l2h_prob_directory_permission = 0770; ## e.g. 1082output.html in (base course directory)/html/tmp/l2h/set1/1-1082 $l2h_data_permission = 0770; ## e.g. file.gif in (base course directory)/html/tmp/gif $tmp_file_permission = 0660; ## e.g. gif/ in (base course directory)/html/tmp/ $tmp_directory_permission = 0770; ##e.g. classlist files (e.g. MTH140A.lst) in (base course directory)/templates/ $classlist_file_permission = 0660; ## Prefixes, extensions, defaults, etc $scoreFilePrefix = 'S'; $dash = '-'; # Can not be the underscore character or an upper or # lowercase letter or a digit. Used in .sco file names $delim = ','; # used in scoring, classlist $dat = 'csv'; @statusDrop = qw(drop d withdraw); $courselist_delim = '::'; # used by login.pl to get course names / dirs $instructor_permissions = 10; $TA_permissions = 5; $score_decimal_digits = 1; # Number of decimal digits in recorded scores. For example # if this is 1 then on a 1 point problem that allows partial # credit, possible scores are 0, .1, .2, ..., 1. $maxAttemptsWarningLevel = 5; # If the set definition file puts a limit on the number of # times a problem may be attempted, processProblem.pl will # give a warning message when <= $maxAttemptsWarningLevel # attempts remain. $noOfFieldsInClasslist = 9; # The number of fields in the classlist file. This is used as # a check to make sure each record in the classlist file has # this number of fields $allowStudentToChangeEMAddress = 1; # setting to 1 allows students to change their # own email address. Setting to 0 disallows this $Global::PG_environment{showPartialCorrectAnswers} = 1; ## Set to 0 or 1. If set to 1 in multipart # questions the student will be told which parts are # correct and which are incorrect. Usually, this is # set explicitly in each individual problem. $allowDestroyRebuildProbSets = 0; # Set to 0 or 1. If set to 1 a professor can destroy and # rebuild problems sets in one operation. This is very # convenient and powerful, but also very dangerous. Usually # this is not allowed in courses students are using. It is # often set to 1 in a private course being used only for # developing problem sets. To do this, reset this in the # private course's webworkCourse.ph file. $Global::PG_environment{recordSubmittedAnswers} = 1; # Set to 0 or 1. If set to 1, submitted answers will be # stored. For example in a multipart question, a student can # do several parts, then logout or go onto another question. # When they view the problem again, the answer blanks will be # filled in with their most recent answers. This also allows # professors to see exactly what a student entered. This default # can be over ridden for an individual problem by setting # recordSubmittedAnswers in the .pg file for the problem. $maxSizeRecordedAns = 256; # Student answers longer than this length in bytes will not # stored in the database. $hide_studentID_from_TAs = 0; # Set to 0 or 1. If set to 1, studentID's will be hidden # from TA's. For example some Universities may use SS#'s for # student ID's and you may not want TA's to view these. ## arguments for flock() $shared_lock = 1; $exclusive_lock = 2; $nonblocking_lock = 4; $unlock_lock = 8; # These values provide defaults for the various answer comparison macros found # in PGanswermacros.pl. They can be over ridden for individual courses by # redefining the variables in the individual course webworkCourse.ph file. # They can be over ridden for individual problems by explicitly passing the # desired values to the answer comparison macro # The following effect numerical answer comparison $numRelPercentTolDefault = .1; $numZeroLevelDefault = 1E-14; $numZeroLevelTolDefault = 1E-12; $numAbsTolDefault = .001; $numFormatDefault = ''; ## use perl's format in prfmt() # The following effect function comparison $functRelPercentTolDefault = .1; $functZeroLevelDefault = 1E-14; $functZeroLevelTolDefault = 1E-12; $functAbsTolDefault = .001; $functNumOfPoints = 3; $functVarDefault = 'x'; $functLLimitDefault = .0000001; $functULimitDefault = .9999999; # The following effects function comparison upto constant for antidifferentiation $functMaxConstantOfIntegration = 1E8; ## These values provide defaults for the window size in the problemEditor.pl script $editor_window_rows = 25; $editor_window_columns = 90; ## This is the maximum number problems sets that can be downloaded at one time ## by a professor. Set this higher or lower depending on the speed of your server $max_num_of_ps_downloads_allowed = 20; # Subroutines for defining the directories and URLs ###### Public vars/routines - these are imported into your namespace, ####### ###### so they can be called as they are. ####### sub getWebworkScriptDirectory { convertPath($scriptDirectory ) }; sub getCourseDatabaseDirectory { convertPath($databaseDirectory )}; sub getCourseDatabaseTieFile { convertPath($DBtie_file )}; sub getCourseLogsDirectory { convertPath($logsDirectory )}; sub getCourseTemplateDirectory { convertPath($templateDirectory )}; sub getCourseEmailDirectory { convertPath("${templateDirectory}email/")}; sub getCourseScoringDirectory { convertPath($scoringDirectory ) }; sub getCourseHtmlDirectory { convertPath($htmlDirectory )}; sub getCourseTempDirectory {convertPath($courseTempDirectory)}; sub getCoursel2hDirectory { convertPath( "${courseTempDirectory}l2h/" )}; sub getCourseScriptsDirectory { convertPath($courseScriptsDirectory )}; sub getCourseMacroDirectory { convertPath($macroDirectory )}; sub getWebworkLogsDirectory { convertPath($webworkLogsDirectory)}; sub getCourseClasslistFile { convertPath("${coursesDirectory}$_[0]/templates/${classlistFilename}") }; sub getCourseKeyFile { convertPath("${coursesDirectory}$_[0]/DATA/${authDirectory}${keyFilename}") }; sub getCoursePasswordFile { convertPath("${coursesDirectory}$_[0]/DATA/${authDirectory}${passwordFilename}") }; sub getCoursePermissionsFile { convertPath("${coursesDirectory}$_[0]/DATA/${authDirectory}${permissionsFilename}") }; sub getCourseDatabaseFile { convertPath("${coursesDirectory}$_[0]/DATA/${$database}") }; sub getCourseMOTDFile { convertPath("${coursesDirectory}$_[0]/templates/${course_motd_filename}") }; sub getSystemMOTDFile { convertPath("${mainDirectory}${system_motd_filename}") }; sub getWebworkCgiURL { $cgiWebworkURL }; sub getCourseHtmlURL { $htmlURL }; sub getCoursel2hURL { "${courseTempURL}l2h/" } sub getCourseTempURL { $courseTempURL }; #defined in webworkCourse.ph sub getDirDelim { $dirDelim }; sub getDelim { $delim }; sub getScoreFilePrefix { $scoreFilePrefix }; sub getScoring_log { $scoring_log }; sub getDash { $dash }; sub getDat { $dat }; sub getBbext { @dbext }; sub getStatusDrop { @statusDrop }; sub getNumRelPercentTolDefault { $numRelPercentTolDefault }; sub getNumZeroLevelDefault { $numZeroLevelDefault }; sub getNumZeroLevelTolDefault { $numZeroLevelTolDefault }; sub getNumAbsTolDefault { $numAbsTolDefault }; sub getNumFormatDefault { $numFormatDefault }; sub getFunctRelPercentTolDefault { $functRelPercentTolDefault }; sub getFunctZeroLevelDefault { $functZeroLevelDefault }; sub getFunctZeroLevelTolDefault { $functZeroLevelTolDefault }; sub getFunctAbsTolDefault { $functAbsTolDefault }; sub getFunctNumOfPoints { $functNumOfPoints }; sub getFunctVarDefault { $functVarDefault }; sub getFunctLLimitDefault { $functLLimitDefault }; sub getFunctULimitDefault { $functULimitDefault }; sub getFunctMaxConstantOfIntegration { $functMaxConstantOfIntegration }; sub getLoginURL { $loginURL }; sub getAllowDestroyRebuildProbSets { $allowDestroyRebuildProbSets }; sub getCourseEnvironment { die "getCourseEnvironment was called without specifying a course" unless $_[0]; my $fullPath = convertPath("${coursesDirectory}$_[0]/$courseEnvironmentFile"); require "$fullPath" || die "Can't find local environment file for $fullPath\n"; } ### dump a (hopefully) descriptive error to the browser and quit sub wwerror { my($title, $msg, $url, $label, $query_string) = @_; # $msg = '' unless defined $msg; $url = '' unless defined $url; $label = '' unless defined $label; $query_string = '' unless defined $query_string; print "content-type: text/html\n\n Error: $title

Error: $title

$msg\n
          
"; if ($url) { print "
\n"; } print ""; &log_error($title, $query_string); exit 1; } sub error {wwerror(@_);} ##alias for wwerror # return a (scalar) tip sub tip { my ($tips, @tiplist); local($/) = undef; #undef $/; # slurp it all in open(TIPS, "$tipsFile") || &error("Can't open $tipsFile"); $tips = ; close(TIPS); # add any local tips to the list before we pick a random one if (-r "${templateDirectory}$tipsFilename") { open(TIPS, "${templateDirectory}$tipsFilename"); $tips .= '%%' . ; close(TIPS); } $/ = "\n"; # <> now reads until newline $tips =~ s/#.*?\n//mg; # remove comments @tiplist = split(/%%/, $tips); return $tiplist[rand(@tiplist)]; # choose one at random } # return an array of tips sub all_tips { my ($tip, $tips, @tiplist); local($/) = undef; # slurp it all in open(TIPS, "$tipsFile") || &error("Can't open $tipsFile"); $tips = ; close(TIPS); # add any local tips to the list before we pick a random one if (-r "${templateDirectory}$tipsFilename") { open(TIPS, "${templateDirectory}$tipsFilename"); $tips .= '%%' . ; close(TIPS); } $/ = "\n"; # <> now reads until newline $tips =~ s/#.*?\n//mg; # remove comments @tiplist = split(/%%/, $tips); return @tiplist; } # begin Timing code use Benchmark; sub dateTime { my @timeArray = localtime(time); my $out = sprintf("%2.2d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", $timeArray[5],$timeArray[4]+1,@timeArray[3,2,1,0]); $out; } #the ps system calls do not work on all systems, and are usually not #necessary anyway. If you wish that information to be logged, simply #uncomment the relevant lines, but be warned that they might need to #be modified for your system sub logTimingInfo { my ($beginTime,$endTime,$script,$course,$user,$remoteHost,$userAgent) = @_; $remoteHost = ""unless defined($remoteHost); $userAgent = "" unless defined($userAgent); open(TIMELOG, ">>${webworkLogsDirectory}timing_log") || warn "*Unable to open timing log for writing:\n ${webworkLogsDirectory}timing_log. "; my $mem_string = ''; # my $process_string = `ps -o vsz -p $$`; # $process_string =~ s/^\s*//; # $process_string =~ s/\s*$//; # my @process_string = split(/\s+/,$process_string); # gets memory size # my $mem_string = " mem: ${process_string[1]}K"; my $load_string = ''; # my @load = split(/\n/,`ps -U wwhttpd -o state`); # my $load_string = " load: " . grep(/R/,@load); print TIMELOG $script,"\t",$course,"\t",&dateTime,"\t", timestr( timediff($endTime,$beginTime), 'all' ),"\t", "pid: $$ DBtie_tries: $Global::DBtie_tries" . $mem_string . $load_string,"\t",$user,"\t", $remoteHost,"\t",$userAgent,"\n"; close(TIMELOG); } # end Timing code # handy routines for modules that wish to throw exceptions outside of the # current package. (taken from Carp.pm) # # We'll want to remove this in final versions of WeBWorK. sub log_error { my ($comment, $data) = @_; # my $accessLog = convertPath("${webworkLogsDirectory}access_log"); my $errorLog = convertPath("${webworkLogsDirectory}error_log"); # open(ACCESS, ">>$accessLog"); open(ERROR, ">>$errorLog"); # print ACCESS "ERROR ($comment) ", scalar(localtime), ': ', &shortmess($data); print ERROR "ERROR ($comment) ", scalar(localtime), ': ', &shortmess($data); # close(ACCESS); close(ERROR); } sub log_info { if( $Global::logAccessData == 1 ) { my ($comment, $data) = @_; my $accessLog = convertPath("${webworkLogsDirectory}access_log"); open(LOG, ">>$accessLog") or warn "Can't open accessLog $accessLog"; print LOG "INFO ($comment) ", scalar(localtime), ': ', &shortmess($data); close(LOG); } } ## converts full path names to to use the $dirDelim instead of / sub convertPath { my ($path) = @_; warn "convertPath has been asked to convert an empty path
|$path| at ", caller(),"
" unless $path; $path =~ s|/|$dirDelim|g; $path; } # ----- BEGIN { sub PG_floating_point_exception_handler { # 1st argument is signal name my($sig) = @_; print "Content-type: text/html\n\n

There was a floating point arithmetic error (exception SIG$sig )

--perhaps you divided by zero or took the square root of a negative number?
\n Use the back button to return to the previous page and recheck your entries.
\n"; exit(0); } $SIG{'FPE'} = \&PG_floating_point_exception_handler; sub PG_warnings_handler { my @input = @_; my $msg_string = longmess(@_); my @msg_array = split("\n",$msg_string); my $out_string = ''; # Extra stack information is provided in this next block # If the warning message does NOT end in \n then a line # number is appended (see Perl manual about warn function) # The presence of the line number is detected below and extra # stack information is added. # To suppress the line number and the extra stack information # add \n to the end of a warn message (in .pl files. In .pg # files add ~~n instead if ($input[$#input]=~/line \d*\.\s*$/) { $out_string .= "##More details:
\n----"; foreach my $line (@msg_array) { chomp($line); next unless $line =~/\w+\:\:/; $out_string .= "----" .$line . "
\n"; } } $Global::WARNINGS .="* " . join("
",@input) . "
\n" . $out_string . "
\n--------------------------------------
\n
\n"; $Global::background_plain_url = $Global::background_warn_url; $Global::bg_color = '#FF99CC'; #for warnings -- this change may come too late } $SIG{__WARN__}=\&PG_warnings_handler; $SIG{__DIE__} = sub { my $message = longmess(@_); $message =~ s/\n/
\n/; my ($package, $filename, $line) = caller(); # use standard die for errors eminating from XML::Parser::Expat # it uses a trapped eval which sometimes fails -- apparently on purpose # and the error is handled by Expat itself. We don't want # to interfer with that. if ($package eq 'XML::Parser::Expat') { die @_; } #print "$package $filename $line \n"; print "Content-type: text/html\r\n\r\n

Software error

\n\n$message\n

\n Please inform the webwork meister.

\n In addition to the error message above the following warnings were detected:


$Global::WARNINGS;
It's sometimes hard to tell exactly what has gone wrong since the full error message may have been sent to standard error instead of to standard out.

To debug you can

  • guess what went wrong and try to fix it.
  • call the offending script directly from the command line of unix
  • enable the debugging features by redefining \$cgiURL in Global.pm and checking the redirection scripts in system/cgi. This will force the standard error to be placed in the standard out pipe as well.
  • Run tail -f error_log
    from the unix command line to see error messages from the webserver. The standard error output is being placed in the error_log file for the apache web server. To run this command you have to be in the directory containing the error_log or enter the full path name of the error_log.

    In a standard apache installation, this file is at /usr/local/apache/logs/error_log

    In a RedHat Linux installation, this file is at /var/log/httpd/error_log

    At Rochester this file is at /ww/logs/error_log.

Good luck.

\n" ; }; } ############### ## Error message routines ############### BEGIN { #error message routines my $CarpLevel = 0; # How many extra package levels to skip on carp. my $MaxEvalLen = 0; # How much eval '...text...' to show. 0 = all. sub longmess { my $error = shift; my $mess = ""; my $i = 1 + $CarpLevel; my ($pack,$file,$line,$sub,$eval,$require); while (($pack,$file,$line,$sub,undef,undef,$eval,$require) = caller($i++)) { if ($error =~ m/\n$/) { $mess .= $error; } else { if (defined $eval) { if ($require) { $sub = "require $eval"; } else { $eval =~ s/[\\\']/\\$&/g; if ($MaxEvalLen && length($eval) > $MaxEvalLen) { substr($eval,$MaxEvalLen) = '...'; } $sub = "eval '$eval'"; } } elsif ($sub eq '(eval)') { $sub = 'eval {...}'; } $mess .= "\t$sub " if $error eq "called"; $mess .= "$error at $file line $line\n"; } $error = "called"; } $mess || $error; } sub shortmess { # Short-circuit &longmess if called via multiple packages my $error = $_[0]; # Instead of "shift" my ($curpack) = caller(1); my $extra = $CarpLevel; my $i = 2; my ($pack,$file,$line); while (($pack,$file,$line) = caller($i++)) { if ($pack ne $curpack) { if ($extra-- > 0) { $curpack = $pack; } else { return "$error at $file line $line\n"; } } } goto &longmess; } } ############### ## End Error message routines ############### 1; ## This line is required by perl