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>
18 #include <sys/sysmacros.h>
22 static const char proc_part_filename
[] = "/proc/partitions";
23 static const char proc_dev_filename
[] = "/proc/devices";
32 /* Get the contents of a file and fill in the respective fields of
33 * FILE. Return 0 on success, non-zero otherwise. */
35 get_file_buffer(struct file_buffer
* file
, const char *filename
)
39 rc
= misc_read_special_file(filename
, &file
->buffer
, &file
->length
, 0);
45 /* Free resources allocated for file buffer identified by
48 free_file_buffer(struct file_buffer
* file
)
50 if (file
->buffer
!= NULL
) {
59 /* Return character at current FILE buffer position or EOF if at end of
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
];
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. */
76 skip_whitespaces(struct file_buffer
* file
)
81 while ((current_char(file
) != '\n') && isspace(current_char(file
))) {
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. */
93 scan_number(struct file_buffer
* file
, size_t* number
)
100 while (isdigit(current_char(file
))) {
102 old_number
= *number
;
103 *number
= *number
* 10 + current_char(file
) - '0';
104 /* Check for overflow */
105 if (old_number
> *number
) {
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. */
119 scan_name(struct file_buffer
* file
, char** name
)
123 start_pos
= file
->pos
;
124 while (!isspace(current_char(file
)) &&
125 (current_char(file
) != EOF
))
127 if (file
->pos
> start_pos
) {
128 *name
= (char *) malloc(file
->pos
- start_pos
+ 1);
131 memcpy((void *) *name
, (void *) &file
->buffer
[start_pos
],
132 file
->pos
- start_pos
);
133 (*name
)[file
->pos
- start_pos
] = 0;
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. */
143 scan_string(struct file_buffer
* file
, const char *string
)
148 for (i
=0; string
[i
] && (current_char(file
) == string
[i
]);
150 if (string
[i
] == '\0')
156 /* Advance the current file position to beginning of next line in file buffer
157 * FILE or to end of file. */
159 skip_line(struct file_buffer
* file
)
161 while ((current_char(file
) != '\n') && (current_char(file
) != EOF
))
163 if (current_char(file
) == '\n')
168 /* Return non-zero if the current file position of file buffer FILE is at the
169 * end of file. Return zero otherwise. */
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. */
182 scan_part_entry(struct file_buffer
* file
, struct proc_part_entry
* entry
)
190 /* Scan for: (\s*)(\d+)(\s+)(\d+)(\s+)(\d+)(\s+)(\S+)(\.*)$ */
191 skip_whitespaces(file
);
192 rc
= scan_number(file
, &dev_major
);
195 rc
= skip_whitespaces(file
);
198 rc
= scan_number(file
, &dev_minor
);
201 rc
= skip_whitespaces(file
);
204 rc
= scan_number(file
, &blockcount
);
207 rc
= skip_whitespaces(file
);
210 rc
= scan_name(file
, &name
);
214 entry
->device
= makedev(dev_major
, dev_minor
);
215 entry
->blockcount
= blockcount
;
221 /* Release resources associated with ENTRY. */
223 proc_part_free_entry(struct proc_part_entry
* entry
)
225 if (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. */
236 scan_dev_entry(struct file_buffer
* file
, struct proc_dev_entry
* entry
,
243 /* Scan for: (\s*)(\d+)(\s+)(\S+)(\.*)$ */
244 skip_whitespaces(file
);
245 rc
= scan_number(file
, &dev_major
);
248 rc
= skip_whitespaces(file
);
251 rc
= scan_name(file
, &name
);
255 entry
->device
= makedev(dev_major
, 0);
257 entry
->blockdev
= blockdev
;
262 /* Release resources associated with ENTRY. */
264 proc_dev_free_entry(struct proc_dev_entry
* entry
)
266 if (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
;
281 rc
= get_file_buffer(&file
, proc_part_filename
);
285 while (!eof(&file
)) {
286 if (scan_part_entry(&file
, entry
) == 0) {
287 if (entry
->device
== device
) {
291 proc_part_free_entry(entry
);
295 free_file_buffer(&file
);
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
;
308 int scan_blockdev
= 0;
310 rc
= get_file_buffer(&file
, proc_dev_filename
);
314 while (!eof(&file
)) {
315 if (scan_string(&file
, "Block") == 0) {
319 } else if (scan_dev_entry(&file
, entry
, scan_blockdev
) == 0) {
320 if ((major(entry
->device
) == major(device
)) &&
321 blockdev
== scan_blockdev
) {
325 proc_dev_free_entry(entry
);
329 free_file_buffer(&file
);