• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements the settings file module for getting, setting and deleting the key-value pairs.
32  */
33 
34 #include "openthread-posix-config.h"
35 #include "platform-posix.h"
36 
37 #include <fcntl.h>
38 #include <inttypes.h>
39 #include <stddef.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 
45 #include "common/code_utils.hpp"
46 #include "common/debug.hpp"
47 #include "posix/platform/settings_file.hpp"
48 
49 namespace ot {
50 namespace Posix {
51 
Init(const char * aSettingsFileBaseName)52 otError SettingsFile::Init(const char *aSettingsFileBaseName)
53 {
54     otError     error     = OT_ERROR_NONE;
55     const char *directory = OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH;
56 
57     OT_ASSERT((aSettingsFileBaseName != nullptr) && (strlen(aSettingsFileBaseName) < kMaxFileBaseNameSize));
58     strncpy(mSettingFileBaseName, aSettingsFileBaseName, sizeof(mSettingFileBaseName) - 1);
59 
60     {
61         struct stat st;
62 
63         if (stat(directory, &st) == -1)
64         {
65             VerifyOrDie(mkdir(directory, 0755) == 0, OT_EXIT_ERROR_ERRNO);
66         }
67     }
68 
69     {
70         char fileName[kMaxFilePathSize];
71 
72         GetSettingsFilePath(fileName, false);
73         mSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
74     }
75 
76     VerifyOrDie(mSettingsFd != -1, OT_EXIT_ERROR_ERRNO);
77 
78     for (off_t size = lseek(mSettingsFd, 0, SEEK_END), offset = lseek(mSettingsFd, 0, SEEK_SET); offset < size;)
79     {
80         uint16_t key;
81         uint16_t length;
82         ssize_t  rval;
83 
84         rval = read(mSettingsFd, &key, sizeof(key));
85         VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
86 
87         rval = read(mSettingsFd, &length, sizeof(length));
88         VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
89 
90         offset += sizeof(key) + sizeof(length) + length;
91         VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
92     }
93 
94 exit:
95     if (error == OT_ERROR_PARSE)
96     {
97         VerifyOrDie(ftruncate(mSettingsFd, 0) == 0, OT_EXIT_ERROR_ERRNO);
98     }
99 
100     return error;
101 }
102 
Deinit(void)103 void SettingsFile::Deinit(void)
104 {
105     VerifyOrExit(mSettingsFd != -1);
106     VerifyOrDie(close(mSettingsFd) == 0, OT_EXIT_ERROR_ERRNO);
107     mSettingsFd = -1;
108 
109 exit:
110     return;
111 }
112 
Get(uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength)113 otError SettingsFile::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
114 {
115     otError error = OT_ERROR_NOT_FOUND;
116     off_t   size;
117     off_t   offset;
118 
119     OT_ASSERT(mSettingsFd >= 0);
120 
121     size   = lseek(mSettingsFd, 0, SEEK_END);
122     offset = lseek(mSettingsFd, 0, SEEK_SET);
123     VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
124 
125     while (offset < size)
126     {
127         uint16_t key;
128         uint16_t length;
129         ssize_t  rval;
130 
131         rval = read(mSettingsFd, &key, sizeof(key));
132         VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
133 
134         rval = read(mSettingsFd, &length, sizeof(length));
135         VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
136 
137         if (key == aKey)
138         {
139             if (aIndex == 0)
140             {
141                 error = OT_ERROR_NONE;
142 
143                 if (aValueLength)
144                 {
145                     if (aValue)
146                     {
147                         uint16_t readLength = (length <= *aValueLength ? length : *aValueLength);
148 
149                         VerifyOrExit(read(mSettingsFd, aValue, readLength) == readLength, error = OT_ERROR_PARSE);
150                     }
151 
152                     *aValueLength = length;
153                 }
154 
155                 break;
156             }
157             else
158             {
159                 --aIndex;
160             }
161         }
162 
163         offset += sizeof(key) + sizeof(length) + length;
164         VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
165     }
166 
167 exit:
168     return error;
169 }
170 
Set(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)171 void SettingsFile::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
172 {
173     int swapFd = -1;
174 
175     OT_ASSERT(mSettingsFd >= 0);
176 
177     switch (Delete(aKey, -1, &swapFd))
178     {
179     case OT_ERROR_NONE:
180     case OT_ERROR_NOT_FOUND:
181         break;
182 
183     default:
184         OT_ASSERT(false);
185         break;
186     }
187 
188     VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
189                     write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
190                     write(swapFd, aValue, aValueLength) == aValueLength,
191                 OT_EXIT_FAILURE);
192 
193     SwapPersist(swapFd);
194 }
195 
Add(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)196 void SettingsFile::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
197 {
198     off_t size;
199     int   swapFd;
200 
201     OT_ASSERT(mSettingsFd >= 0);
202 
203     size   = lseek(mSettingsFd, 0, SEEK_END);
204     swapFd = SwapOpen();
205 
206     if (size > 0)
207     {
208         VerifyOrDie(0 == lseek(mSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO);
209         SwapWrite(swapFd, static_cast<uint16_t>(size));
210     }
211 
212     VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
213                     write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
214                     write(swapFd, aValue, aValueLength) == aValueLength,
215                 OT_EXIT_FAILURE);
216 
217     SwapPersist(swapFd);
218 }
219 
Delete(uint16_t aKey,int aIndex)220 otError SettingsFile::Delete(uint16_t aKey, int aIndex) { return Delete(aKey, aIndex, nullptr); }
221 
Delete(uint16_t aKey,int aIndex,int * aSwapFd)222 otError SettingsFile::Delete(uint16_t aKey, int aIndex, int *aSwapFd)
223 {
224     otError error = OT_ERROR_NOT_FOUND;
225     off_t   size;
226     off_t   offset;
227     int     swapFd;
228 
229     OT_ASSERT(mSettingsFd >= 0);
230 
231     size   = lseek(mSettingsFd, 0, SEEK_END);
232     offset = lseek(mSettingsFd, 0, SEEK_SET);
233     swapFd = SwapOpen();
234 
235     OT_ASSERT(swapFd != -1);
236     OT_ASSERT(offset == 0);
237     VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_FAILED);
238 
239     while (offset < size)
240     {
241         uint16_t key;
242         uint16_t length;
243         ssize_t  rval;
244 
245         rval = read(mSettingsFd, &key, sizeof(key));
246         VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
247 
248         rval = read(mSettingsFd, &length, sizeof(length));
249         VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
250 
251         offset += sizeof(key) + sizeof(length) + length;
252 
253         if (aKey == key)
254         {
255             if (aIndex == 0)
256             {
257                 VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
258                 SwapWrite(swapFd, static_cast<uint16_t>(size - offset));
259                 error = OT_ERROR_NONE;
260                 break;
261             }
262             else if (aIndex == -1)
263             {
264                 VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
265                 error = OT_ERROR_NONE;
266                 continue;
267             }
268             else
269             {
270                 --aIndex;
271             }
272         }
273 
274         rval = write(swapFd, &key, sizeof(key));
275         VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
276 
277         rval = write(swapFd, &length, sizeof(length));
278         VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
279 
280         SwapWrite(swapFd, length);
281     }
282 
283 exit:
284     if (aSwapFd != nullptr)
285     {
286         *aSwapFd = swapFd;
287     }
288     else if (error == OT_ERROR_NONE)
289     {
290         SwapPersist(swapFd);
291     }
292     else if (error == OT_ERROR_NOT_FOUND)
293     {
294         SwapDiscard(swapFd);
295     }
296     else if (error == OT_ERROR_FAILED)
297     {
298         SwapDiscard(swapFd);
299         DieNow(error);
300     }
301 
302     return error;
303 }
304 
Wipe(void)305 void SettingsFile::Wipe(void) { VerifyOrDie(0 == ftruncate(mSettingsFd, 0), OT_EXIT_ERROR_ERRNO); }
306 
GetSettingsFilePath(char aFileName[kMaxFilePathSize],bool aSwap)307 void SettingsFile::GetSettingsFilePath(char aFileName[kMaxFilePathSize], bool aSwap)
308 {
309     snprintf(aFileName, kMaxFilePathSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s.%s", mSettingFileBaseName,
310              (aSwap ? "Swap" : "data"));
311 }
312 
SwapOpen(void)313 int SettingsFile::SwapOpen(void)
314 {
315     char fileName[kMaxFilePathSize];
316     int  fd;
317 
318     GetSettingsFilePath(fileName, true);
319 
320     fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
321     VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO);
322 
323     return fd;
324 }
325 
SwapWrite(int aFd,uint16_t aLength)326 void SettingsFile::SwapWrite(int aFd, uint16_t aLength)
327 {
328     const size_t kBlockSize = 512;
329     uint8_t      buffer[kBlockSize];
330 
331     while (aLength > 0)
332     {
333         uint16_t count = aLength >= sizeof(buffer) ? sizeof(buffer) : aLength;
334         ssize_t  rval  = read(mSettingsFd, buffer, count);
335 
336         VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
337         count = static_cast<uint16_t>(rval);
338         rval  = write(aFd, buffer, count);
339         OT_ASSERT(rval == count);
340         VerifyOrDie(rval == count, OT_EXIT_FAILURE);
341         aLength -= count;
342     }
343 }
344 
SwapPersist(int aFd)345 void SettingsFile::SwapPersist(int aFd)
346 {
347     char swapFile[kMaxFilePathSize];
348     char dataFile[kMaxFilePathSize];
349 
350     GetSettingsFilePath(swapFile, true);
351     GetSettingsFilePath(dataFile, false);
352 
353     VerifyOrDie(0 == close(mSettingsFd), OT_EXIT_ERROR_ERRNO);
354     VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO);
355     VerifyOrDie(0 == rename(swapFile, dataFile), OT_EXIT_ERROR_ERRNO);
356 
357     mSettingsFd = aFd;
358 }
359 
SwapDiscard(int aFd)360 void SettingsFile::SwapDiscard(int aFd)
361 {
362     char swapFileName[kMaxFilePathSize];
363 
364     VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO);
365     GetSettingsFilePath(swapFileName, true);
366     VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO);
367 }
368 
369 } // namespace Posix
370 } // namespace ot
371