1 /*
2 Copyright (C) 2006 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this manual. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <fnmatch.h>
26
27 #include "attr/libattr.h"
28 #define ERROR_CONTEXT_MACROS
29 #include "error_context.h"
30
31 #define ATTR_CONF SYSCONFDIR "/xattr.conf"
32
33 struct attr_action {
34 struct attr_action *next;
35 char *pattern;
36 int action;
37 };
38
39 static struct attr_action *attr_actions;
40
41 static void
42 free_attr_actions(void)
43 {
44 struct attr_action *tmp;
45
46 while (attr_actions) {
47 tmp = attr_actions->next;
48 free(attr_actions->pattern);
49 free(attr_actions);
50 attr_actions = tmp;
51 }
52 }
53
54 static int
55 attr_parse_attr_conf(struct error_context *ctx)
56 {
57 char *text = NULL, *t;
58 size_t size_guess = 4096, len;
59 FILE *file;
60 char *pattern = NULL;
61 struct attr_action *new;
62 int action;
63
64 if (attr_actions)
65 return 0;
66
67 repeat:
68 if ((file = fopen(ATTR_CONF, "r")) == NULL) {
69 if (errno == ENOENT)
70 return 0;
71 goto fail;
72 }
73
74 text = malloc(size_guess + 1);
75 if (!text)
76 goto fail;
77
78 len = fread(text, 1, size_guess, file);
79 if (ferror(file))
80 goto fail;
81 if (!feof(file)) {
82 fclose(file);
83 file = NULL;
84 free(text);
85 text = NULL;
86 size_guess *= 2;
87 goto repeat;
88 }
89 fclose(file);
90 file = NULL;
91
92 text[len] = 0;
93 t = text;
94 for (;;) {
95 t += strspn(t, " \t\n");
96 len = strcspn(t, " \t\n#");
97 if (t[len] == '#') {
98 if (len)
99 goto parse_error;
100 t += strcspn(t, "\n");
101 continue;
102 } else if (t[len] == 0)
103 break;
104 else if (t[len] == '\n')
105 goto parse_error;
106 pattern = strndup(t, len);
107 if (!pattern)
108 goto fail;
109 t += len;
110
111 t += strspn(t, " \t");
112 len = strcspn(t, " \t\n#");
113 if (len == 4 && !strncmp(t, "skip", 4))
114 action = ATTR_ACTION_SKIP;
115 else if (len == 11 && !strncmp(t, "permissions", 11))
116 action = ATTR_ACTION_PERMISSIONS;
117 else
118 goto parse_error;
119 t += len;
120 t += strspn(t, " \t");
121 if (*t != '#' && *t != '\n')
122 goto parse_error;
123
124 new = malloc(sizeof(struct attr_action));
125 if (!new)
126 goto parse_error;
127 new->next = attr_actions;
128 new->pattern = pattern;
129 new->action = action;
130 attr_actions = new;
131
132 t += strcspn(t, "\n");
133 }
134 free(text);
135 return 0;
136
137 parse_error:
138 errno = EINVAL;
139
140 fail:
141 {
142 const char *q = quote (ctx, ATTR_CONF);
143 error (ctx, "%s", q);
144 quote_free (ctx, q);
145 }
146
147 free(pattern);
148 if (file)
149 fclose(file);
150 free(text);
151 free_attr_actions();
152 return -1;
153 }
154
155 int
156 attr_copy_action(const char *name, struct error_context *ctx)
157 {
158 struct attr_action *action = attr_actions;
159
160 if (!attr_parse_attr_conf(ctx)) {
161 for (action = attr_actions; action; action = action->next) {
162 if (!fnmatch(action->pattern, name, 0))
163 return action->action;
164 }
165 }
166 return 0;
167 }