41ac21ba4e38ef20cc0ced4991ee103b0407c6f6
[multipath-tools/.git] / libmultipath / util.c
1 #include <string.h>
2 #include <ctype.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include "debug.h"
8 #include "memory.h"
9 #include "checkers.h"
10 #include "vector.h"
11 #include "structs.h"
12
13 void
14 strchop(char *str)
15 {
16         int i;
17
18         for (i=strlen(str)-1; i >=0 && isspace(str[i]); --i) ;
19         str[++i] = '\0';
20 }
21
22 int
23 basenamecpy (const char * str1, char * str2, int str2len)
24 {
25         char *p;
26
27         if (!str1 || !strlen(str1))
28                 return 0;
29
30         if (strlen(str1) >= str2len)
31                 return 0;
32
33         if (!str2)
34                 return 0;
35
36         p = (char *)str1 + (strlen(str1) - 1);
37
38         while (*--p != '/' && p != str1)
39                 continue;
40
41         if (p != str1)
42                 p++;
43
44         strncpy(str2, p, str2len);
45         str2[str2len - 1] = '\0';
46         strchop(str2);
47         return strlen(str2);
48 }
49
50 int
51 filepresent (char * run) {
52         struct stat buf;
53
54         if(!stat(run, &buf))
55                 return 1;
56         return 0;
57 }
58
59 int
60 get_word (char * sentence, char ** word)
61 {
62         char * p;
63         int len;
64         int skip = 0;
65
66         if (word)
67                 *word = NULL;
68
69         while (*sentence ==  ' ') {
70                 sentence++;
71                 skip++;
72         }
73         if (*sentence == '\0')
74                 return 0;
75
76         p = sentence;
77
78         while (*p !=  ' ' && *p != '\0')
79                 p++;
80
81         len = (int) (p - sentence);
82
83         if (!word)
84                 return skip + len;
85
86         *word = MALLOC(len + 1);
87
88         if (!*word) {
89                 condlog(0, "get_word : oom");
90                 return 0;
91         }
92         strncpy(*word, sentence, len);
93         strchop(*word);
94         condlog(4, "*word = %s, len = %i", *word, len);
95
96         if (*p == '\0')
97                 return 0;
98
99         return skip + len;
100 }
101
102 size_t strlcpy(char *dst, const char *src, size_t size)
103 {
104         size_t bytes = 0;
105         char *q = dst;
106         const char *p = src;
107         char ch;
108
109         while ((ch = *p++)) {
110                 if (bytes+1 < size)
111                         *q++ = ch;
112                 bytes++;
113         }
114
115         /* If size == 0 there is no space for a final null... */
116         if (size)
117                 *q = '\0';
118         return bytes;
119 }
120
121 size_t strlcat(char *dst, const char *src, size_t size)
122 {
123         size_t bytes = 0;
124         char *q = dst;
125         const char *p = src;
126         char ch;
127
128         while (bytes < size && *q) {
129                 q++;
130                 bytes++;
131         }
132         if (bytes == size)
133                 return (bytes + strlen(src));
134
135         while ((ch = *p++)) {
136                 if (bytes+1 < size)
137                 *q++ = ch;
138                 bytes++;
139         }
140
141         *q = '\0';
142         return bytes;
143 }
144
145 void remove_trailing_chars(char *path, char c)
146 {
147         size_t len;
148
149         len = strlen(path);
150         while (len > 0 && path[len-1] == c)
151                 path[--len] = '\0';
152 }
153
154 extern int
155 devt2devname (char *devname, int devname_len, char *devt)
156 {
157         FILE *fd;
158         unsigned int tmpmaj, tmpmin, major, minor;
159         char dev[FILE_NAME_SIZE];
160         char block_path[PATH_SIZE];
161         struct stat statbuf;
162
163         memset(block_path, 0, sizeof(block_path));
164         memset(dev, 0, sizeof(dev));
165         if (sscanf(devt, "%u:%u", &major, &minor) != 2) {
166                 condlog(0, "Invalid device number %s", devt);
167                 return 1;
168         }
169
170         if (devname_len > FILE_NAME_SIZE)
171                 devname_len = FILE_NAME_SIZE;
172
173         if (stat("/sys/dev/block", &statbuf) == 0) {
174                 /* Newer kernels have /sys/dev/block */
175                 sprintf(block_path,"/sys/dev/block/%u:%u", major, minor);
176                 if (lstat(block_path, &statbuf) == 0) {
177                         if (S_ISLNK(statbuf.st_mode) &&
178                             readlink(block_path, dev, FILE_NAME_SIZE) > 0) {
179                                 char *p = strrchr(dev, '/');
180
181                                 if (!p) {
182                                         condlog(0, "No sysfs entry for %s",
183                                                 block_path);
184                                         return 1;
185                                 }
186                                 p++;
187                                 strncpy(devname, p, devname_len);
188                                 return 0;
189                         }
190                 }
191                 goto skip_proc;
192         }
193         memset(block_path, 0, sizeof(block_path));
194
195         if (!(fd = fopen("/proc/partitions", "r"))) {
196                 condlog(0, "Cannot open /proc/partitions");
197                 return 1;
198         }
199
200         while (!feof(fd)) {
201                 int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev);
202                 if (!r) {
203                         r = fscanf(fd,"%*s\n");
204                         continue;
205                 }
206                 if (r != 3)
207                         continue;
208
209                 if ((major == tmpmaj) && (minor == tmpmin)) {
210                         if (snprintf(block_path, sizeof(block_path),
211                                      "/sys/block/%s", dev) >= sizeof(block_path)) {
212                                 condlog(0, "device name %s is too long", dev);
213                                 fclose(fd);
214                                 return 1;
215                         }
216                         break;
217                 }
218         }
219         fclose(fd);
220 skip_proc:
221         if (strncmp(block_path,"/sys/block", 10)) {
222                 condlog(3, "No device found for %u:%u", major, minor);
223                 return 1;
224         }
225
226         if (stat(block_path, &statbuf) < 0) {
227                 condlog(0, "No sysfs entry for %s", block_path);
228                 return 1;
229         }
230
231         if (S_ISDIR(statbuf.st_mode) == 0) {
232                 condlog(0, "sysfs entry %s is not a directory", block_path);
233                 return 1;
234         }
235         basenamecpy((const char *)block_path, devname, devname_len);
236         return 0;
237 }
238
239 dev_t parse_devt(const char *dev_t)
240 {
241         int maj, min;
242
243         if (sscanf(dev_t,"%d:%d", &maj, &min) != 2)
244                 return 0;
245
246         return makedev(maj, min);
247 }