You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							154 lines
						
					
					
						
							3.1 KiB
						
					
					
				
			
		
		
	
	
							154 lines
						
					
					
						
							3.1 KiB
						
					
					
				| #include "selfdrive/common/params.h"
 | |
| 
 | |
| #include "selfdrive/common/util.h"
 | |
| 
 | |
| #ifndef _GNU_SOURCE
 | |
| #define _GNU_SOURCE
 | |
| #endif  // _GNU_SOURCE
 | |
| 
 | |
| #include <sys/file.h>
 | |
| #include <unistd.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| template <typename T>
 | |
| T* null_coalesce(T* a, T* b) {
 | |
|   return a != NULL ? a : b;
 | |
| }
 | |
| 
 | |
| static const char* default_params_path = null_coalesce(
 | |
|     const_cast<const char*>(getenv("PARAMS_PATH")), "/data/params");
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| int write_db_value(const char* params_path, const char* key, const char* value,
 | |
|                    size_t value_size) {
 | |
|   int lock_fd = -1;
 | |
|   int tmp_fd = -1;
 | |
|   int result;
 | |
|   char tmp_path[1024];
 | |
|   char path[1024];
 | |
|   ssize_t bytes_written;
 | |
| 
 | |
|   if (params_path == NULL) {
 | |
|     params_path = default_params_path;
 | |
|   }
 | |
| 
 | |
|   // Write value to temp.
 | |
|   result =
 | |
|       snprintf(tmp_path, sizeof(tmp_path), "%s/.tmp_value_XXXXXX", params_path);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   tmp_fd = mkstemp(tmp_path);
 | |
|   bytes_written = write(tmp_fd, value, value_size);
 | |
|   if (bytes_written != value_size) {
 | |
|     result = -20;
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   result = snprintf(path, sizeof(path), "%s/.lock", params_path);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
|   lock_fd = open(path, 0);
 | |
| 
 | |
|   result = snprintf(path, sizeof(path), "%s/d/%s", params_path, key);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // Take lock.
 | |
|   result = flock(lock_fd, LOCK_EX);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // fsync to force persist the changes.
 | |
|   result = fsync(tmp_fd);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // Move temp into place.
 | |
|   result = rename(tmp_path, path);
 | |
| 
 | |
| cleanup:
 | |
|   // Release lock.
 | |
|   if (lock_fd >= 0) {
 | |
|     close(lock_fd);
 | |
|   }
 | |
|   if (tmp_fd >= 0) {
 | |
|     if (result < 0) {
 | |
|       remove(tmp_path);
 | |
|     }
 | |
|     close(tmp_fd);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| int read_db_value(const char* params_path, const char* key, char** value,
 | |
|                   size_t* value_sz) {
 | |
|   int lock_fd = -1;
 | |
|   int result;
 | |
|   char path[1024];
 | |
| 
 | |
|   if (params_path == NULL) {
 | |
|     params_path = default_params_path;
 | |
|   }
 | |
| 
 | |
|   result = snprintf(path, sizeof(path), "%s/.lock", params_path);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
|   lock_fd = open(path, 0);
 | |
| 
 | |
|   result = snprintf(path, sizeof(path), "%s/d/%s", params_path, key);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // Take lock.
 | |
|   result = flock(lock_fd, LOCK_EX);
 | |
|   if (result < 0) {
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // Read value.
 | |
|   // TODO(mgraczyk): If there is a lot of contention, we can release the lock
 | |
|   //                 after opening the file, before reading.
 | |
|   *value = static_cast<char*>(read_file(path, value_sz));
 | |
|   if (*value == NULL) {
 | |
|     result = -22;
 | |
|     goto cleanup;
 | |
|   }
 | |
| 
 | |
|   // Remove one for null byte.
 | |
|   if (value_sz != NULL) {
 | |
|     *value_sz -= 1;
 | |
|   }
 | |
|   result = 0;
 | |
| 
 | |
| cleanup:
 | |
|   // Release lock.
 | |
|   if (lock_fd >= 0) {
 | |
|     close(lock_fd);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void read_db_value_blocking(const char* params_path, const char* key,
 | |
|                             char** value, size_t* value_sz) {
 | |
|   while (1) {
 | |
|     const int result = read_db_value(params_path, key, value, value_sz);
 | |
|     if (result == 0) {
 | |
|       return;
 | |
|     } else {
 | |
|       // Sleep for 0.1 seconds.
 | |
|       usleep(100000);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 |