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 #include <QDir>
10 
11 #include "mythdb.h"
12 #include "mythcorecontext.h"
13 #include "mythdate.h"
14 #include "checksetup.h"
15 
17 
18 static bool checkPath(QString path, QStringList &probs)
19 {
20  QDir dir(path);
21  if (!dir.exists())
22  {
23  probs.push_back(QObject::tr("Path \"%1\" doesn't exist.").arg(path));
24  return true;
25  }
26 
27  QFile test(path.append("/.test"));
28  if (test.open(QIODevice::WriteOnly))
29  test.remove();
30  else
31  {
32  probs.push_back(QObject::tr("Unable to create file \"%1\" - directory "
33  "is not writable?").arg(path));
34  return true;
35  }
36 
37  return false;
38 }
39 
42 
43 bool checkStoragePaths(QStringList &probs)
44 {
45  bool problemFound = false;
46 
48 
49  query.prepare("SELECT count(groupname) FROM storagegroup;");
50  if (!query.exec() || !query.next())
51  {
52  MythDB::DBError("checkStoragePaths", query);
53  return false;
54  }
55 
56  if (query.value(0).toInt() == 0)
57  {
58  QString trMesg =
59  QObject::tr("No Storage Group directories are defined. You "
60  "must add at least one directory to the Default "
61  "Storage Group where new recordings will be "
62  "stored.");
63  probs.push_back(trMesg);
64  LOG(VB_GENERAL, LOG_ERR, trMesg);
65  return true;
66  }
67 
68  query.prepare("SELECT groupname, dirname "
69  "FROM storagegroup "
70  "WHERE hostname = :HOSTNAME;");
71  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
72  if (!query.exec() || !query.isActive())
73  {
74  MythDB::DBError("checkStoragePaths", query);
75  return false;
76  }
77  if (query.size() < 1)
78  {
80  {
81  // Master backend must have a defined Default SG
82  QString trMesg =
83  QObject::tr("No Storage Group directories are defined. "
84  "You must add at least one directory to the "
85  "Default Storage Group where new recordings "
86  "will be stored.");
87  probs.push_back(trMesg);
88  LOG(VB_GENERAL, LOG_ERR, trMesg);
89  return true;
90  }
91  return false;
92  }
93 
94  QDir checkDir("");
95  QString dirname;
96  while (query.next())
97  {
98  /* The storagegroup.dirname column uses utf8_bin collation, so Qt
99  * uses QString::fromAscii() for toString(). Explicitly convert the
100  * value using QString::fromUtf8() to prevent corruption. */
101  dirname = QString::fromUtf8(query.value(1)
102  .toByteArray().constData());
103  QStringList tokens = dirname.split(",");
104  int curToken = 0;
105  while (curToken < tokens.size())
106  {
107  checkDir.setPath(tokens[curToken]);
108  if (checkPath(tokens[curToken], probs))
109  {
110  problemFound = true;
111  }
112  curToken++;
113  }
114  }
115 
116  return problemFound;
117 }
118 
119 bool checkImageStoragePaths(QStringList &probs)
120 {
121  bool problemFound = false;
122 
123  MSqlQuery query(MSqlQuery::InitCon());
124 
125  query.prepare("SELECT groupname "
126  "FROM storagegroup "
127  "WHERE hostname = :HOSTNAME;");
128  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
129  if (!query.exec() || !query.isActive())
130  {
131  MythDB::DBError("checkImageStoragePaths", query);
132  return false;
133  }
134  if (query.size() < 1)
135  {
136  return false;
137  }
138 
139  QStringList groups;
140  while (query.next())
141  {
142  groups += query.value(0).toString();
143  }
144 
145  if (groups.contains("Videos"))
146  {
147  if (groups.contains("Fanart") &&
148  groups.contains("Coverart") &&
149  groups.contains("Screenshots") &&
150  groups.contains("Banners"))
151  problemFound = false;
152  else
153  {
154  QString trMesg =
155  QObject::tr("You have a Video Storage "
156  "Group, but have not set up "
157  "all Image Groups. If you continue, "
158  "video image downloads will be saved in "
159  "your Videos Storage Group. Do you want "
160  "to store them in their own groups?");
161  probs.push_back(trMesg);
162  LOG(VB_GENERAL, LOG_ERR, trMesg);
163  problemFound = true;
164  }
165  }
166 
167  return problemFound;
168 }
169 
170 // I keep forgetting to change the preset (starting channel) when I add cards,
171 // so this checks that the assigned channel (which may be the default of 3)
172 // actually exists. This should save a few beginner Live TV problems
173 
174 bool checkChannelPresets(QStringList &probs)
175 {
176  bool problemFound = false;
177 
178  MSqlQuery query(MSqlQuery::InitCon());
179 
180  query.prepare("SELECT cardid, startchan, sourceid, inputname, parentid"
181  " FROM capturecard;");
182 
183  if (!query.exec() || !query.isActive())
184  {
185  MythDB::DBError("checkChannelPresets", query);
186  return false;
187  }
188 
189  while (query.next())
190  {
191  int cardid = query.value(0).toInt();
192  QString startchan = query.value(1).toString();
193  int sourceid = query.value(2).toInt();
194  int parentid = query.value(4).toInt();
195 
196  // Warnings only for real devices
197  if (parentid != 0)
198  continue;
199 
200  if (0 == sourceid)
201  {
202  probs.push_back(QObject::tr("Card %1 (type %2) is not connected "
203  "to a video source.")
204  .arg(cardid).arg(query.value(3).toString()));
205  problemFound = true;
206  continue;
207  }
208 
209  if (query.value(1).toString().isEmpty()) // Logic from tv_rec.cpp
210  startchan = "3";
211 
212  MSqlQuery channelExists(MSqlQuery::InitCon());
213  QString channelQuery;
214  channelQuery = QString("SELECT chanid FROM channel"
215  " WHERE channum='%1' AND sourceid=%2;")
216  .arg(startchan).arg(sourceid);
217  channelExists.prepare(channelQuery);
218 
219  if (!channelExists.exec() || !channelExists.isActive())
220  {
221  MythDB::DBError("checkChannelPresets", channelExists);
222  return problemFound;
223  }
224 
225  if (channelExists.size() == 0)
226  {
227  probs.push_back(QObject::tr("Card %1 (type %2) is set to start on "
228  "channel %3, which does not exist.")
229  .arg(cardid).arg(query.value(3).toString()).arg(startchan));
230  problemFound = true;
231  }
232  }
233 
234  return problemFound;
235 }
236 
239 
240 bool CheckSetup(QStringList &problems)
241 {
242  return checkStoragePaths(problems)
243  || checkChannelPresets(problems)
244  || checkImageStoragePaths(problems);
245 }
246 
248 {
249  bool needsReminder = false;
250  MSqlQuery query(MSqlQuery::InitCon());
251 
252  query.prepare("SELECT sourceid "
253  "FROM videosource "
254  "WHERE xmltvgrabber LIKE 'tv_grab_%';");
255  if (!query.exec() || !query.isActive())
256  {
257  MythDB::DBError("needsMFDBReminder", query);
258  }
259  else if (query.size() >= 1)
260  {
261  needsReminder = true;
262  }
263 
264  return needsReminder;
265 }
266 
267 /* vim: set expandtab tabstop=4 shiftwidth=4: */
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
bool CheckSetup(QStringList &problems)
Build up a string of common problems that the user should correct in the MythTV-Setup program.
Definition: checksetup.cpp:240
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
static bool checkPath(QString path, QStringList &probs)
Check that a directory path exists and is writable.
Definition: checksetup.cpp:18
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
int size(void) const
Definition: mythdbcon.h:203
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QVariant value(int i) const
Definition: mythdbcon.h:198
bool needsMFDBReminder()
Definition: checksetup.cpp:247
bool checkImageStoragePaths(QStringList &probs)
Definition: checksetup.cpp:119
bool isActive(void) const
Definition: mythdbcon.h:204
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
bool IsMasterHost(void)
is this the same host as the master
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool checkStoragePaths(QStringList &probs)
Do the Storage Group filesystem paths exist? Are they writable? Is the Live TV filesystem large enoug...
Definition: checksetup.cpp:43
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
QString GetHostName(void)
bool checkChannelPresets(QStringList &probs)
Definition: checksetup.cpp:174