diff --git a/ChangeLog b/ChangeLog index 61c07ea9..3082c139 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 + * 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. diff --git a/docs/manpages/rdlogmanager.xml b/docs/manpages/rdlogmanager.xml index 86bce22d..eb3e6d53 100644 --- a/docs/manpages/rdlogmanager.xml +++ b/docs/manpages/rdlogmanager.xml @@ -119,94 +119,118 @@ - + -Modifier Options - - Modifier options change the default parameters of the specified mode. - - - - - - - - - Specify a start date offset in days. For log operations, this will - be added to "tomorrow's" date to arrive at a target date, - whereas for report operations it will be added to - "yesterday's" date to arrive at a target date. - Default value is 0. - - - - - - - - - - Specify an end date offset in days. This will be added to - "yesterday's" - date to arrive at a target end date. Valid only for certain report - types. Default value is 0. - - - - - - - - - - Protect an existing target object --i.e. if the specified - operation has already been performed, do not overwrite the - prior result. - - - - - - - - - - Specify the name of the service for a log operation. Required - when the the , or - modes are specified (see above). - - - - - - - - BUGS + Modifier Options - The syntax of rdlogmanager1's - switches is decidedly grotty, nor does it conform to the - "long-form" switch conventions used in most other - Rivendell commands. + Modifier options change the default parameters of the specified mode. - + + + + + + + + Specify a start date offset in days. For log operations, this will + be added to "tomorrow's" date to arrive at a target date, + whereas for report operations it will be added to + "yesterday's" date to arrive at a target date. + Default value is 0. + + + + + + + + + + Specify an end date offset in days. This will be added to + "yesterday's" + date to arrive at a target end date. Valid only for certain report + types. Default value is 0. + + + + + + + + + + Protect an existing target object --i.e. if the specified + operation has already been performed, do not overwrite the + prior result. + + + + + + + + + + Specify the name of the service for a log operation. Required + when the the , or + modes are specified (see above). + + + + + -See Also + Exit Values - - rdclilogedit1 - - , - - rdrender1 - + + + + + + 0Normal exit + 1Prior instance found + 2Unable to open database + 3Unable to start a service component + 4Unrecognized/invalid command line option + 5Output overwrite protected + 6No such service + 7No such log + 8No such report + 9Log generation failed + 10Schedule file import failed + 11Insufficient permissions + 11Report generation failed + - + + + + BUGS + + The syntax of rdlogmanager1's + switches is decidedly grotty, nor does it conform to the + "long-form" switch conventions used in most other + Rivendell commands. + + + + See Also + + + rdclilogedit1 + + , + + rdrender1 + + + diff --git a/docs/manpages/rdservice.xml b/docs/manpages/rdservice.xml index b9ccf196..48abc32b 100644 --- a/docs/manpages/rdservice.xml +++ b/docs/manpages/rdservice.xml @@ -97,14 +97,21 @@ - - 0Normal shutdown + 0Normal exit 1Prior instance found 2Unable to open database 3Unable to start a service component - 4Unrecognized command line option + 4Unrecognized/invalid command line option + 5Output overwrite protected + 6No such service + 7No such log + 8No such report + 9Log generation failed + 10Schedule file import failed + 11Insufficient permissions + 11Report generation failed diff --git a/lib/rd.h b/lib/rd.h index ee5af605..5cfbcd47 100644 --- a/lib/rd.h +++ b/lib/rd.h @@ -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 diff --git a/lib/rdsvc.cpp b/lib/rdsvc.cpp index 9f9f5944..2a9ffd78 100644 --- a/lib/rdsvc.cpp +++ b/lib/rdsvc.cpp @@ -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; } } diff --git a/rdlogmanager/commandline_ops.cpp b/rdlogmanager/commandline_ops.cpp index 81ae4c1c..9f26352c 100644 --- a/rdlogmanager/commandline_ops.cpp +++ b/rdlogmanager/commandline_ops.cpp @@ -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; } diff --git a/rdlogmanager/logobject.cpp b/rdlogmanager/logobject.cpp index 061e966c..a8a2b41a 100644 --- a/rdlogmanager/logobject.cpp +++ b/rdlogmanager/logobject.cpp @@ -2,7 +2,7 @@ // // Generate/merge logs from the command line. // -// (C) Copyright 2018 Fred Gleason +// (C) Copyright 2018-2020 Fred Gleason // // 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); } diff --git a/rdlogmanager/rdlogmanager.cpp b/rdlogmanager/rdlogmanager.cpp index 9f80d371..7d0ad69c 100644 --- a/rdlogmanager/rdlogmanager.cpp +++ b/rdlogmanager/rdlogmanager.cpp @@ -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) {