MythTV  master
checksetup.cpp
Go to the documentation of this file.
1 // checksetup.cpp
2 //
3 // Some functions to do simple sanity checks on the MythTV setup.
4 // CheckSetup() is currently meant for the mythtv-setup program,
5 // but the other functions could probably be called from anywhere.
6 // They all return true if any problems are found, and add to a
7 // caller-supplied QString a message describing the problem.
8 
9 // Qt
10 #include <QDir>
11 
12 // MythTV
14 #include "libmythbase/mythdate.h"
15 #include "libmythbase/mythdb.h"
16 #include "libmythtv/cardutil.h"
17 
18 // MythTV Setup
19 #include "checksetup.h"
20 
22 
23 static bool checkPath(QString path, QStringList &probs)
24 {
25  QDir dir(path);
26  if (!dir.exists())
27  {
28  probs.push_back(QObject::tr("Path \"%1\" doesn't exist.").arg(path));
29  return true;
30  }
31 
32  QFile test(path.append("/.test"));
33  if (test.open(QIODevice::WriteOnly))
34  test.remove();
35  else
36  {
37  probs.push_back(QObject::tr("Unable to create file \"%1\" - directory "
38  "is not writable?").arg(path));
39  return true;
40  }
41 
42  return false;
43 }
44 
47 
48 bool checkStoragePaths(QStringList &probs)
49 {
50  bool problemFound = false;
51 
53 
54  query.prepare("SELECT count(groupname) FROM storagegroup;");
55  if (!query.exec() || !query.next())
56  {
57  MythDB::DBError("checkStoragePaths", query);
58  return false;
59  }
60 
61  if (query.value(0).toInt() == 0)
62  {
63  QString trMesg =
64  QObject::tr("No Storage Group directories are defined. You "
65  "must add at least one directory to the Default "
66  "Storage Group where new recordings will be "
67  "stored.");
68  probs.push_back(trMesg);
69  LOG(VB_GENERAL, LOG_ERR, trMesg);
70  return true;
71  }
72 
73  query.prepare("SELECT groupname, dirname "
74  "FROM storagegroup "
75  "WHERE hostname = :HOSTNAME;");
76  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
77  if (!query.exec() || !query.isActive())
78  {
79  MythDB::DBError("checkStoragePaths", query);
80  return false;
81  }
82  if (query.size() < 1)
83  {
85  {
86  // Master backend must have a defined Default SG
87  QString trMesg =
88  QObject::tr("No Storage Group directories are defined. "
89  "You must add at least one directory to the "
90  "Default Storage Group where new recordings "
91  "will be stored.");
92  probs.push_back(trMesg);
93  LOG(VB_GENERAL, LOG_ERR, trMesg);
94  return true;
95  }
96  return false;
97  }
98 
99  QDir checkDir("");
100  QString dirname;
101  while (query.next())
102  {
103  /* The storagegroup.dirname column uses utf8_bin collation, so Qt
104  * uses QString::fromAscii() for toString(). Explicitly convert the
105  * value using QString::fromUtf8() to prevent corruption. */
106  dirname = QString::fromUtf8(query.value(1)
107  .toByteArray().constData());
108  QStringList tokens = dirname.split(",");
109  int curToken = 0;
110  while (curToken < tokens.size())
111  {
112  checkDir.setPath(tokens[curToken]);
113  if (checkPath(tokens[curToken], probs))
114  {
115  problemFound = true;
116  }
117  curToken++;
118  }
119  }
120 
121  return problemFound;
122 }
123 
124 bool checkImageStoragePaths(QStringList &probs)
125 {
126  bool problemFound = false;
127 
128  MSqlQuery query(MSqlQuery::InitCon());
129 
130  query.prepare("SELECT groupname "
131  "FROM storagegroup "
132  "WHERE hostname = :HOSTNAME;");
133  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
134  if (!query.exec() || !query.isActive())
135  {
136  MythDB::DBError("checkImageStoragePaths", query);
137  return false;
138  }
139  if (query.size() < 1)
140  {
141  return false;
142  }
143 
144  QStringList groups;
145  while (query.next())
146  {
147  groups += query.value(0).toString();
148  }
149 
150  if (groups.contains("Videos"))
151  {
152  if (groups.contains("Fanart") &&
153  groups.contains("Coverart") &&
154  groups.contains("Screenshots") &&
155  groups.contains("Banners"))
156  problemFound = false;
157  else
158  {
159  QString trMesg =
160  QObject::tr("You have a Video Storage "
161  "Group, but have not set up "
162  "all Image Groups. If you continue, "
163  "video image downloads will be saved in "
164  "your Videos Storage Group. Do you want "
165  "to store them in their own groups?");
166  probs.push_back(trMesg);
167  LOG(VB_GENERAL, LOG_ERR, trMesg);
168  problemFound = true;
169  }
170  }
171 
172  return problemFound;
173 }
174 
175 // I keep forgetting to change the preset (starting channel) when I add cards,
176 // so this checks that the assigned channel (which may be the default of 3)
177 // actually exists. This should save a few beginner Live TV problems
178 
179 bool checkChannelPresets(QStringList &probs)
180 {
181  bool problemFound = false;
182 
183  MSqlQuery query(MSqlQuery::InitCon());
184 
185  query.prepare("SELECT cardid, startchan, sourceid, inputname, parentid"
186  " FROM capturecard;");
187 
188  if (!query.exec() || !query.isActive())
189  {
190  MythDB::DBError("checkChannelPresets", query);
191  return false;
192  }
193 
194  while (query.next())
195  {
196  int cardid = query.value(0).toInt();
197  QString startchan = query.value(1).toString();
198  int sourceid = query.value(2).toInt();
199  int parentid = query.value(4).toInt();
200 
201  // Warnings only for real devices
202  if (parentid != 0)
203  continue;
204 
205  if (0 == sourceid)
206  {
207  probs.push_back(QObject::tr("Card %1 (%2) No video source connected")
208  .arg(cardid).arg(query.value(3).toString()));
209  problemFound = true;
210  continue;
211  }
212 
213  // Check the start channel and fix it here if needed and if we can.
214  QString newchan = CardUtil::GetStartChannel(cardid);
215  if (!newchan.isEmpty())
216  {
217  if (newchan.compare(startchan) != 0)
218  {
219  bool stat = CardUtil::SetStartChannel(cardid, newchan);
220  QString msg =
221  QString("start channel from %1 to %2 ").arg(startchan, newchan) +
222  QString("for card %1 (%2)").arg(cardid).arg(query.value(3).toString());
223  if (stat)
224  {
225  LOG(VB_GENERAL, LOG_INFO,
226  QString("CheckSetup[%1]: ").arg(cardid) + "Changed " + msg);
227  }
228  else
229  {
230  LOG(VB_GENERAL, LOG_ERR,
231  QString("CheckSetup[%1]: ").arg(cardid) + "Failed to change " + msg);
232  }
233  }
234  }
235  else
236  {
237  probs.push_back(QObject::tr("Card %1 (%2) No visible channels found")
238  .arg(cardid).arg(query.value(3).toString()));
239  problemFound = true;
240  }
241  }
242 
243  return problemFound;
244 }
245 
246 // Check that the display names for all parent inputs are set and that
247 // the last two characters are unique.
248 
249 bool checkInputDisplayNames(QStringList &probs)
250 {
251  bool problemFound = false;
252 
253  MSqlQuery query(MSqlQuery::InitCon());
254 
255  query.prepare("SELECT count(*) total, "
256  " count(distinct right(if(displayname<>'',"
257  " displayname, NULL), 2)) uniq "
258  "FROM capturecard "
259  "WHERE parentid = 0");
260 
261  if (!query.exec() || !query.next())
262  {
263  MythDB::DBError("checkInputDisplayNames", query);
264  return false;
265  }
266 
267  int total = query.value(0).toInt();
268  int uniq = query.value(1).toInt();
269  if (uniq != total)
270  {
271  probs.push_back(QObject::tr(
272  "The display names for one or more inputs are not "
273  "sufficiently unique. They must be set and the "
274  "last two characters must be unique because some "
275  "themes use them to identify the input."));
276  problemFound = true;
277  }
278 
279  return problemFound;
280 }
281 
284 
285 bool CheckSetup(QStringList &problems)
286 {
287  return checkStoragePaths(problems)
288  || checkChannelPresets(problems)
289  || checkInputDisplayNames(problems)
290  || checkImageStoragePaths(problems);
291 }
292 
294 {
295  bool needsReminder = false;
296  MSqlQuery query(MSqlQuery::InitCon());
297 
298  query.prepare("SELECT sourceid "
299  "FROM videosource "
300  "WHERE xmltvgrabber LIKE 'tv_grab_%';");
301  if (!query.exec() || !query.isActive())
302  {
303  MythDB::DBError("needsMFDBReminder", query);
304  }
305  else if (query.size() >= 1)
306  {
307  needsReminder = true;
308  }
309 
310  return needsReminder;
311 }
312 
313 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
checkStoragePaths
bool checkStoragePaths(QStringList &probs)
Do the Storage Group filesystem paths exist? Are they writable? Is the Live TV filesystem large enoug...
Definition: checksetup.cpp:48
mythdb.h
CardUtil::SetStartChannel
static bool SetStartChannel(uint inputid, const QString &channum)
Definition: cardutil.cpp:1678
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
checksetup.h
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
needsMFDBReminder
bool needsMFDBReminder()
Definition: checksetup.cpp:293
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
checkChannelPresets
bool checkChannelPresets(QStringList &probs)
Definition: checksetup.cpp:179
checkInputDisplayNames
bool checkInputDisplayNames(QStringList &probs)
Definition: checksetup.cpp:249
mythdate.h
CheckSetup
bool CheckSetup(QStringList &problems)
Build up a string of common problems that the user should correct in the MythTV-Setup program.
Definition: checksetup.cpp:285
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
checkPath
static bool checkPath(QString path, QStringList &probs)
Check that a directory path exists and is writable.
Definition: checksetup.cpp:23
mythcorecontext.h
cardutil.h
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
checkImageStoragePaths
bool checkImageStoragePaths(QStringList &probs)
Definition: checksetup.cpp:124
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
MythCoreContext::IsMasterHost
bool IsMasterHost(void)
is this the same host as the master
Definition: mythcorecontext.cpp:659
CardUtil::GetStartChannel
static QString GetStartChannel(uint inputid)
Definition: cardutil.cpp:1790
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838