Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * fs/sysfs/file.c - sysfs regular (text) file implementation
4 : *
5 : * Copyright (c) 2001-3 Patrick Mochel
6 : * Copyright (c) 2007 SUSE Linux Products GmbH
7 : * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
8 : *
9 : * Please see Documentation/filesystems/sysfs.rst for more information.
10 : */
11 :
12 : #include <linux/module.h>
13 : #include <linux/kobject.h>
14 : #include <linux/slab.h>
15 : #include <linux/list.h>
16 : #include <linux/mutex.h>
17 : #include <linux/seq_file.h>
18 : #include <linux/mm.h>
19 :
20 : #include "sysfs.h"
21 :
22 : /*
23 : * Determine ktype->sysfs_ops for the given kernfs_node. This function
24 : * must be called while holding an active reference.
25 : */
26 : static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
27 : {
28 0 : struct kobject *kobj = kn->parent->priv;
29 :
30 : if (kn->flags & KERNFS_LOCKDEP)
31 : lockdep_assert_held(kn);
32 0 : return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
33 : }
34 :
35 : /*
36 : * Reads on sysfs are handled through seq_file, which takes care of hairy
37 : * details like buffering and seeking. The following function pipes
38 : * sysfs_ops->show() result through seq_file.
39 : */
40 0 : static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
41 : {
42 0 : struct kernfs_open_file *of = sf->private;
43 0 : struct kobject *kobj = of->kn->parent->priv;
44 0 : const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
45 : ssize_t count;
46 : char *buf;
47 :
48 0 : if (WARN_ON_ONCE(!ops->show))
49 : return -EINVAL;
50 :
51 : /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
52 0 : count = seq_get_buf(sf, &buf);
53 0 : if (count < PAGE_SIZE) {
54 0 : seq_commit(sf, -1);
55 0 : return 0;
56 : }
57 0 : memset(buf, 0, PAGE_SIZE);
58 :
59 0 : count = ops->show(kobj, of->kn->priv, buf);
60 0 : if (count < 0)
61 0 : return count;
62 :
63 : /*
64 : * The code works fine with PAGE_SIZE return but it's likely to
65 : * indicate truncated result or overflow in normal use cases.
66 : */
67 0 : if (count >= (ssize_t)PAGE_SIZE) {
68 0 : printk("fill_read_buffer: %pS returned bad count\n",
69 : ops->show);
70 : /* Try to struggle along */
71 0 : count = PAGE_SIZE - 1;
72 : }
73 0 : seq_commit(sf, count);
74 0 : return 0;
75 : }
76 :
77 0 : static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
78 : size_t count, loff_t pos)
79 : {
80 0 : struct bin_attribute *battr = of->kn->priv;
81 0 : struct kobject *kobj = of->kn->parent->priv;
82 0 : loff_t size = file_inode(of->file)->i_size;
83 :
84 0 : if (!count)
85 : return 0;
86 :
87 0 : if (size) {
88 0 : if (pos >= size)
89 : return 0;
90 0 : if (pos + count > size)
91 0 : count = size - pos;
92 : }
93 :
94 0 : if (!battr->read)
95 : return -EIO;
96 :
97 0 : return battr->read(of->file, kobj, battr, buf, pos, count);
98 : }
99 :
100 : /* kernfs read callback for regular sysfs files with pre-alloc */
101 0 : static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
102 : size_t count, loff_t pos)
103 : {
104 0 : const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
105 0 : struct kobject *kobj = of->kn->parent->priv;
106 : ssize_t len;
107 :
108 : /*
109 : * If buf != of->prealloc_buf, we don't know how
110 : * large it is, so cannot safely pass it to ->show
111 : */
112 0 : if (WARN_ON_ONCE(buf != of->prealloc_buf))
113 : return 0;
114 0 : len = ops->show(kobj, of->kn->priv, buf);
115 0 : if (len < 0)
116 : return len;
117 0 : if (pos) {
118 0 : if (len <= pos)
119 : return 0;
120 0 : len -= pos;
121 0 : memmove(buf, buf + pos, len);
122 : }
123 0 : return min_t(ssize_t, count, len);
124 : }
125 :
126 : /* kernfs write callback for regular sysfs files */
127 0 : static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
128 : size_t count, loff_t pos)
129 : {
130 0 : const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
131 0 : struct kobject *kobj = of->kn->parent->priv;
132 :
133 0 : if (!count)
134 : return 0;
135 :
136 0 : return ops->store(kobj, of->kn->priv, buf, count);
137 : }
138 :
139 : /* kernfs write callback for bin sysfs files */
140 0 : static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
141 : size_t count, loff_t pos)
142 : {
143 0 : struct bin_attribute *battr = of->kn->priv;
144 0 : struct kobject *kobj = of->kn->parent->priv;
145 0 : loff_t size = file_inode(of->file)->i_size;
146 :
147 0 : if (size) {
148 0 : if (size <= pos)
149 : return -EFBIG;
150 0 : count = min_t(ssize_t, count, size - pos);
151 : }
152 0 : if (!count)
153 : return 0;
154 :
155 0 : if (!battr->write)
156 : return -EIO;
157 :
158 0 : return battr->write(of->file, kobj, battr, buf, pos, count);
159 : }
160 :
161 0 : static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
162 : struct vm_area_struct *vma)
163 : {
164 0 : struct bin_attribute *battr = of->kn->priv;
165 0 : struct kobject *kobj = of->kn->parent->priv;
166 :
167 0 : return battr->mmap(of->file, kobj, battr, vma);
168 : }
169 :
170 0 : static int sysfs_kf_bin_open(struct kernfs_open_file *of)
171 : {
172 0 : struct bin_attribute *battr = of->kn->priv;
173 :
174 0 : if (battr->f_mapping)
175 0 : of->file->f_mapping = battr->f_mapping();
176 :
177 0 : return 0;
178 : }
179 :
180 2 : void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
181 : {
182 2 : struct kernfs_node *kn = kobj->sd, *tmp;
183 :
184 2 : if (kn && dir)
185 0 : kn = kernfs_find_and_get(kn, dir);
186 : else
187 2 : kernfs_get(kn);
188 :
189 2 : if (kn && attr) {
190 2 : tmp = kernfs_find_and_get(kn, attr);
191 2 : kernfs_put(kn);
192 2 : kn = tmp;
193 : }
194 :
195 2 : if (kn) {
196 2 : kernfs_notify(kn);
197 2 : kernfs_put(kn);
198 : }
199 2 : }
200 : EXPORT_SYMBOL_GPL(sysfs_notify);
201 :
202 : static const struct kernfs_ops sysfs_file_kfops_empty = {
203 : };
204 :
205 : static const struct kernfs_ops sysfs_file_kfops_ro = {
206 : .seq_show = sysfs_kf_seq_show,
207 : };
208 :
209 : static const struct kernfs_ops sysfs_file_kfops_wo = {
210 : .write = sysfs_kf_write,
211 : };
212 :
213 : static const struct kernfs_ops sysfs_file_kfops_rw = {
214 : .seq_show = sysfs_kf_seq_show,
215 : .write = sysfs_kf_write,
216 : };
217 :
218 : static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
219 : .read = sysfs_kf_read,
220 : .prealloc = true,
221 : };
222 :
223 : static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
224 : .write = sysfs_kf_write,
225 : .prealloc = true,
226 : };
227 :
228 : static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
229 : .read = sysfs_kf_read,
230 : .write = sysfs_kf_write,
231 : .prealloc = true,
232 : };
233 :
234 : static const struct kernfs_ops sysfs_bin_kfops_ro = {
235 : .read = sysfs_kf_bin_read,
236 : };
237 :
238 : static const struct kernfs_ops sysfs_bin_kfops_wo = {
239 : .write = sysfs_kf_bin_write,
240 : };
241 :
242 : static const struct kernfs_ops sysfs_bin_kfops_rw = {
243 : .read = sysfs_kf_bin_read,
244 : .write = sysfs_kf_bin_write,
245 : };
246 :
247 : static const struct kernfs_ops sysfs_bin_kfops_mmap = {
248 : .read = sysfs_kf_bin_read,
249 : .write = sysfs_kf_bin_write,
250 : .mmap = sysfs_kf_bin_mmap,
251 : .open = sysfs_kf_bin_open,
252 : };
253 :
254 5458 : int sysfs_add_file_mode_ns(struct kernfs_node *parent,
255 : const struct attribute *attr, umode_t mode, kuid_t uid,
256 : kgid_t gid, const void *ns)
257 : {
258 5458 : struct kobject *kobj = parent->priv;
259 5458 : const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
260 5458 : struct lock_class_key *key = NULL;
261 5458 : const struct kernfs_ops *ops = NULL;
262 : struct kernfs_node *kn;
263 :
264 : /* every kobject with an attribute needs a ktype assigned */
265 5458 : if (WARN(!sysfs_ops, KERN_ERR
266 : "missing sysfs attribute operations for kobject: %s\n",
267 : kobject_name(kobj)))
268 : return -EINVAL;
269 :
270 5458 : if (mode & SYSFS_PREALLOC) {
271 0 : if (sysfs_ops->show && sysfs_ops->store)
272 : ops = &sysfs_prealloc_kfops_rw;
273 0 : else if (sysfs_ops->show)
274 : ops = &sysfs_prealloc_kfops_ro;
275 0 : else if (sysfs_ops->store)
276 0 : ops = &sysfs_prealloc_kfops_wo;
277 : } else {
278 5458 : if (sysfs_ops->show && sysfs_ops->store)
279 : ops = &sysfs_file_kfops_rw;
280 0 : else if (sysfs_ops->show)
281 : ops = &sysfs_file_kfops_ro;
282 0 : else if (sysfs_ops->store)
283 0 : ops = &sysfs_file_kfops_wo;
284 : }
285 :
286 5458 : if (!ops)
287 0 : ops = &sysfs_file_kfops_empty;
288 :
289 : #ifdef CONFIG_DEBUG_LOCK_ALLOC
290 : if (!attr->ignore_lockdep)
291 : key = attr->key ?: (struct lock_class_key *)&attr->skey;
292 : #endif
293 :
294 5458 : kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
295 : PAGE_SIZE, ops, (void *)attr, ns, key);
296 5458 : if (IS_ERR(kn)) {
297 0 : if (PTR_ERR(kn) == -EEXIST)
298 0 : sysfs_warn_dup(parent, attr->name);
299 0 : return PTR_ERR(kn);
300 : }
301 : return 0;
302 : }
303 :
304 9 : int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
305 : const struct bin_attribute *battr, umode_t mode,
306 : kuid_t uid, kgid_t gid, const void *ns)
307 : {
308 9 : const struct attribute *attr = &battr->attr;
309 9 : struct lock_class_key *key = NULL;
310 : const struct kernfs_ops *ops;
311 : struct kernfs_node *kn;
312 :
313 9 : if (battr->mmap)
314 : ops = &sysfs_bin_kfops_mmap;
315 9 : else if (battr->read && battr->write)
316 : ops = &sysfs_bin_kfops_rw;
317 9 : else if (battr->read)
318 : ops = &sysfs_bin_kfops_ro;
319 0 : else if (battr->write)
320 : ops = &sysfs_bin_kfops_wo;
321 : else
322 0 : ops = &sysfs_file_kfops_empty;
323 :
324 : #ifdef CONFIG_DEBUG_LOCK_ALLOC
325 : if (!attr->ignore_lockdep)
326 : key = attr->key ?: (struct lock_class_key *)&attr->skey;
327 : #endif
328 :
329 9 : kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
330 9 : battr->size, ops, (void *)attr, ns, key);
331 9 : if (IS_ERR(kn)) {
332 0 : if (PTR_ERR(kn) == -EEXIST)
333 0 : sysfs_warn_dup(parent, attr->name);
334 0 : return PTR_ERR(kn);
335 : }
336 : return 0;
337 : }
338 :
339 : /**
340 : * sysfs_create_file_ns - create an attribute file for an object with custom ns
341 : * @kobj: object we're creating for
342 : * @attr: attribute descriptor
343 : * @ns: namespace the new file should belong to
344 : */
345 1170 : int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
346 : const void *ns)
347 : {
348 : kuid_t uid;
349 : kgid_t gid;
350 :
351 1170 : if (WARN_ON(!kobj || !kobj->sd || !attr))
352 : return -EINVAL;
353 :
354 1170 : kobject_get_ownership(kobj, &uid, &gid);
355 1170 : return sysfs_add_file_mode_ns(kobj->sd, attr, attr->mode, uid, gid, ns);
356 : }
357 : EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
358 :
359 0 : int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
360 : {
361 0 : int err = 0;
362 : int i;
363 :
364 0 : for (i = 0; ptr[i] && !err; i++)
365 0 : err = sysfs_create_file(kobj, ptr[i]);
366 0 : if (err)
367 0 : while (--i >= 0)
368 0 : sysfs_remove_file(kobj, ptr[i]);
369 0 : return err;
370 : }
371 : EXPORT_SYMBOL_GPL(sysfs_create_files);
372 :
373 : /**
374 : * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
375 : * @kobj: object we're acting for.
376 : * @attr: attribute descriptor.
377 : * @group: group name.
378 : */
379 2 : int sysfs_add_file_to_group(struct kobject *kobj,
380 : const struct attribute *attr, const char *group)
381 : {
382 : struct kernfs_node *parent;
383 : kuid_t uid;
384 : kgid_t gid;
385 : int error;
386 :
387 2 : if (group) {
388 0 : parent = kernfs_find_and_get(kobj->sd, group);
389 : } else {
390 2 : parent = kobj->sd;
391 2 : kernfs_get(parent);
392 : }
393 :
394 2 : if (!parent)
395 : return -ENOENT;
396 :
397 2 : kobject_get_ownership(kobj, &uid, &gid);
398 2 : error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
399 : NULL);
400 2 : kernfs_put(parent);
401 :
402 2 : return error;
403 : }
404 : EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
405 :
406 : /**
407 : * sysfs_chmod_file - update the modified mode value on an object attribute.
408 : * @kobj: object we're acting for.
409 : * @attr: attribute descriptor.
410 : * @mode: file permissions.
411 : *
412 : */
413 0 : int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
414 : umode_t mode)
415 : {
416 : struct kernfs_node *kn;
417 : struct iattr newattrs;
418 : int rc;
419 :
420 0 : kn = kernfs_find_and_get(kobj->sd, attr->name);
421 0 : if (!kn)
422 : return -ENOENT;
423 :
424 0 : newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
425 0 : newattrs.ia_valid = ATTR_MODE;
426 :
427 0 : rc = kernfs_setattr(kn, &newattrs);
428 :
429 0 : kernfs_put(kn);
430 0 : return rc;
431 : }
432 : EXPORT_SYMBOL_GPL(sysfs_chmod_file);
433 :
434 : /**
435 : * sysfs_break_active_protection - break "active" protection
436 : * @kobj: The kernel object @attr is associated with.
437 : * @attr: The attribute to break the "active" protection for.
438 : *
439 : * With sysfs, just like kernfs, deletion of an attribute is postponed until
440 : * all active .show() and .store() callbacks have finished unless this function
441 : * is called. Hence this function is useful in methods that implement self
442 : * deletion.
443 : */
444 0 : struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
445 : const struct attribute *attr)
446 : {
447 : struct kernfs_node *kn;
448 :
449 0 : kobject_get(kobj);
450 0 : kn = kernfs_find_and_get(kobj->sd, attr->name);
451 0 : if (kn)
452 0 : kernfs_break_active_protection(kn);
453 0 : return kn;
454 : }
455 : EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
456 :
457 : /**
458 : * sysfs_unbreak_active_protection - restore "active" protection
459 : * @kn: Pointer returned by sysfs_break_active_protection().
460 : *
461 : * Undo the effects of sysfs_break_active_protection(). Since this function
462 : * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
463 : * argument passed to sysfs_break_active_protection() that attribute may have
464 : * been removed between the sysfs_break_active_protection() and
465 : * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
466 : * this function has returned.
467 : */
468 0 : void sysfs_unbreak_active_protection(struct kernfs_node *kn)
469 : {
470 0 : struct kobject *kobj = kn->parent->priv;
471 :
472 0 : kernfs_unbreak_active_protection(kn);
473 0 : kernfs_put(kn);
474 0 : kobject_put(kobj);
475 0 : }
476 : EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
477 :
478 : /**
479 : * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
480 : * @kobj: object we're acting for
481 : * @attr: attribute descriptor
482 : * @ns: namespace tag of the file to remove
483 : *
484 : * Hash the attribute name and namespace tag and kill the victim.
485 : */
486 48 : void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
487 : const void *ns)
488 : {
489 48 : struct kernfs_node *parent = kobj->sd;
490 :
491 48 : kernfs_remove_by_name_ns(parent, attr->name, ns);
492 48 : }
493 : EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
494 :
495 : /**
496 : * sysfs_remove_file_self - remove an object attribute from its own method
497 : * @kobj: object we're acting for
498 : * @attr: attribute descriptor
499 : *
500 : * See kernfs_remove_self() for details.
501 : */
502 0 : bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
503 : {
504 0 : struct kernfs_node *parent = kobj->sd;
505 : struct kernfs_node *kn;
506 : bool ret;
507 :
508 0 : kn = kernfs_find_and_get(parent, attr->name);
509 0 : if (WARN_ON_ONCE(!kn))
510 : return false;
511 :
512 0 : ret = kernfs_remove_self(kn);
513 :
514 0 : kernfs_put(kn);
515 0 : return ret;
516 : }
517 : EXPORT_SYMBOL_GPL(sysfs_remove_file_self);
518 :
519 0 : void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
520 : {
521 : int i;
522 :
523 0 : for (i = 0; ptr[i]; i++)
524 0 : sysfs_remove_file(kobj, ptr[i]);
525 0 : }
526 : EXPORT_SYMBOL_GPL(sysfs_remove_files);
527 :
528 : /**
529 : * sysfs_remove_file_from_group - remove an attribute file from a group.
530 : * @kobj: object we're acting for.
531 : * @attr: attribute descriptor.
532 : * @group: group name.
533 : */
534 0 : void sysfs_remove_file_from_group(struct kobject *kobj,
535 : const struct attribute *attr, const char *group)
536 : {
537 : struct kernfs_node *parent;
538 :
539 0 : if (group) {
540 0 : parent = kernfs_find_and_get(kobj->sd, group);
541 : } else {
542 0 : parent = kobj->sd;
543 0 : kernfs_get(parent);
544 : }
545 :
546 0 : if (parent) {
547 0 : kernfs_remove_by_name(parent, attr->name);
548 0 : kernfs_put(parent);
549 : }
550 0 : }
551 : EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
552 :
553 : /**
554 : * sysfs_create_bin_file - create binary file for object.
555 : * @kobj: object.
556 : * @attr: attribute descriptor.
557 : */
558 1 : int sysfs_create_bin_file(struct kobject *kobj,
559 : const struct bin_attribute *attr)
560 : {
561 : kuid_t uid;
562 : kgid_t gid;
563 :
564 1 : if (WARN_ON(!kobj || !kobj->sd || !attr))
565 : return -EINVAL;
566 :
567 1 : kobject_get_ownership(kobj, &uid, &gid);
568 1 : return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid,
569 : gid, NULL);
570 : }
571 : EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
572 :
573 : /**
574 : * sysfs_remove_bin_file - remove binary file for object.
575 : * @kobj: object.
576 : * @attr: attribute descriptor.
577 : */
578 0 : void sysfs_remove_bin_file(struct kobject *kobj,
579 : const struct bin_attribute *attr)
580 : {
581 0 : kernfs_remove_by_name(kobj->sd, attr->attr.name);
582 0 : }
583 : EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
584 :
585 0 : static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
586 : kgid_t kgid)
587 : {
588 0 : struct iattr newattrs = {
589 : .ia_valid = ATTR_UID | ATTR_GID,
590 : .ia_uid = kuid,
591 : .ia_gid = kgid,
592 : };
593 0 : return kernfs_setattr(kn, &newattrs);
594 : }
595 :
596 : /**
597 : * sysfs_link_change_owner - change owner of a sysfs file.
598 : * @kobj: object of the kernfs_node the symlink is located in.
599 : * @targ: object of the kernfs_node the symlink points to.
600 : * @name: name of the link.
601 : * @kuid: new owner's kuid
602 : * @kgid: new owner's kgid
603 : *
604 : * This function looks up the sysfs symlink entry @name under @kobj and changes
605 : * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
606 : * @targ.
607 : *
608 : * Returns 0 on success or error code on failure.
609 : */
610 0 : int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
611 : const char *name, kuid_t kuid, kgid_t kgid)
612 : {
613 0 : struct kernfs_node *kn = NULL;
614 : int error;
615 :
616 0 : if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
617 : return -EINVAL;
618 :
619 0 : error = -ENOENT;
620 0 : kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
621 0 : if (!kn)
622 : goto out;
623 :
624 0 : error = -EINVAL;
625 0 : if (kernfs_type(kn) != KERNFS_LINK)
626 : goto out;
627 0 : if (kn->symlink.target_kn->priv != targ)
628 : goto out;
629 :
630 0 : error = internal_change_owner(kn, kuid, kgid);
631 :
632 : out:
633 0 : kernfs_put(kn);
634 0 : return error;
635 : }
636 :
637 : /**
638 : * sysfs_file_change_owner - change owner of a sysfs file.
639 : * @kobj: object.
640 : * @name: name of the file to change.
641 : * @kuid: new owner's kuid
642 : * @kgid: new owner's kgid
643 : *
644 : * This function looks up the sysfs entry @name under @kobj and changes the
645 : * ownership to @kuid/@kgid.
646 : *
647 : * Returns 0 on success or error code on failure.
648 : */
649 0 : int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
650 : kgid_t kgid)
651 : {
652 : struct kernfs_node *kn;
653 : int error;
654 :
655 0 : if (!name)
656 : return -EINVAL;
657 :
658 0 : if (!kobj->state_in_sysfs)
659 : return -EINVAL;
660 :
661 0 : kn = kernfs_find_and_get(kobj->sd, name);
662 0 : if (!kn)
663 : return -ENOENT;
664 :
665 0 : error = internal_change_owner(kn, kuid, kgid);
666 :
667 0 : kernfs_put(kn);
668 :
669 0 : return error;
670 : }
671 : EXPORT_SYMBOL_GPL(sysfs_file_change_owner);
672 :
673 : /**
674 : * sysfs_change_owner - change owner of the given object.
675 : * @kobj: object.
676 : * @kuid: new owner's kuid
677 : * @kgid: new owner's kgid
678 : *
679 : * Change the owner of the default directory, files, groups, and attributes of
680 : * @kobj to @kuid/@kgid. Note that sysfs_change_owner mirrors how the sysfs
681 : * entries for a kobject are added by driver core. In summary,
682 : * sysfs_change_owner() takes care of the default directory entry for @kobj,
683 : * the default attributes associated with the ktype of @kobj and the default
684 : * attributes associated with the ktype of @kobj.
685 : * Additional properties not added by driver core have to be changed by the
686 : * driver or subsystem which created them. This is similar to how
687 : * driver/subsystem specific entries are removed.
688 : *
689 : * Returns 0 on success or error code on failure.
690 : */
691 0 : int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
692 : {
693 : int error;
694 : const struct kobj_type *ktype;
695 :
696 0 : if (!kobj->state_in_sysfs)
697 : return -EINVAL;
698 :
699 : /* Change the owner of the kobject itself. */
700 0 : error = internal_change_owner(kobj->sd, kuid, kgid);
701 0 : if (error)
702 : return error;
703 :
704 0 : ktype = get_ktype(kobj);
705 0 : if (ktype) {
706 : /*
707 : * Change owner of the default groups associated with the
708 : * ktype of @kobj.
709 : */
710 0 : error = sysfs_groups_change_owner(kobj, ktype->default_groups,
711 : kuid, kgid);
712 0 : if (error)
713 : return error;
714 : }
715 :
716 : return 0;
717 : }
718 : EXPORT_SYMBOL_GPL(sysfs_change_owner);
719 :
720 : /**
721 : * sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
722 : * @buf: start of PAGE_SIZE buffer.
723 : * @fmt: format
724 : * @...: optional arguments to @format
725 : *
726 : *
727 : * Returns number of characters written to @buf.
728 : */
729 0 : int sysfs_emit(char *buf, const char *fmt, ...)
730 : {
731 : va_list args;
732 : int len;
733 :
734 0 : if (WARN(!buf || offset_in_page(buf),
735 : "invalid sysfs_emit: buf:%p\n", buf))
736 : return 0;
737 :
738 0 : va_start(args, fmt);
739 0 : len = vscnprintf(buf, PAGE_SIZE, fmt, args);
740 0 : va_end(args);
741 :
742 0 : return len;
743 : }
744 : EXPORT_SYMBOL_GPL(sysfs_emit);
745 :
746 : /**
747 : * sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
748 : * @buf: start of PAGE_SIZE buffer.
749 : * @at: offset in @buf to start write in bytes
750 : * @at must be >= 0 && < PAGE_SIZE
751 : * @fmt: format
752 : * @...: optional arguments to @fmt
753 : *
754 : *
755 : * Returns number of characters written starting at &@buf[@at].
756 : */
757 0 : int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
758 : {
759 : va_list args;
760 : int len;
761 :
762 0 : if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
763 : "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
764 : return 0;
765 :
766 0 : va_start(args, fmt);
767 0 : len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
768 0 : va_end(args);
769 :
770 0 : return len;
771 : }
772 : EXPORT_SYMBOL_GPL(sysfs_emit_at);
|