1 |
/* |
2 |
* sysfs_dir.c |
3 |
* |
4 |
* Directory utility functions for libsysfs |
5 |
* |
6 |
* Copyright (C) IBM Corp. 2003-2005 |
7 |
* |
8 |
* This library is free software; you can redistribute it and/or |
9 |
* modify it under the terms of the GNU Lesser General Public |
10 |
* License as published by the Free Software Foundation; either |
11 |
* version 2.1 of the License, or (at your option) any later version. |
12 |
* |
13 |
* This library is distributed in the hope that it will be useful, |
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 |
* Lesser General Public License for more details. |
17 |
* |
18 |
* You should have received a copy of the GNU Lesser General Public |
19 |
* License along with this library; if not, write to the Free Software |
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 |
* |
22 |
*/ |
23 |
#include "libsysfs.h" |
24 |
#include "sysfs.h" |
25 |
|
26 |
/** |
27 |
* sysfs_close_attribute: closes and cleans up attribute |
28 |
* @sysattr: attribute to close. |
29 |
*/ |
30 |
void sysfs_close_attribute(struct sysfs_attribute *sysattr) |
31 |
{ |
32 |
if (sysattr) { |
33 |
if (sysattr->value) |
34 |
free(sysattr->value); |
35 |
free(sysattr); |
36 |
} |
37 |
} |
38 |
|
39 |
/** |
40 |
* alloc_attribute: allocates and initializes attribute structure |
41 |
* returns struct sysfs_attribute with success and NULL with error. |
42 |
*/ |
43 |
static struct sysfs_attribute *alloc_attribute(void) |
44 |
{ |
45 |
return (struct sysfs_attribute *) |
46 |
calloc(1, sizeof(struct sysfs_attribute)); |
47 |
} |
48 |
|
49 |
/** |
50 |
* sysfs_open_attribute: creates sysfs_attribute structure |
51 |
* @path: path to attribute. |
52 |
* returns sysfs_attribute struct with success and NULL with error. |
53 |
*/ |
54 |
struct sysfs_attribute *sysfs_open_attribute(const char *path) |
55 |
{ |
56 |
struct sysfs_attribute *sysattr = NULL; |
57 |
struct stat fileinfo; |
58 |
|
59 |
if (!path) { |
60 |
errno = EINVAL; |
61 |
return NULL; |
62 |
} |
63 |
sysattr = alloc_attribute(); |
64 |
if (!sysattr) { |
65 |
dprintf("Error allocating attribute at %s\n", path); |
66 |
return NULL; |
67 |
} |
68 |
if (sysfs_get_name_from_path(path, sysattr->name, |
69 |
SYSFS_NAME_LEN) != 0) { |
70 |
dprintf("Error retrieving attrib name from path: %s\n", path); |
71 |
sysfs_close_attribute(sysattr); |
72 |
return NULL; |
73 |
} |
74 |
safestrcpy(sysattr->path, path); |
75 |
if ((stat(sysattr->path, &fileinfo)) != 0) { |
76 |
dprintf("Stat failed: No such attribute?\n"); |
77 |
sysattr->method = 0; |
78 |
free(sysattr); |
79 |
sysattr = NULL; |
80 |
} else { |
81 |
if (fileinfo.st_mode & S_IRUSR) |
82 |
sysattr->method |= SYSFS_METHOD_SHOW; |
83 |
if (fileinfo.st_mode & S_IWUSR) |
84 |
sysattr->method |= SYSFS_METHOD_STORE; |
85 |
} |
86 |
|
87 |
return sysattr; |
88 |
} |
89 |
|
90 |
/** |
91 |
* sysfs_read_attribute: reads value from attribute |
92 |
* @sysattr: attribute to read |
93 |
* returns 0 with success and -1 with error. |
94 |
*/ |
95 |
int sysfs_read_attribute(struct sysfs_attribute *sysattr) |
96 |
{ |
97 |
char *fbuf = NULL; |
98 |
char *vbuf = NULL; |
99 |
ssize_t length = 0; |
100 |
long pgsize = 0; |
101 |
int fd; |
102 |
|
103 |
if (!sysattr) { |
104 |
errno = EINVAL; |
105 |
return -1; |
106 |
} |
107 |
if (!(sysattr->method & SYSFS_METHOD_SHOW)) { |
108 |
dprintf("Show method not supported for attribute %s\n", |
109 |
sysattr->path); |
110 |
errno = EACCES; |
111 |
return -1; |
112 |
} |
113 |
pgsize = getpagesize(); |
114 |
fbuf = (char *)calloc(1, pgsize+1); |
115 |
if (!fbuf) { |
116 |
dprintf("calloc failed\n"); |
117 |
return -1; |
118 |
} |
119 |
if ((fd = open(sysattr->path, O_RDONLY)) < 0) { |
120 |
dprintf("Error reading attribute %s\n", sysattr->path); |
121 |
free(fbuf); |
122 |
return -1; |
123 |
} |
124 |
length = read(fd, fbuf, pgsize); |
125 |
if (length < 0) { |
126 |
dprintf("Error reading from attribute %s\n", sysattr->path); |
127 |
close(fd); |
128 |
free(fbuf); |
129 |
return -1; |
130 |
} |
131 |
if (sysattr->len > 0) { |
132 |
if ((sysattr->len == length) && |
133 |
(!(strncmp(sysattr->value, fbuf, length)))) { |
134 |
close(fd); |
135 |
free(fbuf); |
136 |
return 0; |
137 |
} |
138 |
free(sysattr->value); |
139 |
} |
140 |
sysattr->len = length; |
141 |
close(fd); |
142 |
vbuf = (char *)realloc(fbuf, length+1); |
143 |
if (!vbuf) { |
144 |
dprintf("realloc failed\n"); |
145 |
free(fbuf); |
146 |
return -1; |
147 |
} |
148 |
sysattr->value = vbuf; |
149 |
|
150 |
return 0; |
151 |
} |
152 |
|
153 |
/** |
154 |
* sysfs_write_attribute: write value to the attribute |
155 |
* @sysattr: attribute to write |
156 |
* @new_value: value to write |
157 |
* @len: length of "new_value" |
158 |
* returns 0 with success and -1 with error. |
159 |
*/ |
160 |
int sysfs_write_attribute(struct sysfs_attribute *sysattr, |
161 |
const char *new_value, size_t len) |
162 |
{ |
163 |
int fd; |
164 |
int length; |
165 |
|
166 |
if (!sysattr || !new_value || len == 0) { |
167 |
errno = EINVAL; |
168 |
return -1; |
169 |
} |
170 |
|
171 |
if (!(sysattr->method & SYSFS_METHOD_STORE)) { |
172 |
dprintf ("Store method not supported for attribute %s\n", |
173 |
sysattr->path); |
174 |
errno = EACCES; |
175 |
return -1; |
176 |
} |
177 |
if (sysattr->method & SYSFS_METHOD_SHOW) { |
178 |
/* |
179 |
* read attribute again to see if we can get an updated value |
180 |
*/ |
181 |
if ((sysfs_read_attribute(sysattr))) { |
182 |
dprintf("Error reading attribute\n"); |
183 |
return -1; |
184 |
} |
185 |
if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0 && |
186 |
(len == sysattr->len)) { |
187 |
dprintf("Attr %s already has the requested value %s\n", |
188 |
sysattr->name, new_value); |
189 |
return 0; |
190 |
} |
191 |
} |
192 |
/* |
193 |
* open O_WRONLY since some attributes have no "read" but only |
194 |
* "write" permission |
195 |
*/ |
196 |
if ((fd = open(sysattr->path, O_WRONLY)) < 0) { |
197 |
dprintf("Error reading attribute %s\n", sysattr->path); |
198 |
return -1; |
199 |
} |
200 |
|
201 |
length = write(fd, new_value, len); |
202 |
if (length < 0) { |
203 |
dprintf("Error writing to the attribute %s - invalid value?\n", |
204 |
sysattr->name); |
205 |
close(fd); |
206 |
return -1; |
207 |
} else if ((unsigned int)length != len) { |
208 |
dprintf("Could not write %zd bytes to attribute %s\n", |
209 |
len, sysattr->name); |
210 |
/* |
211 |
* since we could not write user supplied number of bytes, |
212 |
* restore the old value if one available |
213 |
*/ |
214 |
if (sysattr->method & SYSFS_METHOD_SHOW) { |
215 |
length = write(fd, sysattr->value, sysattr->len); |
216 |
close(fd); |
217 |
return -1; |
218 |
} |
219 |
} |
220 |
|
221 |
/* |
222 |
* Validate length that has been copied. Alloc appropriate area |
223 |
* in sysfs_attribute. Verify first if the attribute supports reading |
224 |
* (show method). If it does not, do not bother |
225 |
*/ |
226 |
if (sysattr->method & SYSFS_METHOD_SHOW) { |
227 |
if (length != sysattr->len) { |
228 |
sysattr->value = (char *)realloc |
229 |
(sysattr->value, length); |
230 |
sysattr->len = length; |
231 |
safestrcpymax(sysattr->value, new_value, length); |
232 |
} else { |
233 |
/*"length" of the new value is same as old one */ |
234 |
safestrcpymax(sysattr->value, new_value, length); |
235 |
} |
236 |
} |
237 |
|
238 |
close(fd); |
239 |
return 0; |
240 |
} |
241 |
|