OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / hdparm / sysfs.c
1 /*
2  * Access helpers for sysfs.
3  * Copyright (c) Mark Lord 2008
4  *
5  * You may use/distribute this freely, under the terms of either
6  * (your choice) the GNU General Public License version 2,
7  * or a BSD style license.
8  */
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <dirent.h>
16 #include <sys/stat.h>
17 #include <linux/types.h>
18
19 #include "hdparm.h"
20
21 static char *path_append (char *path, const char *new)
22 {
23         char *pathtail = path + strlen(path);
24
25         *pathtail = '/';
26         strcpy(pathtail+1, new);
27         return pathtail;
28 }
29
30 static int sysfs_write_attr (char *path, const char *attr, const char *fmt, void *val, int verbose)
31 {
32         FILE *fp;
33         int count = -1, err = 0;
34         char *pathtail = path_append(path, attr);
35
36         fp = fopen(path, "w");
37         if (!fp) {
38                 err = errno;
39         } else if (fmt[0] != '%') {
40                 err = EINVAL;
41         } else {
42                 switch (fmt[1]) {
43                         case 's':
44                                 count = fprintf(fp, fmt, val);
45                                 break;
46                         case 'd':
47                         case 'u':
48                                 count = fprintf(fp, fmt, *(unsigned int *)val);
49                                 break;
50                         case 'l':
51                                 if (fmt[2] == 'l')
52                                         count = fprintf(fp, fmt, *(unsigned long long *)val);
53                                 else
54                                         count = fprintf(fp, fmt, *(unsigned long *)val);
55                                 break;
56                         default:
57                                 errno = EINVAL;
58                 }
59                 if (count < 0)
60                         err = errno;
61                 fclose(fp);
62         }
63         if (err && verbose) perror(path);
64         *pathtail = '\0';
65         return err;
66 }
67
68 static int sysfs_read_attr (char *path, const char *attr, const char *fmt, void *val1, void *val2, int verbose)
69 {
70         FILE *fp;
71         int count, err = 0;
72         char *pathtail = path_append(path, attr);
73
74         fp = fopen(path, "r");
75         if (!fp) {
76                 err = errno;
77         } else {
78                 count = fscanf(fp, fmt, val1, val2);
79                 if (count != (val2 ? 2 : 1))
80                         err = (count == EOF) ? errno : EINVAL;
81                 fclose(fp);
82         }
83         if (err && verbose) perror(path);
84         *pathtail = '\0';
85         return err;
86 }
87
88 static int sysfs_find_dev2 (char *path, dev_t dev, int recurse, int verbose)
89 {
90         DIR *dp;
91         struct dirent *entry;
92         char *pathtail;
93
94         if (!(dp = opendir(path))) {
95                 int err = errno;
96                 if (verbose) perror(path);
97                 return err;
98         }
99         pathtail = path + strlen(path);
100         while ((entry = readdir(dp)) != NULL) {
101                 if ((entry->d_type == DT_DIR || entry->d_type == DT_LNK) && entry->d_name[0] != '.') {
102                         unsigned int maj, min;
103                         sprintf(pathtail, "/%s", entry->d_name);
104                         if (sysfs_read_attr(path, "/dev", "%u:%u", &maj, &min, verbose))
105                                 min = ~minor(dev);
106                         else if (maj != major(dev))
107                                 continue;
108                         if (min == minor(dev)
109                          || (recurse && sysfs_find_dev2(path, dev, recurse - 1, verbose) == 0)) {
110                                 closedir(dp);
111                                 return 0;
112                         }
113                 }
114         }
115         closedir(dp);
116         *pathtail = '\0';
117         if (verbose)
118                 fprintf(stderr, "%u,%u: device not found in /sys\n", major(dev), minor(dev));
119         return ENOENT;
120 }
121
122 static int sysfs_find_dev (dev_t dev, char *path, int verbose)
123 {
124         int err, recurse = 1;
125
126         strcpy(path, "/sys/block");
127         err = sysfs_find_dev2(path, dev, recurse, 0);
128         if (err && verbose)
129                 fprintf(stderr, "%s(%u:%u): %s\n", __func__,
130                         major(dev), minor(dev), strerror(err));
131         return err;
132 }
133
134 static int get_dev_from_fd (int fd, dev_t *dev, int verbose)
135 {
136         struct stat st;
137
138         if (0 != fstat(fd, &st)) {
139                 int err = errno;
140                 if (verbose) perror(" fstat() failed");
141                 return err;
142         }
143         if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
144                 *dev = st.st_rdev;
145         else
146                 *dev = st.st_dev;
147         return 0;
148 }
149
150 static int sysfs_find_fd (int fd, char **path_p, int verbose)
151 {
152         static int have_prev = 0;
153         static dev_t prev;
154         static char path[PATH_MAX];
155         dev_t dev;
156         int err;
157
158         memset(&dev, 0, sizeof(dev));
159         err = get_dev_from_fd(fd, &dev, verbose);
160         if (!err) {
161                 if (have_prev && 0 == memcmp(&dev, &prev, sizeof(dev))) {
162                         /*re-use previous path, since dev was unchanged from before */
163                 } else {
164                         prev = dev;
165                         have_prev = 1;
166                         err = sysfs_find_dev(dev, path, verbose);
167                 }
168         }
169         if (err)
170                 have_prev = 0;
171         else
172                 *path_p = path;
173         return err;
174 }
175
176 int sysfs_get_attr (int fd, const char *attr, const char *fmt, void *val1, void *val2, int verbose)
177 {
178         char *path;
179         int err;
180
181         err = sysfs_find_fd(fd, &path, verbose);
182         if (!err)
183                 err = sysfs_read_attr(path, attr, fmt, val1, val2, verbose);
184         return err;
185 }
186
187 int sysfs_set_attr (int fd, const char *attr, const char *fmt, void *val_p, int verbose)
188 {
189         char *path;
190         int err;
191
192         err = sysfs_find_fd(fd, &path, verbose);
193         if (!err)
194                 err = sysfs_write_attr(path, attr, fmt, val_p, verbose);
195         return err;
196 }