diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/symlink.c | 88 |
1 files changed, 42 insertions, 46 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3eac20c63c41..5f66c4466151 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -19,39 +19,6 @@ | |||
19 | 19 | ||
20 | #include "sysfs.h" | 20 | #include "sysfs.h" |
21 | 21 | ||
22 | static int object_depth(struct sysfs_dirent *sd) | ||
23 | { | ||
24 | int depth = 0; | ||
25 | |||
26 | for (; sd->s_parent; sd = sd->s_parent) | ||
27 | depth++; | ||
28 | |||
29 | return depth; | ||
30 | } | ||
31 | |||
32 | static int object_path_length(struct sysfs_dirent * sd) | ||
33 | { | ||
34 | int length = 1; | ||
35 | |||
36 | for (; sd->s_parent; sd = sd->s_parent) | ||
37 | length += strlen(sd->s_name) + 1; | ||
38 | |||
39 | return length; | ||
40 | } | ||
41 | |||
42 | static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) | ||
43 | { | ||
44 | --length; | ||
45 | for (; sd->s_parent; sd = sd->s_parent) { | ||
46 | int cur = strlen(sd->s_name); | ||
47 | |||
48 | /* back up enough to print this bus id with '/' */ | ||
49 | length -= cur; | ||
50 | strncpy(buffer + length, sd->s_name, cur); | ||
51 | *(buffer + --length) = '/'; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | /** | 22 | /** |
56 | * sysfs_create_link - create symlink between two objects. | 23 | * sysfs_create_link - create symlink between two objects. |
57 | * @kobj: object whose directory we're creating the link in. | 24 | * @kobj: object whose directory we're creating the link in. |
@@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
112 | return error; | 79 | return error; |
113 | } | 80 | } |
114 | 81 | ||
115 | |||
116 | /** | 82 | /** |
117 | * sysfs_remove_link - remove symlink in object's directory. | 83 | * sysfs_remove_link - remove symlink in object's directory. |
118 | * @kobj: object we're acting for. | 84 | * @kobj: object we're acting for. |
@@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) | |||
124 | sysfs_hash_and_remove(kobj->sd, name); | 90 | sysfs_hash_and_remove(kobj->sd, name); |
125 | } | 91 | } |
126 | 92 | ||
127 | static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, | 93 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
128 | struct sysfs_dirent * target_sd, char *path) | 94 | struct sysfs_dirent *target_sd, char *path) |
129 | { | 95 | { |
130 | char * s; | 96 | struct sysfs_dirent *base, *sd; |
131 | int depth, size; | 97 | char *s = path; |
98 | int len = 0; | ||
99 | |||
100 | /* go up to the root, stop at the base */ | ||
101 | base = parent_sd; | ||
102 | while (base->s_parent) { | ||
103 | sd = target_sd->s_parent; | ||
104 | while (sd->s_parent && base != sd) | ||
105 | sd = sd->s_parent; | ||
106 | |||
107 | if (base == sd) | ||
108 | break; | ||
109 | |||
110 | strcpy(s, "../"); | ||
111 | s += 3; | ||
112 | base = base->s_parent; | ||
113 | } | ||
114 | |||
115 | /* determine end of target string for reverse fillup */ | ||
116 | sd = target_sd; | ||
117 | while (sd->s_parent && sd != base) { | ||
118 | len += strlen(sd->s_name) + 1; | ||
119 | sd = sd->s_parent; | ||
120 | } | ||
132 | 121 | ||
133 | depth = object_depth(parent_sd); | 122 | /* check limits */ |
134 | size = object_path_length(target_sd) + depth * 3 - 1; | 123 | if (len < 2) |
135 | if (size > PATH_MAX) | 124 | return -EINVAL; |
125 | len--; | ||
126 | if ((s - path) + len > PATH_MAX) | ||
136 | return -ENAMETOOLONG; | 127 | return -ENAMETOOLONG; |
137 | 128 | ||
138 | pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); | 129 | /* reverse fillup of target string from target to base */ |
130 | sd = target_sd; | ||
131 | while (sd->s_parent && sd != base) { | ||
132 | int slen = strlen(sd->s_name); | ||
139 | 133 | ||
140 | for (s = path; depth--; s += 3) | 134 | len -= slen; |
141 | strcpy(s,"../"); | 135 | strncpy(s + len, sd->s_name, slen); |
136 | if (len) | ||
137 | s[--len] = '/'; | ||
142 | 138 | ||
143 | fill_object_path(target_sd, path, size); | 139 | sd = sd->s_parent; |
144 | pr_debug("%s: path = '%s'\n", __FUNCTION__, path); | 140 | } |
145 | 141 | ||
146 | return 0; | 142 | return 0; |
147 | } | 143 | } |