Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Contains the set direction of the hosts plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "hosts.h"
11 :
12 : #ifndef HAVE_KDBCONFIG
13 : #include "kdbconfig.h"
14 : #endif
15 :
16 : #include <kdbextension.h>
17 : #include <kdbproposal.h>
18 :
19 64 : static int keyCmpOrderWrapper (const void * a, const void * b)
20 : {
21 64 : return elektraKeyCmpOrder (*((const Key **) a), *((const Key **) b));
22 : }
23 :
24 50 : static void writeComment (const char * spaces, const char * start, const char * comment, FILE * fp)
25 : {
26 50 : if (spaces)
27 : {
28 : char * endptr;
29 8 : long spaceValue = strtol (spaces, &endptr, 10);
30 :
31 8 : if (*endptr == '\0')
32 : {
33 16 : for (int i = 0; i < spaceValue; i++)
34 : {
35 16 : fprintf (fp, " ");
36 : }
37 : }
38 : }
39 :
40 50 : if (start)
41 : {
42 14 : fprintf (fp, "%s", start);
43 : }
44 :
45 50 : if (comment)
46 : {
47 33 : fprintf (fp, "%s", comment);
48 : }
49 50 : }
50 :
51 150 : static const char * getMetaValue (Key * key, const char * metaName)
52 : {
53 150 : const Key * metaKey = keyGetMeta (key, metaName);
54 :
55 150 : if (metaKey) return keyString (metaKey);
56 :
57 : return 0;
58 : }
59 :
60 54 : static void writeLineComments (Key * key, FILE * fp)
61 : {
62 : // TODO: this is really inefficient
63 54 : KeySet * metaKeys = elektraKeyGetMetaKeySet (key);
64 54 : Key * commentParent = keyNew ("comment", KEY_META_NAME, KEY_END);
65 54 : KeySet * comments = elektraArrayGet (commentParent, metaKeys);
66 54 : keyDel (commentParent);
67 :
68 54 : ksRewind (comments);
69 : Key * current;
70 141 : while ((current = ksNext (comments)))
71 : {
72 33 : if (strcmp (keyName (current), "comment/#0"))
73 : {
74 20 : Key * spaceKey = keyDup (current);
75 20 : keyAddBaseName (spaceKey, "space");
76 20 : Key * startKey = keyDup (current);
77 20 : keyAddBaseName (startKey, "start");
78 20 : const char * spaces = getMetaValue (key, keyName (spaceKey));
79 20 : const char * start = getMetaValue (key, keyName (startKey));
80 20 : const char * comment = getMetaValue (key, keyName (current));
81 20 : keyDel (spaceKey);
82 20 : keyDel (startKey);
83 20 : writeComment (spaces, start, comment, fp);
84 20 : fprintf (fp, "\n");
85 : }
86 : }
87 :
88 54 : ksDel (metaKeys);
89 54 : ksDel (comments);
90 54 : }
91 :
92 30 : static void writeInlineComment (Key * key, FILE * fp)
93 : {
94 :
95 30 : const char * spaces = getMetaValue (key, "comment/#0/space");
96 30 : const char * start = getMetaValue (key, "comment/#0/start");
97 30 : const char * comment = getMetaValue (key, "comment/#0");
98 :
99 30 : writeComment (spaces, start, comment, fp);
100 30 : }
101 :
102 30 : static void writeHostsEntry (Key * key, KeySet * returned, FILE * fp)
103 : {
104 30 : fprintf (fp, "%s\t%s", (char *) keyValue (key), (char *) keyBaseName (key));
105 : /* position the cursor at the current key and
106 : * iterate over its subkeys
107 : */
108 30 : ksLookup (returned, key, KDB_O_NONE);
109 : Key * alias;
110 70 : while ((alias = ksNext (returned)) != 0)
111 : {
112 24 : if (keyRel (key, alias) < 1) break;
113 :
114 10 : fprintf (fp, " %s", (char *) keyBaseName (alias));
115 : }
116 30 : }
117 :
118 24 : int elektraHostsSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
119 : {
120 24 : int errnosave = errno;
121 : FILE * fp;
122 :
123 24 : fp = fopen (keyString (parentKey), "w");
124 :
125 24 : if (fp == 0)
126 : {
127 0 : ELEKTRA_SET_ERROR_SET (parentKey);
128 0 : errno = errnosave;
129 0 : return -1;
130 : }
131 :
132 : /* build an array of entries and sort them according to their order metadata */
133 : Key ** keyArray;
134 24 : size_t arraySize = ksGetSize (returned);
135 24 : keyArray = calloc (arraySize, sizeof (Key *));
136 :
137 24 : ksRewind (returned);
138 24 : int ret = elektraKsToMemArray (returned, keyArray);
139 :
140 24 : if (ret < 0)
141 : {
142 0 : ELEKTRA_SET_RESOURCE_ERROR (parentKey, strerror (errno));
143 0 : fclose (fp);
144 0 : return -1;
145 : }
146 :
147 24 : qsort (keyArray, arraySize, sizeof (Key *), keyCmpOrderWrapper);
148 :
149 24 : Key * ipv4Base = keyDup (parentKey);
150 24 : keyAddBaseName (ipv4Base, "ipv4");
151 24 : Key * ipv6Base = keyDup (parentKey);
152 24 : keyAddBaseName (ipv6Base, "ipv6");
153 :
154 : /* now write the hosts file */
155 86 : for (size_t i = 0; i < arraySize; ++i)
156 : {
157 62 : Key * key = keyArray[i];
158 :
159 : /* only process canonical name keys */
160 62 : if (!keyIsDirectBelow (ipv4Base, key) && !keyIsDirectBelow (ipv6Base, key)) continue;
161 :
162 30 : writeLineComments (key, fp);
163 30 : writeHostsEntry (key, returned, fp);
164 30 : writeInlineComment (key, fp);
165 30 : fprintf (fp, "\n");
166 : }
167 :
168 24 : writeLineComments (parentKey, fp);
169 :
170 24 : keyDel (ipv4Base);
171 24 : keyDel (ipv6Base);
172 :
173 24 : fclose (fp);
174 24 : errno = errnosave;
175 24 : elektraFree (keyArray);
176 24 : return 1;
177 : }
|