2020-10-09 Fred Gleason <fredg@paravelsystems.com>

* Defined a set of standard exit code defines starting with
	'RD_EXIT_' in 'lib/rd.h'.
	* Regularized the exit codes returned by rdlogmanager(1).
	* Cleaned up error handling when using rdlogmanager(1) in
	command line mode.
	* Fixed a bug in rdlogmanager(1) that could leave a log lock
	asserted after exiting when handling schedule import errors.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2020-10-09 13:48:44 -04:00
parent b9f84fca37
commit 998e0124f6
8 changed files with 196 additions and 128 deletions

View File

@ -20432,3 +20432,11 @@
* Added generation of an 'RDLogManager Error Report' when errors
are detected when importing an external scheduler file in
rdlogmanager(1).
2020-10-09 Fred Gleason <fredg@paravelsystems.com>
* Defined a set of standard exit code defines starting with
'RD_EXIT_' in 'lib/rd.h'.
* Regularized the exit codes returned by rdlogmanager(1).
* Cleaned up error handling when using rdlogmanager(1) in
command line mode.
* Fixed a bug in rdlogmanager(1) that could leave a log lock
asserted after exiting when handling schedule import errors.

View File

@ -119,94 +119,118 @@
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refsect1>
<refsect1 id='modifier_options'><title>Modifier Options</title>
<para>
Modifier options change the default parameters of the specified mode.
</para>
<variablelist remap='TP'>
<varlistentry>
<term>
<option>-d
<arg choice='req'><replaceable>days</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify a start date offset in days. For log operations, this will
be added to &quot;tomorrow's&quot; date to arrive at a target date,
whereas for report operations it will be added to
&quot;yesterday's&quot; date to arrive at a target date.
Default value is <userinput>0</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-e
<arg choice='req'><replaceable>days</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify an end date offset in days. This will be added to
&quot;yesterday's&quot;
date to arrive at a target end date. Valid only for certain report
types. Default value is <userinput>0</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-P</option>
</term>
<listitem>
<para>
Protect an existing target object --i.e. if the specified
operation has already been performed, do not overwrite the
prior result.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-s
<arg choice='req'><replaceable>service-name</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify the name of the service for a log operation. Required
when the the <option>-g</option>, <option>-m</option> or
<option>-t</option> modes are specified (see above).
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>BUGS</title>
<refsect1 id='modifier_options'><title>Modifier Options</title>
<para>
The syntax of <command>rdlogmanager</command><manvolnum>1</manvolnum>'s
switches is decidedly grotty, nor does it conform to the
&quot;long-form&quot; switch conventions used in most other
Rivendell commands.
Modifier options change the default parameters of the specified mode.
</para>
</refsect1>
<variablelist remap='TP'>
<varlistentry>
<term>
<option>-d
<arg choice='req'><replaceable>days</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify a start date offset in days. For log operations, this will
be added to &quot;tomorrow's&quot; date to arrive at a target date,
whereas for report operations it will be added to
&quot;yesterday's&quot; date to arrive at a target date.
Default value is <userinput>0</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-e
<arg choice='req'><replaceable>days</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify an end date offset in days. This will be added to
&quot;yesterday's&quot;
date to arrive at a target end date. Valid only for certain report
types. Default value is <userinput>0</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-P</option>
</term>
<listitem>
<para>
Protect an existing target object --i.e. if the specified
operation has already been performed, do not overwrite the
prior result.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-s
<arg choice='req'><replaceable>service-name</replaceable></arg>
</option>
</term>
<listitem>
<para>
Specify the name of the service for a log operation. Required
when the the <option>-g</option>, <option>-m</option> or
<option>-t</option> modes are specified (see above).
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id='see_also'><title>See Also</title>
<refsect1 id='exit_values'><title>Exit Values</title>
<para>
<citerefentry>
<refentrytitle>rdclilogedit</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
<literal>,</literal>
<citerefentry>
<refentrytitle>rdrender</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
<segmentedlist>
<?dbhtml list-presentation="tabular"?>
<?dbfo list-presentation="tabular"?>
<segtitle></segtitle>
<segtitle></segtitle>
<seglistitem><seg>0</seg><seg>Normal exit</seg></seglistitem>
<seglistitem><seg>1</seg><seg>Prior instance found</seg></seglistitem>
<seglistitem><seg>2</seg><seg>Unable to open database</seg></seglistitem>
<seglistitem><seg>3</seg><seg>Unable to start a service component</seg></seglistitem>
<seglistitem><seg>4</seg><seg>Unrecognized/invalid command line option</seg></seglistitem>
<seglistitem><seg>5</seg><seg>Output overwrite protected</seg></seglistitem>
<seglistitem><seg>6</seg><seg>No such service</seg></seglistitem>
<seglistitem><seg>7</seg><seg>No such log</seg></seglistitem>
<seglistitem><seg>8</seg><seg>No such report</seg></seglistitem>
<seglistitem><seg>9</seg><seg>Log generation failed</seg></seglistitem>
<seglistitem><seg>10</seg><seg>Schedule file import failed</seg></seglistitem>
<seglistitem><seg>11</seg><seg>Insufficient permissions</seg></seglistitem>
<seglistitem><seg>11</seg><seg>Report generation failed</seg></seglistitem>
</segmentedlist>
</para>
</refsect1>
</refsect1>
<refsect1>
<title>BUGS</title>
<para>
The syntax of <command>rdlogmanager</command><manvolnum>1</manvolnum>'s
switches is decidedly grotty, nor does it conform to the
&quot;long-form&quot; switch conventions used in most other
Rivendell commands.
</para>
</refsect1>
<refsect1 id='see_also'><title>See Also</title>
<para>
<citerefentry>
<refentrytitle>rdclilogedit</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
<literal>,</literal>
<citerefentry>
<refentrytitle>rdrender</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -97,14 +97,21 @@
<segmentedlist>
<?dbhtml list-presentation="tabular"?>
<?dbfo list-presentation="tabular"?>
<!-- Is there a way to suppress the title line entirely? -->
<segtitle></segtitle>
<segtitle></segtitle>
<seglistitem><seg>0</seg><seg>Normal shutdown</seg></seglistitem>
<seglistitem><seg>0</seg><seg>Normal exit</seg></seglistitem>
<seglistitem><seg>1</seg><seg>Prior instance found</seg></seglistitem>
<seglistitem><seg>2</seg><seg>Unable to open database</seg></seglistitem>
<seglistitem><seg>3</seg><seg>Unable to start a service component</seg></seglistitem>
<seglistitem><seg>4</seg><seg>Unrecognized command line option</seg></seglistitem>
<seglistitem><seg>4</seg><seg>Unrecognized/invalid command line option</seg></seglistitem>
<seglistitem><seg>5</seg><seg>Output overwrite protected</seg></seglistitem>
<seglistitem><seg>6</seg><seg>No such service</seg></seglistitem>
<seglistitem><seg>7</seg><seg>No such log</seg></seglistitem>
<seglistitem><seg>8</seg><seg>No such report</seg></seglistitem>
<seglistitem><seg>9</seg><seg>Log generation failed</seg></seglistitem>
<seglistitem><seg>10</seg><seg>Schedule file import failed</seg></seglistitem>
<seglistitem><seg>11</seg><seg>Insufficient permissions</seg></seglistitem>
<seglistitem><seg>11</seg><seg>Report generation failed</seg></seglistitem>
</segmentedlist>
</para>
</refsect1>

View File

@ -615,4 +615,21 @@
*/
#define RD_RSS_XML_FILE_EXTENSION "rss"
/*
* Exit Codes
*/
#define RD_EXIT_OK 0 // Normal exit
#define RD_EXIT_PRIOR_INSTANCE 1 // Prior instance found
#define RD_EXIT_NO_DB 2 // Unable to open database
#define RD_EXIT_SVC_FAILED 3 // Unable to start a service component
#define RD_EXIT_UNKNOWN_OPTION 4 // Unrecognized command line option
#define RD_EXIT_OUTPUT_PROTECTED 5 // Couldn't overwrite output (-P)
#define RD_EXIT_NO_SERVICE 6 // No such service
#define RD_EXIT_NO_LOG 7 // No such log
#define RD_EXIT_NO_REPORT 8 // No such report
#define RD_EXIT_LOG_GEN_FAILED 9 // Log generation failed
#define RD_EXIT_LOG_LINK_FAILED 10 // Schedule import failed
#define RD_EXIT_NO_PERMS 11 // Insufficient permissions
#define RD_EXIT_REPORT_FAILED 12 // Report generation failed
#endif // RD_H

View File

@ -826,6 +826,8 @@ bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date,
RDLogEvent *dest_event=NULL;
RDLogLine *logline=NULL;
*err_msg="";
RDLogLock *log_lock=new RDLogLock(logname,user,svc_station,this);
if(!TryLock(log_lock,err_msg)) {
delete log_lock;
@ -877,6 +879,7 @@ bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date,
//
if(src==RDSvc::Music) {
if(!ResolveInlineTrafficLinks(logname,err_msg)) {
delete log_lock;
return false;
}
}

View File

@ -50,8 +50,8 @@ int RunReportOperation(int argc,char *argv[],const QString &rptname,
rda=new RDApplication("RDLogManager","rdlogmanager",RDLOGMANAGER_USAGE);
if(!rda->open(&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(1);
fprintf(stderr,"rdlogmanager: %s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_NO_DB);
}
//
@ -60,7 +60,7 @@ int RunReportOperation(int argc,char *argv[],const QString &rptname,
RDReport *report=new RDReport(rptname,rda->station(),rda->config());
if(!report->exists()) {
fprintf(stderr,"rdlogmanager: no such report\n");
return 256;
return RD_EXIT_NO_REPORT;
}
//
@ -71,14 +71,14 @@ int RunReportOperation(int argc,char *argv[],const QString &rptname,
fprintf(stderr,"report \"%s\" for %s already exists\n",
(const char *)rptname.utf8(),
(const char *)yesterday.addDays(start_offset).toString());
exit(256);
exit(RD_EXIT_OUTPUT_PROTECTED);
}
if(!report->generateReport(yesterday.addDays(start_offset),
yesterday.addDays(end_offset),rda->station(),
&out_path)) {
fprintf(stderr,"rdlogmanager: report generation failed [%s]\n",
(const char *)RDReport::errorText(report->errorCode()));
return 256;
return RD_EXIT_REPORT_FAILED;
}
return 0;
return RD_EXIT_OK;
}

View File

@ -2,7 +2,7 @@
//
// Generate/merge logs from the command line.
//
// (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2018-2020 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -48,8 +48,8 @@ LogObject::LogObject(const QString &svcname,int start_offset,
//
rda=new RDApplication("RDLogManager","rdlogmanager","");
if(!rda->open(&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(1);
fprintf(stderr,"rdlogmanager: %s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_NO_DB);
}
connect(rda,SIGNAL(userChanged()),this,SLOT(userData()));
@ -73,7 +73,7 @@ void LogObject::userData()
RDSvc *svc=new RDSvc(log_service_name,rda->station(),rda->config());
if(!svc->exists()) {
fprintf(stderr,"rdlogmanager: no such service\n");
exit(256);
exit(RD_EXIT_NO_SERVICE);
}
QDate start_date=QDate::currentDate().addDays(1+log_start_offset);
QString logname=
@ -87,8 +87,8 @@ void LogObject::userData()
if(log_generate_log) {
if(log_protect_existing&&log->exists()) {
fprintf(stderr,"log \"%s\" already exists\n",
(const char *)log->name().utf8());
exit(256);
log->name().utf8().constData());
exit(RD_EXIT_OUTPUT_PROTECTED);
}
SendNotification(RDNotification::DeleteAction,log->name());
log->removeTracks(rda->station(),rda->user(),rda->config());
@ -99,8 +99,9 @@ void LogObject::userData()
RDDateDecode(svc->nameTemplate(),start_date.addDays(1),
rda->station(),rda->config(),svc->name()),
&unused_report,rda->user(),&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(256);
fprintf(stderr,"rdlogmanager: log generation failed\n");
printf("%s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_LOG_GEN_FAILED);
}
log->updateTracks();
SendNotification(RDNotification::AddAction,log->name());
@ -123,39 +124,42 @@ void LogObject::userData()
if(log_merge_music) {
if(!log->exists()) {
fprintf(stderr,"rdlogmanager: log does not exist\n");
exit(256);
exit(RD_EXIT_NO_LOG);
}
if(log_protect_existing&&
(log->linkState(RDLog::SourceMusic)==RDLog::LinkDone)) {
fprintf(stderr,
"rdlogmanager: music for log \"%s\" is already imported\n",
(const char *)log->name().utf8());
exit(256);
log->name().utf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
if((!log->includeImportMarkers())&&
(log->linkState(RDLog::SourceMusic)!=RDLog::LinkMissing)) {
fprintf(stderr,
"rdlogmanager: music for log \"%s\" cannot be reimported\n",
(const char *)log->name().utf8());
exit(256);
log->name().utf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
report="";
log->removeTracks(rda->station(),rda->user(),rda->config());
if(!svc->clearLogLinks(RDSvc::Traffic,logname,rda->user(),&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(256);
fprintf(stderr,"rdlogmanager: music import failed\n");
printf("%s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
if(!svc->clearLogLinks(RDSvc::Music,logname,rda->user(),&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(256);
fprintf(stderr,"rdlogmanager: music import failed\n");
printf("%s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
if(svc->linkLog(RDSvc::Music,start_date,logname,&report,rda->user(),
&err_msg)) {
printf("%s\n",(const char*)report);
}
else {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(256);
fprintf(stderr,"rdlogmanager: music import failed\n");
printf("%s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
SendNotification(RDNotification::ModifyAction,log->name());
}
@ -166,33 +170,38 @@ void LogObject::userData()
if(log_merge_traffic) {
if(!log->exists()) {
fprintf(stderr,"rdlogmanager: log does not exist\n");
exit(256);
exit(RD_EXIT_NO_LOG);
}
if(log_protect_existing&&
(log->linkState(RDLog::SourceTraffic)==RDLog::LinkDone)) {
fprintf(stderr,
"rdlogmanager: traffic for log \"%s\" is already imported\n",
(const char *)log->name().utf8());
exit(256);
exit(RD_EXIT_LOG_LINK_FAILED);
}
if((!log->includeImportMarkers())&&
(log->linkState(RDLog::SourceTraffic)!=RDLog::LinkMissing)) {
fprintf(stderr,
"rdlogmanager: traffic for log \"%s\" cannot be reimported\n",
(const char *)log->name().utf8());
exit(256);
log->name().utf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
report="";
if(!svc->clearLogLinks(RDSvc::Traffic,logname,rda->user(),&err_msg)) {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
exit(256);
fprintf(stderr,"rdlogmanager: traffic schedule import failed\n");
printf("%s\n",err_msg.toUtf8().constData());
exit(RD_EXIT_LOG_LINK_FAILED);
}
if(svc->linkLog(RDSvc::Traffic,start_date,logname,&report,rda->user(),
&err_msg)) {
printf("%s\n",(const char*)report);
printf("%s\n",report.toUtf8().constData());
}
else {
fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg);
fprintf(stderr,"rdlogmanager: traffic import failed\n");
printf("%s\n",err_msg.toUtf8().constData());
delete log;
delete svc;
exit(RD_EXIT_LOG_LINK_FAILED);
}
SendNotification(RDNotification::ModifyAction,log->name());
}
@ -202,10 +211,10 @@ void LogObject::userData()
//
delete log;
delete svc;
exit(0);
exit(RD_EXIT_OK);
}
fprintf(stderr,"rdlogmanager: insufficient permissions\n");
exit(1);
exit(RD_EXIT_NO_PERMS);
}

View File

@ -60,7 +60,7 @@ MainWidget::MainWidget(RDConfig *c,QWidget *parent)
rda=new RDApplication("RDLogManager","rdlogmanager",RDLOGMANAGER_USAGE,this);
if(!rda->open(&err_msg)) {
QMessageBox::critical(this,"RDLogManager - "+tr("Error"),err_msg);
exit(1);
exit(RD_EXIT_NO_DB);
}
setWindowTitle(tr("RDLogManager"));
@ -228,7 +228,7 @@ void MainWidget::reportsData()
void MainWidget::quitMainWidget()
{
exit(0);
exit(RD_EXIT_OK);
}
@ -319,7 +319,7 @@ int main(int argc,char *argv[])
}
else {
fprintf(stderr,"rdlogmanager: missing argument to \"-s\"\n");
exit(2);
exit(RD_EXIT_UNKNOWN_OPTION);
}
cmd->setProcessed(i,true);
}
@ -330,7 +330,7 @@ int main(int argc,char *argv[])
}
else {
fprintf(stderr,"rdlogmanager: missing argument to \"-r\"\n");
exit(2);
exit(RD_EXIT_UNKNOWN_OPTION);
}
cmd->setProcessed(i,true);
}
@ -341,7 +341,7 @@ int main(int argc,char *argv[])
}
else {
fprintf(stderr,"rdlogmanager: missing argument to \"-d\"\n");
exit(2);
exit(RD_EXIT_UNKNOWN_OPTION);
}
cmd->setProcessed(i,true);
}
@ -352,14 +352,14 @@ int main(int argc,char *argv[])
}
else {
fprintf(stderr,"rdlogmanager: missing argument to \"-e\"\n");
exit(2);
exit(RD_EXIT_UNKNOWN_OPTION);
}
cmd->setProcessed(i,true);
}
if(!cmd->processed(i)) {
fprintf(stderr,"rdlogmanager: unknown command option \"%s\"\n",
(const char *)cmd->key(i));
exit(2);
exit(RD_EXIT_UNKNOWN_OPTION);
}
}
delete cmd;
@ -367,7 +367,7 @@ int main(int argc,char *argv[])
(cmd_generate||cmd_merge_traffic||cmd_merge_music)) {
fprintf(stderr,
"rdlogmanager: log and report operations are mutually exclusive\n");
exit(256);
exit(RD_EXIT_UNKNOWN_OPTION);
}
if(cmd_generate||cmd_merge_traffic||cmd_merge_music) {