lttng: start: ensure a cmd_error_code is returned by the command
[lttng-tools.git] / src / bin / lttng / conf.cpp
1 /*
2 * Copyright (C) 2011 EfficiOS Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include "conf.hpp"
10
11 #include <common/common.hpp>
12 #include <common/compat/errno.hpp>
13 #include <common/utils.hpp>
14
15 #include <limits.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 /*
24 * Returns the path with '/CONFIG_FILENAME' added to it;
25 * path will be NULL if an error occurs.
26 */
27 char *config_get_file_path(const char *path)
28 {
29 int ret;
30 char *file_path;
31
32 ret = asprintf(&file_path, "%s/%s", path, CONFIG_FILENAME);
33 if (ret < 0) {
34 ERR("Fail allocating config file path");
35 file_path = nullptr;
36 }
37
38 return file_path;
39 }
40
41 /*
42 * Returns an open FILE pointer to the config file;
43 * on error, NULL is returned.
44 */
45 static FILE *open_config(const char *path, const char *mode)
46 {
47 FILE *fp = nullptr;
48 char *file_path;
49
50 file_path = config_get_file_path(path);
51 if (file_path == nullptr) {
52 goto error;
53 }
54
55 fp = fopen(file_path, mode);
56 if (fp == nullptr) {
57 goto error;
58 }
59
60 error:
61 free(file_path);
62 return fp;
63 }
64
65 /*
66 * Creates the empty config file at the path.
67 * On success, returns 0;
68 * on error, returns -1.
69 */
70 static int create_config_file(const char *path)
71 {
72 int ret;
73 FILE *fp;
74
75 fp = open_config(path, "w+");
76 if (fp == nullptr) {
77 ERR("Unable to create config file");
78 ret = -1;
79 goto error;
80 }
81
82 ret = fclose(fp);
83
84 error:
85 return ret;
86 }
87
88 /*
89 * Append data to the config file in file_path
90 * On success, returns 0;
91 * on error, returns -1.
92 */
93 static int write_config(const char *file_path, size_t size, char *data)
94 {
95 FILE *fp;
96 size_t len;
97 int ret = 0;
98
99 fp = open_config(file_path, "a");
100 if (fp == nullptr) {
101 ret = -1;
102 goto end;
103 }
104
105 /* Write session name into config file */
106 len = fwrite(data, size, 1, fp);
107 if (len != 1) {
108 ret = -1;
109 }
110 if (fclose(fp)) {
111 PERROR("close write_config");
112 }
113 end:
114 return ret;
115 }
116
117 /*
118 * Destroys directory config and file config.
119 */
120 void config_destroy(const char *path)
121 {
122 int ret;
123 char *config_path;
124
125 config_path = config_get_file_path(path);
126 if (config_path == nullptr) {
127 return;
128 }
129
130 if (!config_exists(config_path)) {
131 goto end;
132 }
133
134 DBG("Removing %s\n", config_path);
135 ret = remove(config_path);
136 if (ret < 0) {
137 PERROR("remove config file");
138 }
139 end:
140 free(config_path);
141 }
142
143 /*
144 * Destroys the default config
145 */
146 void config_destroy_default()
147 {
148 const char *path = utils_get_home_dir();
149 if (path == nullptr) {
150 return;
151 }
152 config_destroy(path);
153 }
154
155 /*
156 * Returns 1 if config exists, 0 otherwise
157 */
158 int config_exists(const char *path)
159 {
160 int ret;
161 struct stat info;
162
163 ret = stat(path, &info);
164 if (ret < 0) {
165 return 0;
166 }
167 return S_ISREG(info.st_mode) || S_ISDIR(info.st_mode);
168 }
169
170 static int _config_read_session_name(const char *path, char **name)
171 {
172 int ret = 0;
173 FILE *fp;
174 char var[NAME_MAX], *session_name;
175
176 #if (NAME_MAX == 255)
177 #define NAME_MAX_SCANF_IS_A_BROKEN_API "254"
178 #endif
179
180 session_name = calloc<char>(NAME_MAX);
181 if (session_name == nullptr) {
182 ret = -ENOMEM;
183 ERR("Out of memory");
184 goto error;
185 }
186
187 fp = open_config(path, "r");
188 if (fp == nullptr) {
189 ret = -ENOENT;
190 goto error;
191 }
192
193 while (!feof(fp)) {
194 if ((ret = fscanf(fp,
195 "%" NAME_MAX_SCANF_IS_A_BROKEN_API
196 "[^'=']=%" NAME_MAX_SCANF_IS_A_BROKEN_API "s\n",
197 var,
198 session_name)) != 2) {
199 if (ret == -1) {
200 ERR("Missing session=NAME in config file.");
201 goto error_close;
202 }
203 continue;
204 }
205
206 if (strcmp(var, "session") == 0) {
207 goto found;
208 }
209 }
210
211 error_close:
212 if (fclose(fp) < 0) {
213 PERROR("close config read session name");
214 }
215 error:
216 free(session_name);
217 return ret;
218 found:
219 *name = session_name;
220 if (fclose(fp) < 0) {
221 PERROR("close config read session name found");
222 }
223 return ret;
224 }
225
226 /*
227 * Returns the session name from the config file.
228 *
229 * The caller is responsible for freeing the returned string.
230 * On error, NULL is returned.
231 */
232 char *config_read_session_name(const char *path)
233 {
234 int ret;
235 char *name = nullptr;
236
237 ret = _config_read_session_name(path, &name);
238 if (ret == -ENOENT) {
239 const char *home_dir = utils_get_home_dir();
240
241 ERR("Can't find valid lttng config %s/.lttngrc", home_dir);
242 MSG("Did you create a session? (lttng create <my_session>)");
243 }
244
245 return name;
246 }
247
248 /*
249 * Returns the session name from the config file. (no warnings/errors emitted)
250 *
251 * The caller is responsible for freeing the returned string.
252 * On error, NULL is returned.
253 */
254 char *config_read_session_name_quiet(const char *path)
255 {
256 char *name = nullptr;
257
258 (void) _config_read_session_name(path, &name);
259 return name;
260 }
261
262 /*
263 * Write session name option to the config file.
264 * On success, returns 0;
265 * on error, returns -1.
266 */
267 int config_add_session_name(const char *path, const char *name)
268 {
269 int ret;
270 const char *attr = "session=";
271 /* Max name len accepted plus attribute's len and the NULL byte. */
272 char session_name[NAME_MAX + strlen(attr) + 1];
273
274 /*
275 * With GNU C < 2.1, snprintf returns -1 if the target buffer is too small;
276 * With GNU C >= 2.1, snprintf returns the required size (excluding closing null)
277 */
278 ret = snprintf(session_name, sizeof(session_name), "%s%s\n", attr, name);
279 if (ret < 0) {
280 ret = -1;
281 goto error;
282 }
283 ret = write_config(path, ret, session_name);
284 error:
285 return ret;
286 }
287
288 /*
289 * Init configuration directory and file.
290 * On success, returns 0;
291 * on error, returns -1.
292 */
293 int config_init(const char *session_name)
294 {
295 int ret;
296 const char *path;
297
298 path = utils_get_home_dir();
299 if (path == nullptr) {
300 ret = -1;
301 goto error;
302 }
303
304 /* Create default config file */
305 ret = create_config_file(path);
306 if (ret < 0) {
307 goto error;
308 }
309
310 ret = config_add_session_name(path, session_name);
311 if (ret < 0) {
312 goto error;
313 }
314
315 DBG("Init config session in %s", path);
316
317 error:
318 return ret;
319 }
This page took 0.03715 seconds and 4 git commands to generate.