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