summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2013-12-13 04:35:44 +0100
committerGravatar Nikias Bassen2013-12-13 04:35:44 +0100
commitc168c3c7746e51fef4ec748a3982553833bb0c4e (patch)
tree927567acde881f84bdd3b40caf7dd095952423ad
parent3537f78a98111b88aab5e2d94dda340cf09be5af (diff)
downloadusbmuxd-c168c3c7746e51fef4ec748a3982553833bb0c4e.tar.gz
usbmuxd-c168c3c7746e51fef4ec748a3982553833bb0c4e.tar.bz2
add support for reading and writing config and pair record files
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am1
-rw-r--r--src/conf.c499
-rw-r--r--src/conf.h40
-rw-r--r--src/main.c7
-rw-r--r--src/preflight.c11
-rw-r--r--src/utils.c144
-rw-r--r--src/utils.h17
8 files changed, 709 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 9e113d7..6737f6f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -57,7 +57,7 @@ AC_TYPE_UINT8_T
57# Checks for library functions. 57# Checks for library functions.
58AC_FUNC_MALLOC 58AC_FUNC_MALLOC
59AC_FUNC_REALLOC 59AC_FUNC_REALLOC
60AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) 60AC_CHECK_FUNCS([strcasecmp strdup strerror strndup stpcpy])
61 61
62# Check for operating system 62# Check for operating system
63AC_MSG_CHECKING([whether to enable WIN32 build settings]) 63AC_MSG_CHECKING([whether to enable WIN32 build settings])
diff --git a/src/Makefile.am b/src/Makefile.am
index 883f1d8..38858c4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,7 @@ usbmuxd_SOURCES = client.c client.h \
9 log.c log.h \ 9 log.c log.h \
10 usb-linux.c usb.h \ 10 usb-linux.c usb.h \
11 utils.c utils.h \ 11 utils.c utils.h \
12 conf.c conf.h \
12 main.c 13 main.c
13usbmuxd_CFLAGS = $(AM_CFLAGS) 14usbmuxd_CFLAGS = $(AM_CFLAGS)
14usbmuxd_LDFLAGS = $(AM_LDFLAGS) 15usbmuxd_LDFLAGS = $(AM_LDFLAGS)
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..780a7c4
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,499 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#ifdef HAVE_SYS_TYPES_H
31#include <sys/types.h>
32#endif
33
34#include <dirent.h>
35#include <libgen.h>
36#include <sys/stat.h>
37#include <errno.h>
38
39#ifdef WIN32
40#include <shlobj.h>
41#endif
42
43#include "conf.h"
44#include "utils.h"
45#include "log.h"
46
47#ifdef WIN32
48#define DIR_SEP '\\'
49#define DIR_SEP_S "\\"
50#else
51#define DIR_SEP '/'
52#define DIR_SEP_S "/"
53#endif
54
55#define CONFIG_SYSTEM_BUID_KEY "SystemBUID"
56#define CONFIG_HOST_ID_KEY "HostID"
57
58#define CONFIG_EXT ".plist"
59
60#ifdef WIN32
61#define CONFIG_DIR "Apple"DIR_SEP_S"Lockdown"
62#else
63#define CONFIG_DIR "lockdown"
64#endif
65
66#define CONFIG_FILE "SystemConfiguration"CONFIG_EXT
67
68static char *__config_dir = NULL;
69
70#ifdef WIN32
71static char *config_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)
72{
73 if (!unistr || (len <= 0)) return NULL;
74 char *outbuf = (char*)malloc(3*(len+1));
75 int p = 0;
76 int i = 0;
77
78 wchar_t wc;
79
80 while (i < len) {
81 wc = unistr[i++];
82 if (wc >= 0x800) {
83 outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF));
84 outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F));
85 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
86 } else if (wc >= 0x80) {
87 outbuf[p++] = (char)(0xC0 + ((wc >> 6) & 0x1F));
88 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
89 } else {
90 outbuf[p++] = (char)(wc & 0x7F);
91 }
92 }
93 if (items_read) {
94 *items_read = i;
95 }
96 if (items_written) {
97 *items_written = p;
98 }
99 outbuf[p] = 0;
100
101 return outbuf;
102}
103#endif
104
105const char *config_get_config_dir()
106{
107 char *base_config_dir = NULL;
108
109 if (__config_dir)
110 return __config_dir;
111
112#ifdef WIN32
113 wchar_t path[MAX_PATH+1];
114 HRESULT hr;
115 LPITEMIDLIST pidl = NULL;
116 BOOL b = FALSE;
117
118 hr = SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_APPDATA, &pidl);
119 if (hr == S_OK) {
120 b = SHGetPathFromIDListW (pidl, path);
121 if (b) {
122 base_config_dir = config_utf16_to_utf8 (path, wcslen(path), NULL, NULL);
123 CoTaskMemFree (pidl);
124 }
125 }
126#else
127#ifdef __APPLE__
128 base_config_dir = strdup("/var/db");
129#else
130 base_config_dir = strdup("/var/lib");
131#endif
132#endif
133 __config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL);
134
135 if (__config_dir) {
136 int i = strlen(__config_dir)-1;
137 while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
138 __config_dir[i--] = '\0';
139 }
140 }
141
142 free(base_config_dir);
143
144 usbmuxd_log(LL_DEBUG, "initialized config_dir to %s", __config_dir);
145
146 return __config_dir;
147}
148
149static int __mkdir(const char *dir, int mode)
150{
151#ifdef WIN32
152 return mkdir(dir);
153#else
154 return mkdir(dir, mode);
155#endif
156}
157
158static int mkdir_with_parents(const char *dir, int mode)
159{
160 if (!dir) return -1;
161 if (__mkdir(dir, mode) == 0) {
162 return 0;
163 } else {
164 if (errno == EEXIST) return 0;
165 }
166 int res;
167 char *parent = strdup(dir);
168 char* parentdir = dirname(parent);
169 if (parentdir) {
170 res = mkdir_with_parents(parentdir, mode);
171 } else {
172 res = -1;
173 }
174 free(parent);
175 return res;
176}
177
178/**
179 * Creates a freedesktop compatible configuration directory.
180 */
181static void config_create_config_dir(void)
182{
183 const char *config_path = config_get_config_dir();
184 struct stat st;
185 if (stat(config_path, &st) != 0) {
186 mkdir_with_parents(config_path, 0755);
187 }
188}
189
190static int get_rand(int min, int max)
191{
192 int retval = (rand() % (max - min)) + min;
193 return retval;
194}
195
196static char *config_generate_uuid(int idx)
197{
198 char *uuid = (char *) malloc(sizeof(char) * 37);
199 const char *chars = "ABCDEF0123456789";
200 srand(time(NULL) - idx);
201 int i = 0;
202
203 for (i = 0; i < 36; i++) {
204 if (i == 8 || i == 13 || i == 18 || i == 23) {
205 uuid[i] = '-';
206 continue;
207 } else {
208 uuid[i] = chars[get_rand(0, 16)];
209 }
210 }
211 /* make it a real string */
212 uuid[36] = '\0';
213 return uuid;
214}
215
216/**
217 * Generates a valid BUID for this system (which is actually a UUID).
218 *
219 * @return A null terminated string containing a valid BUID.
220 */
221static char *config_generate_system_buid()
222{
223 return config_generate_uuid(1);
224}
225
226static int internal_set_value(const char *config_file, const char *key, plist_t value)
227{
228 if (!config_file)
229 return 0;
230
231 /* read file into plist */
232 plist_t config = NULL;
233
234 plist_read_from_filename(&config, config_file);
235 if (!config) {
236 config = plist_new_dict();
237 plist_dict_insert_item(config, key, value);
238 } else {
239 plist_t n = plist_dict_get_item(config, key);
240 if (n) {
241 plist_dict_remove_item(config, key);
242 }
243 plist_dict_insert_item(config, key, value);
244 remove(config_file);
245 }
246
247 /* store in config file */
248 char *value_string = NULL;
249 if (plist_get_node_type(value) == PLIST_STRING) {
250 plist_get_string_val(value, &value_string);
251 usbmuxd_log(LL_DEBUG, "setting key %s to %s in config_file %s", key, value_string, config_file);
252 if (value_string)
253 free(value_string);
254 } else {
255 usbmuxd_log(LL_DEBUG, "setting key %s in config_file %s", key, config_file);
256 }
257
258 plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
259
260 plist_free(config);
261
262 return 1;
263}
264
265static int config_set_value(const char *key, plist_t value)
266{
267 const char *config_path = NULL;
268 char *config_file = NULL;
269
270 /* Make sure config directory exists */
271 config_create_config_dir();
272
273 config_path = config_get_config_dir();
274 config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL);
275
276 int result = internal_set_value(config_file, key, value);
277
278 free(config_file);
279
280 return result;
281}
282
283static int internal_get_value(const char* config_file, const char *key, plist_t *value)
284{
285 *value = NULL;
286
287 /* now parse file to get the SystemBUID */
288 plist_t config = NULL;
289 if (plist_read_from_filename(&config, config_file)) {
290 usbmuxd_log(LL_DEBUG, "reading key %s from config_file %s", key, config_file);
291 plist_t n = plist_dict_get_item(config, key);
292 if (n) {
293 *value = plist_copy(n);
294 plist_free(n);
295 n = NULL;
296 }
297 }
298 plist_free(config);
299
300 return 1;
301}
302
303static int config_get_value(const char *key, plist_t *value)
304{
305 const char *config_path = NULL;
306 char *config_file = NULL;
307
308 config_path = config_get_config_dir();
309 config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL);
310
311 int result = internal_get_value(config_file, key, value);
312
313 free(config_file);
314
315 return result;
316}
317
318/**
319 * Store SystemBUID in config file.
320 *
321 * @param system_buid A null terminated string containing a valid SystemBUID.
322 */
323static int config_set_system_buid(const char *system_buid)
324{
325 return config_set_value(CONFIG_SYSTEM_BUID_KEY, plist_new_string(system_buid));
326}
327
328/**
329 * Reads the BUID from a previously generated configuration file.
330 *
331 * @param system_buid pointer to a variable that will be set to point to a
332 * newly allocated string containing the BUID.
333 *
334 * @note It is the responsibility of the calling function to free the returned system_buid
335 */
336void config_get_system_buid(char **system_buid)
337{
338 plist_t value = NULL;
339
340 config_get_value(CONFIG_SYSTEM_BUID_KEY, &value);
341
342 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
343 plist_get_string_val(value, system_buid);
344 usbmuxd_log(LL_DEBUG, "got %s %s", CONFIG_SYSTEM_BUID_KEY, *system_buid);
345 }
346
347 if (value)
348 plist_free(value);
349
350 if (!*system_buid) {
351 /* no config, generate system_buid */
352 usbmuxd_log(LL_DEBUG, "no previous %s found", CONFIG_SYSTEM_BUID_KEY);
353 *system_buid = config_generate_system_buid();
354 config_set_system_buid(*system_buid);
355 }
356
357 usbmuxd_log(LL_DEBUG, "using %s as %s", *system_buid, CONFIG_SYSTEM_BUID_KEY);
358}
359
360/**
361 * Store a pairing record for the given device identifier.
362 *
363 * @param udid device identifier
364 * @param record_data buffer containing a pairing record
365 * @param record_size size of buffer passed in record_data
366 *
367 * @return 0 on success or a negative errno otherwise.
368 */
369int config_set_device_record(const char *udid, char* record_data, uint64_t record_size)
370{
371 int res = 0;
372
373 if (!udid || record_data || record_size < 8)
374 return -EINVAL;
375
376 plist_t plist = NULL;
377 if (memcmp(record_data, "bplist00", 8) == 0) {
378 plist_from_bin(record_data, record_size, &plist);
379 } else {
380 plist_from_xml(record_data, record_size, &plist);
381 }
382
383 if (!plist || plist_get_node_type(plist) != PLIST_DICT) {
384 if (plist)
385 plist_free(plist);
386 return -EINVAL;
387 }
388
389 /* ensure config directory exists */
390 config_create_config_dir();
391
392 /* build file path */
393 const char *config_path = config_get_config_dir();
394 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
395
396 remove(device_record_file);
397
398 /* store file */
399 if (!plist_write_to_filename(plist, device_record_file, PLIST_FORMAT_XML)) {
400 usbmuxd_log(LL_DEBUG, "could not open '%s' for writing: %s", device_record_file, strerror(errno));
401 res = -ENOENT;
402 }
403 free(device_record_file);
404 if (plist)
405 plist_free(plist);
406
407 return res;
408}
409
410/**
411 * Retrieve a pairing record for the given device identifier
412 *
413 * @param udid device identifier
414 * @param record_data pointer to a variable that will be set to point to a
415 * newly allocated buffer holding the pairing record
416 * @param record_size pointer to a variable that will be set to the size
417 * of the buffer given in record_data.
418 *
419 * @return 0 on success or a negative errno otherwise.
420 */
421int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size)
422{
423 int res = 0;
424
425 /* ensure config directory exists */
426 config_create_config_dir();
427
428 /* build file path */
429 const char *config_path = config_get_config_dir();
430 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
431
432 /* read file */
433 buffer_read_from_filename(device_record_file, record_data, record_size); if (!*record_data) {
434 usbmuxd_log(LL_ERROR, "%s: failed to read '%s': %s", __func__, device_record_file, strerror(errno));
435 res = -ENOENT;
436 }
437 free(device_record_file);
438
439 return res;
440}
441
442/**
443 * Remove the pairing record stored for a device from this host.
444 *
445 * @param udid The udid of the device
446 *
447 * @return 0 on success or a negative errno otherwise.
448 */
449int config_remove_device_record(const char *udid)
450{
451 int res = 0;
452
453 /* build file path */
454 const char *config_path = config_get_config_dir();
455 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
456
457 /* remove file */
458 if (remove(device_record_file) != 0) {
459 res = -errno;
460 usbmuxd_log(LL_DEBUG, "could not remove %s: %s", device_record_file, strerror(errno));
461 }
462
463 free(device_record_file);
464
465 return res;
466}
467
468static int config_device_record_get_value(const char *udid, const char *key, plist_t *value)
469{
470 const char *config_path = NULL;
471 char *config_file = NULL;
472
473 config_path = config_get_config_dir();
474 config_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
475
476 int result = internal_get_value(config_file, key, value);
477
478 free(config_file);
479
480 return result;
481}
482
483void config_device_record_get_host_id(const char *udid, char **host_id)
484{
485 plist_t value = NULL;
486
487 config_device_record_get_value(udid, CONFIG_HOST_ID_KEY, &value);
488
489 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
490 plist_get_string_val(value, host_id);
491 }
492
493 if (value)
494 plist_free(value);
495
496 if (!*host_id) {
497 usbmuxd_log(LL_ERROR, "%s: ERROR couldn't get HostID from pairing record for udid %s\n", __func__, udid);
498 }
499}
diff --git a/src/conf.h b/src/conf.h
new file mode 100644
index 0000000..a104185
--- /dev/null
+++ b/src/conf.h
@@ -0,0 +1,40 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#ifndef __CONF_H__
22#define __CONF_H__
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <plist/plist.h>
29
30const char *config_get_config_dir();
31
32void config_get_system_buid(char **system_buid);
33
34int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size);
35int config_set_device_record(const char *udid, char* record_data, uint64_t record_size);
36int config_remove_device_record(const char *udid);
37
38void config_device_record_get_host_id(const char *udid, char **host_id);
39
40#endif
diff --git a/src/main.c b/src/main.c
index 15cb5a1..9e2db60 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,10 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
46#include "usb.h" 46#include "usb.h"
47#include "device.h" 47#include "device.h"
48#include "client.h" 48#include "client.h"
49 49#include "conf.h"
50#ifdef HAVE_LIBIMOBILEDEVICE
51extern const char* userpref_get_config_dir();
52#endif
53 50
54static const char *socket_path = "/var/run/usbmuxd"; 51static const char *socket_path = "/var/run/usbmuxd";
55static const char *lockfile = "/var/run/usbmuxd.pid"; 52static const char *lockfile = "/var/run/usbmuxd.pid";
@@ -534,7 +531,7 @@ int main(int argc, char *argv[])
534 goto terminate; 531 goto terminate;
535 532
536#ifdef HAVE_LIBIMOBILEDEVICE 533#ifdef HAVE_LIBIMOBILEDEVICE
537 const char* userprefdir = userpref_get_config_dir(); 534 const char* userprefdir = config_get_config_dir();
538 struct stat fst; 535 struct stat fst;
539 memset(&fst, '\0', sizeof(struct stat)); 536 memset(&fst, '\0', sizeof(struct stat));
540 if (stat(userprefdir, &fst) < 0) { 537 if (stat(userprefdir, &fst) < 0) {
diff --git a/src/preflight.c b/src/preflight.c
index def6a82..283c6d9 100644
--- a/src/preflight.c
+++ b/src/preflight.c
@@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 36
37#include "preflight.h" 37#include "preflight.h"
38#include "client.h" 38#include "client.h"
39#include "conf.h"
39#include "log.h" 40#include "log.h"
40 41
41#ifdef HAVE_LIBIMOBILEDEVICE 42#ifdef HAVE_LIBIMOBILEDEVICE
@@ -55,12 +56,10 @@ struct cb_data {
55 int is_device_connected; 56 int is_device_connected;
56}; 57};
57 58
58extern uint16_t userpref_remove_device_record(const char* udid);
59
60static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown) 59static void lockdownd_set_untrusted_host_buid(lockdownd_client_t lockdown)
61{ 60{
62 char* system_buid = NULL; 61 char* system_buid = NULL;
63 userpref_get_system_buid(&system_buid); 62 config_get_system_buid(&system_buid);
64 usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid); 63 usbmuxd_log(LL_DEBUG, "%s: Setting UntrustedHostBUID to %s", __func__, system_buid);
65 lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid)); 64 lockdownd_set_value(lockdown, NULL, "UntrustedHostBUID", plist_new_string(system_buid));
66 free(system_buid); 65 free(system_buid);
@@ -162,7 +161,7 @@ retry:
162 161
163 int is_device_paired = 0; 162 int is_device_paired = 0;
164 char *host_id = NULL; 163 char *host_id = NULL;
165 userpref_device_record_get_host_id(dev->udid, &host_id); 164 config_device_record_get_host_id(dev->udid, &host_id);
166 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); 165 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
167 free(host_id); 166 free(host_id);
168 if (lerr == LOCKDOWN_E_SUCCESS) { 167 if (lerr == LOCKDOWN_E_SUCCESS) {
@@ -179,7 +178,7 @@ retry:
179 break; 178 break;
180 case LOCKDOWN_E_SSL_ERROR: 179 case LOCKDOWN_E_SSL_ERROR:
181 usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid); 180 usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid);
182 if (userpref_remove_device_record(_dev->udid) == 0) { 181 if (config_remove_device_record(_dev->udid) == 0) {
183 lockdownd_client_free(lockdown); 182 lockdownd_client_free(lockdown);
184 lockdown = NULL; 183 lockdown = NULL;
185 goto retry; 184 goto retry;
@@ -293,7 +292,7 @@ retry:
293 } 292 }
294 293
295 host_id = NULL; 294 host_id = NULL;
296 userpref_device_record_get_host_id(dev->udid, &host_id); 295 config_device_record_get_host_id(dev->udid, &host_id);
297 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL); 296 lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
298 free(host_id); 297 free(host_id);
299 if (lerr != LOCKDOWN_E_SUCCESS) { 298 if (lerr != LOCKDOWN_E_SUCCESS) {
diff --git a/src/utils.c b/src/utils.c
index ceef535..475a921 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -3,6 +3,7 @@
3 3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com> 4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li> 5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (c) 2013 Federico Mena Quintero
6 7
7This library is free software; you can redistribute it and/or modify 8This library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as 9it under the terms of the GNU Lesser General Public License as
@@ -27,6 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27#include <stdlib.h> 28#include <stdlib.h>
28#include <string.h> 29#include <string.h>
29#include <stdio.h> 30#include <stdio.h>
31#include <stdarg.h>
32
30#include "utils.h" 33#include "utils.h"
31 34
32#include "log.h" 35#include "log.h"
@@ -118,3 +121,144 @@ int collection_count(struct collection *col)
118 } 121 }
119 return cnt; 122 return cnt;
120} 123}
124
125#ifndef HAVE_STPCPY
126/**
127 * Copy characters from one string into another
128 *
129 * @note: The strings should not overlap, as the behavior is undefined.
130 *
131 * @s1: The source string.
132 * @s2: The destination string.
133 *
134 * @return a pointer to the terminating `\0' character of @s1,
135 * or NULL if @s1 or @s2 is NULL.
136 */
137char *stpcpy(char * s1, const char * s2)
138{
139 if (s1 == NULL || s2 == NULL)
140 return NULL;
141
142 strcpy(s1, s2);
143
144 return s1 + strlen(s2);
145}
146#endif
147
148/**
149 * Concatenate strings into a newly allocated string
150 *
151 * @note: Specify NULL for the last string in the varargs list
152 *
153 * @str: The first string in the list
154 * @...: Subsequent strings. Use NULL for the last item.
155 *
156 * @return a newly allocated string, or NULL if @str is NULL. This will also
157 * return NULL and set errno to ENOMEM if memory is exhausted.
158 */
159char *string_concat(const char *str, ...)
160{
161 size_t len;
162 va_list args;
163 char *s;
164 char *result;
165 char *dest;
166
167 if (!str)
168 return NULL;
169
170 /* Compute final length */
171
172 len = strlen(str) + 1; /* plus 1 for the null terminator */
173
174 va_start(args, str);
175 s = va_arg(args, char *);
176 while (s) {
177 len += strlen(s);
178 s = va_arg(args, char*);
179 }
180 va_end(args);
181
182 /* Concat each string */
183
184 result = malloc(len);
185 if (!result)
186 return NULL; /* errno remains set */
187
188 dest = result;
189
190 dest = stpcpy(dest, str);
191
192 va_start(args, str);
193 s = va_arg(args, char *);
194 while (s) {
195 dest = stpcpy(dest, s);
196 s = va_arg(args, char *);
197 }
198 va_end(args);
199
200 return result;
201}
202
203void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
204{
205 FILE *f;
206 uint64_t size;
207
208 *length = 0;
209
210 f = fopen(filename, "rb");
211 if (!f) {
212 return;
213 }
214
215 fseek(f, 0, SEEK_END);
216 size = ftell(f);
217 rewind(f);
218
219 if (size == 0) {
220 fclose(f);
221 return;
222 }
223
224 *buffer = (char*)malloc(sizeof(char)*(size+1));
225 if (fread(*buffer, sizeof(char), size, f) != size) {
226 usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s\n", __func__, (int)size, filename);
227 }
228 fclose(f);
229
230 *length = size;
231}
232
233void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
234{
235 FILE *f;
236
237 f = fopen(filename, "wb");
238 if (f) {
239 fwrite(buffer, sizeof(char), length, f);
240 fclose(f);
241 }
242}
243
244int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
245{
246 char *buffer = NULL;
247 uint32_t length;
248
249 if (!plist || !filename)
250 return 0;
251
252 if (format == PLIST_FORMAT_XML)
253 plist_to_xml(plist, &buffer, &length);
254 else if (format == PLIST_FORMAT_BINARY)
255 plist_to_bin(plist, &buffer, &length);
256 else
257 return 0;
258
259 buffer_write_to_filename(filename, buffer, length);
260
261 free(buffer);
262
263 return 1;
264}
diff --git a/src/utils.h b/src/utils.h
index 69a4259..730fbad 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24#define __UTILS_H__ 24#define __UTILS_H__
25 25
26#include <poll.h> 26#include <poll.h>
27#include <plist/plist.h>
27 28
28enum fdowner { 29enum fdowner {
29 FD_LISTEN, 30 FD_LISTEN,
@@ -69,4 +70,20 @@ void collection_free(struct collection *col);
69 } \ 70 } \
70 } while(0); 71 } while(0);
71 72
73#ifndef HAVE_STPCPY
74char *stpcpy(char * s1, const char * s2);
75#endif
76char *string_concat(const char *str, ...);
77
78void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
79void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
80
81enum plist_format_t {
82 PLIST_FORMAT_XML,
83 PLIST_FORMAT_BINARY
84};
85
86int plist_read_from_filename(plist_t *plist, const char *filename);
87int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
88
72#endif 89#endif