Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
ostree_mock.c
1 #define _GNU_SOURCE
2 #include <assert.h>
3 #include <dlfcn.h>
4 #include <ostree.h>
5 #include <stdio.h>
6 
7 /**
8  * @brief This mock allows the OSTree package manager usage on non-OSTree booted environment, e.g. local host
9  *
10  * in order to use it the following has to be pre-defined
11  * 1) OSTREE_DEPLOYMENT_VERSION_FILE environment variable that points to the test file containing a revision
12  * hash/checksum and its serial number 2) LD_PRELOAD environment variable that refers to the libostree_mock.so 3)
13  * [pacman].os == OSTREE_DEPLOYMENT_OS_NAME (aktualizr configuration, pacman section, os field must be equal to
14  * OSTREE_DEPLOYMENT_OS_NAME defined here)
15  *
16  * OSTREE_DEPLOYMENT_VERSION_FILE must follow this schema/format
17  *
18  * <deployed-revision-hash>\n
19  * <deployed-revision-serial>\n
20  * <booted-revision-hash>\n
21  * <booted-revision-serial>
22  *
23  * For example
24  *
25  * d0ef921904bc573616a42e862de2421b265a76d06a334cfe5ad9f811107bbee0
26  * 0
27  * d0ef921904bc573616a42e862de2421b265a76d06a334cfe5ad9f811107bbee0
28  * 0
29  */
30 
31 static const char OSTREE_DEPLOYMENT_OS_NAME[] = "dummy-os";
32 static const char OSTREE_DEPLOYMENT_VERSION_FILE[] = "OSTREE_DEPLOYMENT_VERSION_FILE";
33 
35  int serial;
36  char rev[256];
37 };
38 
39 static int get_ostree_deployment_version(const char* filename, struct OstreeDeploymentVersion* deployed,
40  struct OstreeDeploymentVersion* booted);
41 
43  struct OstreeDeploymentVersion deployed;
44  struct OstreeDeploymentVersion booted;
45  OstreeDeployment* booted_ostree_native_deployment;
46 };
47 
48 static struct OstreeDeploymentInfo* get_ostree_deployment_info() {
49  // NOTE: Is not tread-safe. This mock is used solely for testing and normally is called from one thread of the
50  // Aktualirz
51  static struct OstreeDeploymentInfo DeploymentInfo;
52  static int isDeploymentInfoLoaded = 0;
53 
54  if (isDeploymentInfoLoaded) {
55  return &DeploymentInfo;
56  }
57 
58  const char* deployment_version_file = NULL;
59  if ((deployment_version_file = getenv(OSTREE_DEPLOYMENT_VERSION_FILE)) == NULL) {
60  return NULL;
61  }
62 
63  if (get_ostree_deployment_version(deployment_version_file, &DeploymentInfo.deployed, &DeploymentInfo.booted) != 0) {
64  return NULL;
65  }
66 
67  // Allocation of the singletone object in a heap, one instance per a process, a memory will be released during
68  // the process teardown, no need in explicit deallocation
69  DeploymentInfo.booted_ostree_native_deployment =
70  ostree_deployment_new(0, OSTREE_DEPLOYMENT_OS_NAME, DeploymentInfo.deployed.rev, DeploymentInfo.deployed.serial,
71  DeploymentInfo.booted.rev, DeploymentInfo.booted.serial);
72 
73  assert(DeploymentInfo.booted_ostree_native_deployment != NULL);
74 
75  isDeploymentInfoLoaded = 1;
76 
77  return &DeploymentInfo;
78 }
79 
80 const char* ostree_deployment_get_csum(OstreeDeployment* self) {
81  const char* (*orig)(OstreeDeployment*) = (const char* (*)(OstreeDeployment*))(dlsym(RTLD_NEXT, __func__));
82  struct OstreeDeploymentInfo* deployment_info = get_ostree_deployment_info();
83 
84  if (deployment_info != NULL) {
85  return deployment_info->deployed.rev;
86  }
87 
88  return orig(self);
89 }
90 
91 OstreeDeployment* ostree_sysroot_get_booted_deployment(OstreeSysroot* self) {
92  OstreeDeployment* (*orig)(OstreeSysroot*) = (OstreeDeployment * (*)(OstreeSysroot*))(dlsym(RTLD_NEXT, __func__));
93  struct OstreeDeploymentInfo* deployment_info = get_ostree_deployment_info();
94 
95  if (deployment_info != NULL) {
96  return deployment_info->booted_ostree_native_deployment;
97  }
98 
99  return orig(self);
100 }
101 
102 static int read_deployment_info(FILE* file, struct OstreeDeploymentVersion* deployment) {
103  struct OstreeDeploymentVersion deployment_res;
104 
105  // TODO: make it more robust and reliable as a file might contain a value exceeding 255
106  if (fscanf(file, "%254s\n", deployment_res.rev) != 1) {
107  return -1;
108  }
109 
110  // TODO: make it more robust and reliable as a file might contain a value exceeding 255 and/or char(s) instead of a
111  // number for the serial value
112  if (fscanf(file, "%d\n", &deployment_res.serial) != 1) {
113  return -1;
114  }
115 
116  *deployment = deployment_res;
117  return 0;
118 }
119 
120 static int get_ostree_deployment_version(const char* filename, struct OstreeDeploymentVersion* deployed,
121  struct OstreeDeploymentVersion* booted) {
122  FILE* file = fopen(filename, "r");
123  if (file == NULL) {
124  printf("\n>>>>>>>>>> Failed to open the file: %s\n\n", filename);
125  return -1;
126  }
127 
128  int return_code = -1;
129 
130  do {
131  struct OstreeDeploymentVersion deployed_res;
132  if (read_deployment_info(file, &deployed_res) != 0) {
133  break;
134  }
135 
136  if (booted != NULL) {
137  struct OstreeDeploymentVersion booted_res;
138  if (read_deployment_info(file, &booted_res) != 0) {
139  break;
140  }
141  *booted = booted_res;
142  }
143 
144  *deployed = deployed_res;
145  return_code = 0;
146  } while (0);
147 
148  fclose(file);
149  if (return_code != 0) {
150  printf("%s: Failed to read the deployment info from: %s\n", __FILE__, filename);
151  }
152  return return_code;
153 }
OstreeDeploymentVersion
Definition: ostree_mock.c:34
OstreeDeploymentInfo
Definition: ostree_mock.c:42