Import version 1.8.3
[s390-tools.git] / zipl / src / proc.c
blob871636846fb767bec9923fdcccc8aaf4e3f21991
1 /*
2 * s390-tools/zipl/src/proc.c
3 * Scanner for the /proc/ files
5 * Copyright IBM Corp. 2001, 2007.
7 * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
8 */
10 #include "proc.h"
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <sys/sysmacros.h>
20 #include "misc.h"
22 static const char proc_part_filename[] = "/proc/partitions";
23 static const char proc_dev_filename[] = "/proc/devices";
25 struct file_buffer {
26 char* buffer;
27 off_t pos;
28 size_t length;
32 /* Get the contents of a file and fill in the respective fields of
33 * FILE. Return 0 on success, non-zero otherwise. */
34 static int
35 get_file_buffer(struct file_buffer* file, const char *filename)
37 int rc;
39 rc = misc_read_special_file(filename, &file->buffer, &file->length, 0);
40 file->pos = 0;
41 return rc;
45 /* Free resources allocated for file buffer identified by
46 * FILE. */
47 static void
48 free_file_buffer(struct file_buffer* file)
50 if (file->buffer != NULL) {
51 free(file->buffer);
52 file->buffer = NULL;
53 file->pos = 0;
54 file->length = 0;
59 /* Return character at current FILE buffer position or EOF if at end of
60 * file. */
61 static int
62 current_char(struct file_buffer* file)
64 if (file->buffer != NULL)
65 if (file->pos < (off_t) file->length)
66 return file->buffer[file->pos];
67 return EOF;
71 /* Advance the current file pointer of file buffer FILE until the current
72 * character is no longer a whitespace or until the end of line or file is
73 * reached. Return 0 if at least one whitespace character was encountered,
74 * non-zero otherwise. */
75 static int
76 skip_whitespaces(struct file_buffer* file)
78 int rc;
80 rc = -1;
81 while ((current_char(file) != '\n') && isspace(current_char(file))) {
82 rc = 0;
83 file->pos++;
85 return rc;
89 /* Scan a positive integer number at the current position of file buffer FILE
90 * and advance the position respectively. Upon success, return zero and set
91 * NUMBER to contain the scanned number. Return non-zero otherwise. */
92 static int
93 scan_number(struct file_buffer* file, size_t* number)
95 int rc;
96 size_t old_number;
98 *number=0;
99 rc = -1;
100 while (isdigit(current_char(file))) {
101 rc = 0;
102 old_number = *number;
103 *number = *number * 10 + current_char(file) - '0';
104 /* Check for overflow */
105 if (old_number > *number) {
106 rc = -1;
107 break;
109 file->pos++;
111 return rc;
115 /* Scan a device node name at the current position of file buffer FILE and
116 * advance the position respectively. Upon success, return zero and set
117 * NAME to contain a copy of the scanned name. Return non-zero otherwise. */
118 static int
119 scan_name(struct file_buffer* file, char** name)
121 off_t start_pos;
123 start_pos = file->pos;
124 while (!isspace(current_char(file)) &&
125 (current_char(file) != EOF))
126 file->pos++;
127 if (file->pos > start_pos) {
128 *name = (char *) malloc(file->pos - start_pos + 1);
129 if (*name == NULL)
130 return -1;
131 memcpy((void *) *name, (void *) &file->buffer[start_pos],
132 file->pos - start_pos);
133 (*name)[file->pos - start_pos] = 0;
134 return 0;
135 } else
136 return -1;
139 /* Scan for the specified STRING at the current position of file buffer FILE
140 * and advance the position respectively. Upon success, return zero. Return
141 * non-zero otherwise. */
142 static int
143 scan_string(struct file_buffer* file, const char *string)
145 int i;
147 i=0;
148 for (i=0; string[i] && (current_char(file) == string[i]);
149 i++, file->pos++);
150 if (string[i] == '\0')
151 return 0;
152 return -1;
156 /* Advance the current file position to beginning of next line in file buffer
157 * FILE or to end of file. */
158 static void
159 skip_line(struct file_buffer* file)
161 while ((current_char(file) != '\n') && (current_char(file) != EOF))
162 file->pos++;
163 if (current_char(file) == '\n')
164 file->pos++;
168 /* Return non-zero if the current file position of file buffer FILE is at the
169 * end of file. Return zero otherwise. */
170 static int
171 eof(struct file_buffer* file)
173 return file->pos >= (off_t) file->length;
177 /* Scan a line of the specified /proc/partitions FILE buffer and advance the
178 * current file position pointer respectively. If the current line matches
179 * the correct pattern, fill in the corresponding data into ENTRY and return 0.
180 * Return non-zero otherwise. */
181 static int
182 scan_part_entry(struct file_buffer* file, struct proc_part_entry* entry)
184 int rc;
185 size_t dev_major;
186 size_t dev_minor;
187 size_t blockcount;
188 char* name;
190 /* Scan for: (\s*)(\d+)(\s+)(\d+)(\s+)(\d+)(\s+)(\S+)(\.*)$ */
191 skip_whitespaces(file);
192 rc = scan_number(file, &dev_major);
193 if (rc)
194 return rc;
195 rc = skip_whitespaces(file);
196 if (rc)
197 return rc;
198 rc = scan_number(file, &dev_minor);
199 if (rc)
200 return rc;
201 rc = skip_whitespaces(file);
202 if (rc)
203 return rc;
204 rc = scan_number(file, &blockcount);
205 if (rc)
206 return rc;
207 rc = skip_whitespaces(file);
208 if (rc)
209 return rc;
210 rc = scan_name(file, &name);
211 if (rc)
212 return rc;
213 skip_line(file);
214 entry->device = makedev(dev_major, dev_minor);
215 entry->blockcount = blockcount;
216 entry->name = name;
217 return 0;
221 /* Release resources associated with ENTRY. */
222 void
223 proc_part_free_entry(struct proc_part_entry* entry)
225 if (entry->name != NULL) {
226 free(entry->name);
227 entry->name = NULL;
231 /* Scan a line of the specified /proc/devices FILE buffer and advance the
232 * current file position pointer respectively. If the current line matches
233 * the correct pattern, fill in the corresponding data into ENTRY and return 0.
234 * Return non-zero otherwise. */
235 static int
236 scan_dev_entry(struct file_buffer* file, struct proc_dev_entry* entry,
237 int blockdev)
239 int rc;
240 size_t dev_major;
241 char* name;
243 /* Scan for: (\s*)(\d+)(\s+)(\S+)(\.*)$ */
244 skip_whitespaces(file);
245 rc = scan_number(file, &dev_major);
246 if (rc)
247 return rc;
248 rc = skip_whitespaces(file);
249 if (rc)
250 return rc;
251 rc = scan_name(file, &name);
252 if (rc)
253 return rc;
254 skip_line(file);
255 entry->device = makedev(dev_major, 0);
256 entry->name = name;
257 entry->blockdev = blockdev;
258 return 0;
262 /* Release resources associated with ENTRY. */
263 void
264 proc_dev_free_entry(struct proc_dev_entry* entry)
266 if (entry->name != NULL) {
267 free(entry->name);
268 entry->name = NULL;
273 /* Scan /proc/partitions for an entry matching DEVICE. When there is a match,
274 * store entry data in ENTRY and return 0. Return non-zero otherwise. */
276 proc_part_get_entry(dev_t device, struct proc_part_entry* entry)
278 struct file_buffer file;
279 int rc;
281 rc = get_file_buffer(&file, proc_part_filename);
282 if (rc)
283 return rc;
284 rc = -1;
285 while (!eof(&file)) {
286 if (scan_part_entry(&file, entry) == 0) {
287 if (entry->device == device) {
288 rc = 0;
289 break;
291 proc_part_free_entry(entry);
292 } else
293 skip_line(&file);
295 free_file_buffer(&file);
296 return rc;
299 /* Scan /proc/devices for a blockdevice (BLOCKDEV is 1) or a character
300 * device (BLOCKDEV is 0) with a major number matching the major number of DEV.
301 * When there is a match, store entry data in ENTRY and return 0. Return
302 * non-zero otherwise. */
304 proc_dev_get_entry(dev_t device, int blockdev, struct proc_dev_entry* entry)
306 struct file_buffer file;
307 int rc;
308 int scan_blockdev = 0;
310 rc = get_file_buffer(&file, proc_dev_filename);
311 if (rc)
312 return rc;
313 rc = -1;
314 while (!eof(&file)) {
315 if (scan_string(&file, "Block") == 0) {
316 skip_line(&file);
317 scan_blockdev = 1;
318 continue;
319 } else if (scan_dev_entry(&file, entry, scan_blockdev) == 0) {
320 if ((major(entry->device) == major(device)) &&
321 blockdev == scan_blockdev) {
322 rc = 0;
323 break;
325 proc_dev_free_entry(entry);
326 } else
327 skip_line(&file);
329 free_file_buffer(&file);
330 return rc;