Branch data Line data Source code
1 : : /*
2 : : * fs/sysfs/symlink.c - sysfs symlink implementation
3 : : *
4 : : * Copyright (c) 2001-3 Patrick Mochel
5 : : * Copyright (c) 2007 SUSE Linux Products GmbH
6 : : * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
7 : : *
8 : : * This file is released under the GPLv2.
9 : : *
10 : : * Please see Documentation/filesystems/sysfs.txt for more information.
11 : : */
12 : :
13 : : #include <linux/fs.h>
14 : : #include <linux/gfp.h>
15 : : #include <linux/mount.h>
16 : : #include <linux/module.h>
17 : : #include <linux/kobject.h>
18 : : #include <linux/namei.h>
19 : : #include <linux/mutex.h>
20 : : #include <linux/security.h>
21 : :
22 : : #include "sysfs.h"
23 : :
24 : 0 : static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
25 : : struct kobject *target,
26 : : const char *name, int warn)
27 : : {
28 : : struct sysfs_dirent *target_sd = NULL;
29 : : struct sysfs_dirent *sd = NULL;
30 : : struct sysfs_addrm_cxt acxt;
31 : : enum kobj_ns_type ns_type;
32 : : int error;
33 : :
34 [ - + ]: 674 : BUG_ON(!name || !parent_sd);
35 : :
36 : : /*
37 : : * We don't own @target and it may be removed at any time.
38 : : * Synchronize using sysfs_symlink_target_lock. See
39 : : * sysfs_remove_dir() for details.
40 : : */
41 : : spin_lock(&sysfs_symlink_target_lock);
42 [ + - ]: 674 : if (target->sd)
43 : : target_sd = sysfs_get(target->sd);
44 : : spin_unlock(&sysfs_symlink_target_lock);
45 : :
46 : : error = -ENOENT;
47 [ + - ]: 674 : if (!target_sd)
48 : : goto out_put;
49 : :
50 : : error = -ENOMEM;
51 : 674 : sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
52 [ + - ]: 674 : if (!sd)
53 : : goto out_put;
54 : :
55 : : ns_type = sysfs_ns_type(parent_sd);
56 [ - + ]: 674 : if (ns_type)
57 : 0 : sd->s_ns = target_sd->s_ns;
58 : 674 : sd->s_symlink.target_sd = target_sd;
59 : : target_sd = NULL; /* reference is now owned by the symlink */
60 : :
61 : 674 : sysfs_addrm_start(&acxt);
62 : : /* Symlinks must be between directories with the same ns_type */
63 [ - + ][ # # ]: 674 : if (!ns_type ||
64 : 0 : (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) {
65 [ + - ]: 674 : if (warn)
66 : 674 : error = sysfs_add_one(&acxt, sd, parent_sd);
67 : : else
68 : 0 : error = __sysfs_add_one(&acxt, sd, parent_sd);
69 : : } else {
70 : : error = -EINVAL;
71 : 0 : WARN(1, KERN_WARNING
72 : : "sysfs: symlink across ns_types %s/%s -> %s/%s\n",
73 : : parent_sd->s_name,
74 : : sd->s_name,
75 : : sd->s_symlink.target_sd->s_parent->s_name,
76 : : sd->s_symlink.target_sd->s_name);
77 : : }
78 : 674 : sysfs_addrm_finish(&acxt);
79 : :
80 [ + - ]: 674 : if (error)
81 : : goto out_put;
82 : :
83 : : return 0;
84 : :
85 : : out_put:
86 : : sysfs_put(target_sd);
87 : : sysfs_put(sd);
88 : : return error;
89 : : }
90 : :
91 : : /**
92 : : * sysfs_create_link_sd - create symlink to a given object.
93 : : * @sd: directory we're creating the link in.
94 : : * @target: object we're pointing to.
95 : : * @name: name of the symlink.
96 : : */
97 : 0 : int sysfs_create_link_sd(struct sysfs_dirent *sd, struct kobject *target,
98 : : const char *name)
99 : : {
100 : 0 : return sysfs_do_create_link_sd(sd, target, name, 1);
101 : : }
102 : :
103 : : static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
104 : : const char *name, int warn)
105 : : {
106 : : struct sysfs_dirent *parent_sd = NULL;
107 : :
108 [ # # ][ + - ]: 674 : if (!kobj)
109 : : parent_sd = &sysfs_root;
110 : : else
111 : 674 : parent_sd = kobj->sd;
112 : :
113 [ # # ][ + - ]: 674 : if (!parent_sd)
114 : : return -EFAULT;
115 : :
116 : 674 : return sysfs_do_create_link_sd(parent_sd, target, name, warn);
117 : : }
118 : :
119 : : /**
120 : : * sysfs_create_link - create symlink between two objects.
121 : : * @kobj: object whose directory we're creating the link in.
122 : : * @target: object we're pointing to.
123 : : * @name: name of the symlink.
124 : : */
125 : 0 : int sysfs_create_link(struct kobject *kobj, struct kobject *target,
126 : : const char *name)
127 : : {
128 : 0 : return sysfs_do_create_link(kobj, target, name, 1);
129 : : }
130 : : EXPORT_SYMBOL_GPL(sysfs_create_link);
131 : :
132 : : /**
133 : : * sysfs_create_link_nowarn - create symlink between two objects.
134 : : * @kobj: object whose directory we're creating the link in.
135 : : * @target: object we're pointing to.
136 : : * @name: name of the symlink.
137 : : *
138 : : * This function does the same as sysfs_create_link(), but it
139 : : * doesn't warn if the link already exists.
140 : : */
141 : 0 : int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
142 : : const char *name)
143 : : {
144 : 0 : return sysfs_do_create_link(kobj, target, name, 0);
145 : : }
146 : :
147 : : /**
148 : : * sysfs_delete_link - remove symlink in object's directory.
149 : : * @kobj: object we're acting for.
150 : : * @targ: object we're pointing to.
151 : : * @name: name of the symlink to remove.
152 : : *
153 : : * Unlike sysfs_remove_link sysfs_delete_link has enough information
154 : : * to successfully delete symlinks in tagged directories.
155 : : */
156 : 0 : void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
157 : : const char *name)
158 : : {
159 : : const void *ns = NULL;
160 : :
161 : : /*
162 : : * We don't own @target and it may be removed at any time.
163 : : * Synchronize using sysfs_symlink_target_lock. See
164 : : * sysfs_remove_dir() for details.
165 : : */
166 : : spin_lock(&sysfs_symlink_target_lock);
167 [ + - ][ - + ]: 39 : if (targ->sd && sysfs_ns_type(kobj->sd))
168 : 0 : ns = targ->sd->s_ns;
169 : : spin_unlock(&sysfs_symlink_target_lock);
170 : 39 : sysfs_hash_and_remove(kobj->sd, name, ns);
171 : 39 : }
172 : :
173 : : /**
174 : : * sysfs_remove_link - remove symlink in object's directory.
175 : : * @kobj: object we're acting for.
176 : : * @name: name of the symlink to remove.
177 : : */
178 : 0 : void sysfs_remove_link(struct kobject *kobj, const char *name)
179 : : {
180 : : struct sysfs_dirent *parent_sd = NULL;
181 : :
182 [ + - ]: 299 : if (!kobj)
183 : : parent_sd = &sysfs_root;
184 : : else
185 : 299 : parent_sd = kobj->sd;
186 : :
187 : 299 : sysfs_hash_and_remove(parent_sd, name, NULL);
188 : 299 : }
189 : : EXPORT_SYMBOL_GPL(sysfs_remove_link);
190 : :
191 : : /**
192 : : * sysfs_rename_link_ns - rename symlink in object's directory.
193 : : * @kobj: object we're acting for.
194 : : * @targ: object we're pointing to.
195 : : * @old: previous name of the symlink.
196 : : * @new: new name of the symlink.
197 : : * @new_ns: new namespace of the symlink.
198 : : *
199 : : * A helper function for the common rename symlink idiom.
200 : : */
201 : 0 : int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
202 : : const char *old, const char *new, const void *new_ns)
203 : : {
204 : 0 : struct sysfs_dirent *parent_sd, *sd = NULL;
205 : : const void *old_ns = NULL;
206 : : int result;
207 : :
208 [ # # ]: 0 : if (!kobj)
209 : : parent_sd = &sysfs_root;
210 : : else
211 : 0 : parent_sd = kobj->sd;
212 : :
213 [ # # ]: 0 : if (targ->sd)
214 : 0 : old_ns = targ->sd->s_ns;
215 : :
216 : : result = -ENOENT;
217 : 0 : sd = sysfs_get_dirent_ns(parent_sd, old, old_ns);
218 [ # # ]: 0 : if (!sd)
219 : : goto out;
220 : :
221 : : result = -EINVAL;
222 [ # # ]: 0 : if (sysfs_type(sd) != SYSFS_KOBJ_LINK)
223 : : goto out;
224 [ # # ]: 0 : if (sd->s_symlink.target_sd->s_dir.kobj != targ)
225 : : goto out;
226 : :
227 : 0 : result = sysfs_rename(sd, parent_sd, new, new_ns);
228 : :
229 : : out:
230 : : sysfs_put(sd);
231 : 0 : return result;
232 : : }
233 : : EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);
234 : :
235 : 0 : static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
236 : : struct sysfs_dirent *target_sd, char *path)
237 : : {
238 : : struct sysfs_dirent *base, *sd;
239 : : char *s = path;
240 : : int len = 0;
241 : :
242 : : /* go up to the root, stop at the base */
243 : : base = parent_sd;
244 [ + + ]: 5273 : while (base->s_parent) {
245 : 4512 : sd = target_sd->s_parent;
246 [ + + ][ + - ]: 12682 : while (sd->s_parent && base != sd)
247 : : sd = sd->s_parent;
248 : :
249 [ + - ]: 4512 : if (base == sd)
250 : : break;
251 : :
252 : 4512 : strcpy(s, "../");
253 : 4512 : s += 3;
254 : 4512 : base = base->s_parent;
255 : : }
256 : :
257 : : /* determine end of target string for reverse fillup */
258 : : sd = target_sd;
259 [ + + ][ + - ]: 2963 : while (sd->s_parent && sd != base) {
260 : 2202 : len += strlen(sd->s_name) + 1;
261 : : sd = sd->s_parent;
262 : : }
263 : :
264 : : /* check limits */
265 [ + - ]: 761 : if (len < 2)
266 : : return -EINVAL;
267 : 761 : len--;
268 [ + - ]: 761 : if ((s - path) + len > PATH_MAX)
269 : : return -ENAMETOOLONG;
270 : :
271 : : /* reverse fillup of target string from target to base */
272 : : sd = target_sd;
273 [ + - ][ + - ]: 2963 : while (sd->s_parent && sd != base) {
274 : 2202 : int slen = strlen(sd->s_name);
275 : :
276 : 2202 : len -= slen;
277 : 2202 : strncpy(s + len, sd->s_name, slen);
278 [ + + ]: 2202 : if (len)
279 : 1441 : s[--len] = '/';
280 : :
281 : 2202 : sd = sd->s_parent;
282 : : }
283 : :
284 : : return 0;
285 : : }
286 : :
287 : 761 : static int sysfs_getlink(struct dentry *dentry, char *path)
288 : : {
289 : 761 : struct sysfs_dirent *sd = dentry->d_fsdata;
290 : 761 : struct sysfs_dirent *parent_sd = sd->s_parent;
291 : 761 : struct sysfs_dirent *target_sd = sd->s_symlink.target_sd;
292 : : int error;
293 : :
294 : 761 : mutex_lock(&sysfs_mutex);
295 : 761 : error = sysfs_get_target_path(parent_sd, target_sd, path);
296 : 761 : mutex_unlock(&sysfs_mutex);
297 : :
298 : 761 : return error;
299 : : }
300 : :
301 : 0 : static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
302 : : {
303 : : int error = -ENOMEM;
304 : 761 : unsigned long page = get_zeroed_page(GFP_KERNEL);
305 [ + - ]: 761 : if (page) {
306 : 761 : error = sysfs_getlink(dentry, (char *) page);
307 [ - + ]: 761 : if (error < 0)
308 : 0 : free_page((unsigned long)page);
309 : : }
310 [ - + ]: 1522 : nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
311 : 761 : return NULL;
312 : : }
313 : :
314 : 0 : static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd,
315 : : void *cookie)
316 : : {
317 : : char *page = nd_get_link(nd);
318 [ + - ]: 761 : if (!IS_ERR(page))
319 : 761 : free_page((unsigned long)page);
320 : 0 : }
321 : :
322 : : const struct inode_operations sysfs_symlink_inode_operations = {
323 : : .setxattr = sysfs_setxattr,
324 : : .readlink = generic_readlink,
325 : : .follow_link = sysfs_follow_link,
326 : : .put_link = sysfs_put_link,
327 : : .setattr = sysfs_setattr,
328 : : .getattr = sysfs_getattr,
329 : : .permission = sysfs_permission,
330 : : };
|