Skip to content

Commit bb7ff67

Browse files
Update lockfile handler (#332)
* fixes bug of device client not starting when filesystem requirements are not met
1 parent fb17eae commit bb7ff67

File tree

6 files changed

+85
-42
lines changed

6 files changed

+85
-42
lines changed

integration-tests/entry-point.sh

+30-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ CERT_PATH=${CERT_DIRECTORY}cert.crt
88
KEY_PATH=${CERT_DIRECTORY}key.pem
99
ROOT_CA_PATH=${CERT_DIRECTORY}AmazonRootCA1.pem
1010

11-
# Ensure /run/lock exists
12-
mkdir -p /run/lock > dev/null
13-
1411
# create Certificate Directory
1512
mkdir -p ${CERT_DIRECTORY}
1613

@@ -60,6 +57,36 @@ chmod 640 ${CONFIG_PATH}
6057
# start ssh
6158
service ssh start || true
6259

60+
# Ensure lockfile exists
61+
mkdir -p /run/lock > dev/null
62+
63+
# Spoof lockfile
64+
echo "${THING_NAME}" > /run/lock/devicecl.lock
65+
bash -c 'sleep 1000' &
66+
FAKE_PID=$!
67+
echo ${FAKE_PID} >> /run/lock/devicecl.lock
68+
69+
# TEST: Start and stop Device Client
70+
# 1. Rename aws-iot-device-client to sleep and exec binary
71+
# 2. Kill dummy process
72+
# 3. Kill Device Client. If Device Client has already exited as expected, then pkill will return 1, and we pass the test
73+
cp aws-iot-device-client sleep
74+
./sleep &
75+
DC_PID=$!
76+
77+
# give some buffer time for the background instance of DC to run its logic.
78+
sleep 5
79+
kill $FAKE_PID
80+
kill $DC_PID
81+
retVal=$?
82+
if [ $retVal -ne 1 ]; then
83+
echo 'TEST FAILURE: Device Client ran with a valid lockfile already in place.'
84+
exit 1
85+
fi
86+
87+
# Cleanup
88+
rm -rf /run/lock
89+
6390
# start Device Client
6491
./aws-iot-device-client 2>&1 &
6592

source/config/Config.cpp

-9
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,6 @@ bool PlainConfig::Validate() const
326326
{
327327
return false;
328328
}
329-
if (lockFilePath.empty() || !FileUtils::IsValidFilePath(lockFilePath))
330-
{
331-
LOGM_ERROR(
332-
Config::TAG,
333-
"*** %s: Invalid Lock File Path %s ***",
334-
DeviceClient::DC_FATAL_ERROR,
335-
Sanitize(lockFilePath).c_str());
336-
return false;
337-
}
338329
if (rootCa.has_value() && !rootCa->empty() && FileUtils::FileExists(rootCa->c_str()))
339330
{
340331
string parentDir = FileUtils::ExtractParentDirectory(rootCa->c_str());

source/main.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,13 @@ bool init(int argc, char *argv[])
113113
string filename = config.config.lockFilePath;
114114
if (!filename.empty())
115115
{
116-
lockFile = unique_ptr<LockFile>(new LockFile{filename, argv[0]});
116+
string thing;
117+
if (config.config.thingName.has_value() && !config.config.thingName.value().empty())
118+
{
119+
thing = config.config.thingName.value();
120+
}
121+
122+
lockFile = unique_ptr<LockFile>(new LockFile{filename, argv[0], thing});
117123
}
118124
}
119125
catch (std::runtime_error &e)
@@ -316,7 +322,7 @@ int main(int argc, char *argv[])
316322
*/
317323
if (!init(argc, argv))
318324
{
319-
return -1;
325+
return 1;
320326
}
321327
features = make_shared<FeatureRegistry>();
322328

@@ -537,6 +543,9 @@ int main(int argc, char *argv[])
537543
case SIGINT:
538544
shutdown();
539545
break;
546+
case SIGTERM:
547+
shutdown();
548+
break;
540549
case SIGHUP:
541550
resourceManager->dumpMemTrace();
542551
break;

source/util/LockFile.cpp

+15-11
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,22 @@ using namespace Aws::Iot::DeviceClient::Logging;
1616
constexpr char LockFile::TAG[];
1717
constexpr char LockFile::FILE_NAME[];
1818

19-
LockFile::LockFile(const std::string &filedir, const std::string &process) : dir(filedir)
19+
LockFile::LockFile(const std::string &filedir, const std::string &process, const std::string &thingName) : dir(filedir)
2020
{
21+
LOG_DEBUG(TAG, "creating lockfile");
2122
string fullPath = dir + FILE_NAME;
2223
ifstream fileIn(fullPath);
2324
if (fileIn)
2425
{
26+
string storedThingName;
2527
string storedPid;
26-
if (fileIn >> storedPid && !(kill(stoi(storedPid), 0) == -1 && errno == ESRCH))
28+
if (fileIn >> storedThingName && storedThingName == thingName && fileIn >> storedPid &&
29+
!(kill(stoi(storedPid), 0) == -1 && errno == ESRCH))
2730
{
2831
string processPath = "/proc/" + storedPid + "/cmdline";
2932
string basename = process.substr(process.find_last_of("/\\") + 1);
3033
string cmdline;
3134
ifstream cmd(processPath.c_str());
32-
33-
// check if process contains name
3435
if (cmd && cmd >> cmdline && cmdline.find(basename) != string::npos)
3536
{
3637
LOGM_ERROR(
@@ -56,14 +57,17 @@ LockFile::LockFile(const std::string &filedir, const std::string &process) : dir
5657
FILE *file = fopen(fullPath.c_str(), "wx");
5758
if (!file)
5859
{
59-
LOGM_ERROR(TAG, "Unable to open lockfile: %s", Sanitize(fullPath).c_str());
60-
61-
throw runtime_error{"Can not write to lockfile."};
60+
LOGM_ERROR(
61+
TAG, "Unable to open lockfile. File may be in use or does not exist: %s", Sanitize(fullPath).c_str());
62+
}
63+
else
64+
{
65+
string pid = to_string(getpid());
66+
fputs(thingName.c_str(), file);
67+
fputs(string("\n").c_str(), file);
68+
fputs(pid.c_str(), file);
69+
fclose(file);
6270
}
63-
64-
string pid = to_string(getpid());
65-
fputs(pid.c_str(), file);
66-
fclose(file);
6771
}
6872

6973
LockFile::~LockFile()

source/util/LockFile.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace Aws
3131
* @param filedir directory the lockfile will be written to
3232
* @param process the executable path passed in by argv[0], usually aws-iot-device-client
3333
*/
34-
explicit LockFile(const std::string &filedir, const std::string &process);
34+
LockFile(const std::string &filedir, const std::string &process, const std::string &thingName);
3535
/**
3636
* This class uses RAII for resource management. Destructor will be called on program exit and the
3737
* file will be deleted.

test/util/TestLockFile.cpp

+28-16
Original file line numberDiff line numberDiff line change
@@ -14,69 +14,81 @@ using namespace Aws::Iot::DeviceClient::Util;
1414
TEST(LockFile, normalCreation)
1515
{
1616
string path = "/run/lock/";
17-
string filename = "devicecl.lock";
18-
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "./aws-iot-device-client"});
17+
string fileName = "devicecl.lock";
18+
string thingName = "thing";
19+
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "./aws-iot-device-client", thingName});
1920

20-
ifstream fileIn(path + filename);
21+
ifstream fileIn(path + fileName);
2122
ASSERT_TRUE(fileIn);
2223

2324
string storedPid;
24-
if (fileIn >> storedPid)
25+
string storedName;
26+
if (fileIn >> storedName && fileIn >> storedPid)
2527
{
28+
ASSERT_STREQ(thingName.c_str(), storedName.c_str());
2629
ASSERT_STREQ(to_string(getpid()).c_str(), storedPid.c_str());
2730
}
2831
}
2932

3033
TEST(LockFile, earlyDeletion)
3134
{
3235
string path = "/run/lock/";
33-
string filename = "devicecl.lock";
34-
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client"});
36+
string fileName = "devicecl.lock";
37+
string thingName = "thing";
38+
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client", thingName});
3539
lockFile.reset();
3640

37-
ifstream fileIn(path + filename);
41+
ifstream fileIn(path + fileName);
3842
ASSERT_FALSE(fileIn);
3943
}
4044

4145
TEST(LockFile, multipleFiles)
4246
{
4347
string path = "/run/lock/";
44-
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client"});
48+
string thingName = "thing";
49+
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client", thingName});
4550

46-
EXPECT_THROW(unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client"}), std::runtime_error);
51+
EXPECT_THROW(unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client", thingName}), std::runtime_error);
4752
}
4853

4954
TEST(LockFile, multipleFilesWithExtendedPath)
5055
{
5156
string path = "/run/lock/";
52-
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client"});
57+
string thingName = "thing";
58+
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client", thingName});
5359

54-
EXPECT_THROW(unique_ptr<LockFile>(new LockFile{path, "directory/test-aws-iot-device-client"}), std::runtime_error);
60+
EXPECT_THROW(
61+
unique_ptr<LockFile>(new LockFile{path, "directory/test-aws-iot-device-client", thingName}),
62+
std::runtime_error);
5563
}
5664

5765
TEST(LockFile, staleFile)
5866
{
5967
string path = "/run/lock/";
60-
string filename = "devicecl.lock";
68+
string fileName = "devicecl.lock";
69+
string thingName = "thing";
6170
string pidMax;
6271
ifstream pidFile("/proc/sys/kernel/pid_max");
6372
if (pidFile && pidFile >> pidMax)
6473
{
65-
ofstream fileOut(path + filename);
74+
ofstream fileOut(path + fileName);
6675
if (fileOut)
6776
{
6877
fileOut << pidMax;
6978
}
7079
fileOut.close();
7180

72-
unique_ptr<LockFile> lockFile = unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client"});
81+
unique_ptr<LockFile> lockFile =
82+
unique_ptr<LockFile>(new LockFile{path, "test-aws-iot-device-client", thingName});
7383

74-
ifstream fileIn(path + filename);
84+
ifstream fileIn(path + fileName);
7585
ASSERT_TRUE(fileIn);
7686

7787
string storedPid;
78-
if (fileIn >> storedPid)
88+
string storedName;
89+
if (fileIn >> storedName && fileIn >> storedPid)
7990
{
91+
ASSERT_STREQ(thingName.c_str(), storedName.c_str());
8092
ASSERT_STREQ(to_string(getpid()).c_str(), storedPid.c_str());
8193
}
8294
}

0 commit comments

Comments
 (0)