Subversion Repositories HelenOS

Rev

Rev 4492 | Rev 4509 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4492 Rev 4508
1
/*
1
/*
2
 * Copyright (c) 2005 Martin Decky
2
 * Copyright (c) 2005 Martin Decky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <unistd.h>
36
#include <unistd.h>
37
#include <fcntl.h>
37
#include <fcntl.h>
38
#include <string.h>
38
#include <string.h>
39
#include <errno.h>
39
#include <errno.h>
40
#include <bool.h>
40
#include <bool.h>
41
#include <malloc.h>
41
#include <malloc.h>
42
#include <io/klog.h>
42
#include <io/klog.h>
43
#include <vfs/vfs.h>
43
#include <vfs/vfs.h>
44
#include <ipc/devmap.h>
44
#include <ipc/devmap.h>
-
 
45
#include <libadt/list.h>
45
 
46
 
46
FILE stdin_null = {
47
static FILE stdin_null = {
47
    .fd = -1,
48
    .fd = -1,
48
    .error = true,
49
    .error = true,
49
    .eof = true,
50
    .eof = true,
50
    .klog = false,
51
    .klog = false,
51
    .phone = -1
52
    .phone = -1
52
};
53
};
53
 
54
 
54
FILE stdout_klog = {
55
static FILE stdout_klog = {
55
    .fd = -1,
56
    .fd = -1,
56
    .error = false,
57
    .error = false,
57
    .eof = false,
58
    .eof = false,
58
    .klog = true,
59
    .klog = true,
59
    .phone = -1
60
    .phone = -1
60
};
61
};
61
 
62
 
-
 
63
static FILE stderr_klog = {
-
 
64
    .fd = -1,
-
 
65
    .error = false,
-
 
66
    .eof = false,
-
 
67
    .klog = true,
-
 
68
    .phone = -1
-
 
69
};
-
 
70
 
-
 
71
FILE *stdin = NULL;
-
 
72
FILE *stdout = NULL;
-
 
73
FILE *stderr = NULL;
-
 
74
 
-
 
75
static LIST_INITIALIZE(files);
-
 
76
 
-
 
77
void stdio_init(int filc, fdi_node_t *filv[])
-
 
78
{
-
 
79
    if (filc > 0) {
-
 
80
        stdin = fopen_node(filv[0], "r");
-
 
81
    } else {
62
FILE *stdin = &stdin_null;
82
        stdin = &stdin_null;
-
 
83
        list_append(&stdin->link, &files);
-
 
84
    }
-
 
85
   
-
 
86
    if (filc > 1) {
-
 
87
        stdout = fopen_node(filv[1], "w");
-
 
88
    } else {
63
FILE *stdout = &stdout_klog;
89
        stdout = &stdout_klog;
-
 
90
        list_append(&stdout->link, &files);
-
 
91
    }
-
 
92
   
-
 
93
    if (filc > 2) {
-
 
94
        stderr = fopen_node(filv[2], "w");
-
 
95
    } else {
64
FILE *stderr = &stdout_klog;
96
        stderr = &stderr_klog;
-
 
97
        list_append(&stderr->link, &files);
-
 
98
    }
-
 
99
}
-
 
100
 
-
 
101
void stdio_done(void)
-
 
102
{
-
 
103
    link_t *link = files.next;
-
 
104
   
-
 
105
    while (link != &files) {
-
 
106
        FILE *file = list_get_instance(link, FILE, link);
-
 
107
        fclose(file);
-
 
108
        link = files.next;
-
 
109
    }
-
 
110
}
65
 
111
 
66
static bool parse_mode(const char *mode, int *flags)
112
static bool parse_mode(const char *mode, int *flags)
67
{
113
{
68
    /* Parse mode except first character. */
114
    /* Parse mode except first character. */
69
    const char *mp = mode;
115
    const char *mp = mode;
70
    if (*mp++ == 0) {
116
    if (*mp++ == 0) {
71
        errno = EINVAL;
117
        errno = EINVAL;
72
        return false;
118
        return false;
73
    }
119
    }
74
   
120
   
75
    if ((*mp == 'b') || (*mp == 't'))
121
    if ((*mp == 'b') || (*mp == 't'))
76
        mp++;
122
        mp++;
77
   
123
   
78
    bool plus;
124
    bool plus;
79
    if (*mp == '+') {
125
    if (*mp == '+') {
80
        mp++;
126
        mp++;
81
        plus = true;
127
        plus = true;
82
    } else
128
    } else
83
        plus = false;
129
        plus = false;
84
   
130
   
85
    if (*mp != 0) {
131
    if (*mp != 0) {
86
        errno = EINVAL;
132
        errno = EINVAL;
87
        return false;
133
        return false;
88
    }
134
    }
89
   
135
   
90
    /* Parse first character of mode and determine flags for open(). */
136
    /* Parse first character of mode and determine flags for open(). */
91
    switch (mode[0]) {
137
    switch (mode[0]) {
92
    case 'r':
138
    case 'r':
93
        *flags = plus ? O_RDWR : O_RDONLY;
139
        *flags = plus ? O_RDWR : O_RDONLY;
94
        break;
140
        break;
95
    case 'w':
141
    case 'w':
96
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
142
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
97
        break;
143
        break;
98
    case 'a':
144
    case 'a':
99
        /* TODO: a+ must read from beginning, append to the end. */
145
        /* TODO: a+ must read from beginning, append to the end. */
100
        if (plus) {
146
        if (plus) {
101
            errno = ENOTSUP;
147
            errno = ENOTSUP;
102
            return false;
148
            return false;
103
        }
149
        }
104
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
150
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
105
    default:
151
    default:
106
        errno = EINVAL;
152
        errno = EINVAL;
107
        return false;
153
        return false;
108
    }
154
    }
109
   
155
   
110
    return true;
156
    return true;
111
}
157
}
112
 
158
 
113
/** Open a stream.
159
/** Open a stream.
114
 *
160
 *
115
 * @param path Path of the file to open.
161
 * @param path Path of the file to open.
116
 * @param mode Mode string, (r|w|a)[b|t][+].
162
 * @param mode Mode string, (r|w|a)[b|t][+].
117
 *
163
 *
118
 */
164
 */
119
FILE *fopen(const char *path, const char *mode)
165
FILE *fopen(const char *path, const char *mode)
120
{
166
{
121
    int flags;
167
    int flags;
122
    if (!parse_mode(mode, &flags))
168
    if (!parse_mode(mode, &flags))
123
        return NULL;
169
        return NULL;
124
   
170
   
125
    /* Open file. */
171
    /* Open file. */
126
    FILE *stream = malloc(sizeof(FILE));
172
    FILE *stream = malloc(sizeof(FILE));
127
    if (stream == NULL) {
173
    if (stream == NULL) {
128
        errno = ENOMEM;
174
        errno = ENOMEM;
129
        return NULL;
175
        return NULL;
130
    }
176
    }
131
   
177
   
132
    stream->fd = open(path, flags, 0666);
178
    stream->fd = open(path, flags, 0666);
133
    if (stream->fd < 0) {
179
    if (stream->fd < 0) {
134
        /* errno was set by open() */
180
        /* errno was set by open() */
135
        free(stream);
181
        free(stream);
136
        return NULL;
182
        return NULL;
137
    }
183
    }
138
   
184
   
139
    stream->error = false;
185
    stream->error = false;
140
    stream->eof = false;
186
    stream->eof = false;
141
    stream->klog = false;
187
    stream->klog = false;
142
    stream->phone = -1;
188
    stream->phone = -1;
143
   
189
   
-
 
190
    list_append(&stream->link, &files);
-
 
191
   
144
    return stream;
192
    return stream;
145
}
193
}
146
 
194
 
147
FILE *fopen_node(fdi_node_t *node, const char *mode)
195
FILE *fopen_node(fdi_node_t *node, const char *mode)
148
{
196
{
149
    int flags;
197
    int flags;
150
    if (!parse_mode(mode, &flags))
198
    if (!parse_mode(mode, &flags))
151
        return NULL;
199
        return NULL;
152
   
200
   
153
    /* Open file. */
201
    /* Open file. */
154
    FILE *stream = malloc(sizeof(FILE));
202
    FILE *stream = malloc(sizeof(FILE));
155
    if (stream == NULL) {
203
    if (stream == NULL) {
156
        errno = ENOMEM;
204
        errno = ENOMEM;
157
        return NULL;
205
        return NULL;
158
    }
206
    }
159
   
207
   
160
    stream->fd = open_node(node, flags);
208
    stream->fd = open_node(node, flags);
161
    if (stream->fd < 0) {
209
    if (stream->fd < 0) {
162
        /* errno was set by open_node() */
210
        /* errno was set by open_node() */
163
        free(stream);
211
        free(stream);
164
        return NULL;
212
        return NULL;
165
    }
213
    }
166
   
214
   
167
    stream->error = false;
215
    stream->error = false;
168
    stream->eof = false;
216
    stream->eof = false;
169
    stream->klog = false;
217
    stream->klog = false;
170
    stream->phone = -1;
218
    stream->phone = -1;
171
   
219
   
-
 
220
    list_append(&stream->link, &files);
-
 
221
   
172
    return stream;
222
    return stream;
173
}
223
}
174
 
224
 
175
int fclose(FILE *stream)
225
int fclose(FILE *stream)
176
{
226
{
177
    int rc = 0;
227
    int rc = 0;
178
   
228
   
179
    fflush(stream);
229
    fflush(stream);
180
   
230
   
181
    if (stream->phone >= 0)
231
    if (stream->phone >= 0)
182
        ipc_hangup(stream->phone);
232
        ipc_hangup(stream->phone);
183
   
233
   
184
    if (stream->fd >= 0)
234
    if (stream->fd >= 0)
185
        rc = close(stream->fd);
235
        rc = close(stream->fd);
186
   
236
   
-
 
237
    list_remove(&stream->link);
-
 
238
   
-
 
239
    if ((stream != &stdin_null)
187
    if ((stream != &stdin_null) && (stream != &stdout_klog))
240
        && (stream != &stdout_klog)
-
 
241
        && (stream != &stderr_klog))
188
        free(stream);
242
        free(stream);
189
   
243
   
190
    stream = NULL;
244
    stream = NULL;
191
   
245
   
192
    if (rc != 0) {
246
    if (rc != 0) {
193
        /* errno was set by close() */
247
        /* errno was set by close() */
194
        return EOF;
248
        return EOF;
195
    }
249
    }
196
   
250
   
197
    return 0;
251
    return 0;
198
}
252
}
199
 
253
 
200
/** Read from a stream.
254
/** Read from a stream.
201
 *
255
 *
202
 * @param buf    Destination buffer.
256
 * @param buf    Destination buffer.
203
 * @param size   Size of each record.
257
 * @param size   Size of each record.
204
 * @param nmemb  Number of records to read.
258
 * @param nmemb  Number of records to read.
205
 * @param stream Pointer to the stream.
259
 * @param stream Pointer to the stream.
206
 *
260
 *
207
 */
261
 */
208
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
262
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
209
{
263
{
210
    size_t left = size * nmemb;
264
    size_t left = size * nmemb;
211
    size_t done = 0;
265
    size_t done = 0;
212
   
266
   
213
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
267
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
214
        ssize_t rd = read(stream->fd, buf + done, left);
268
        ssize_t rd = read(stream->fd, buf + done, left);
215
       
269
       
216
        if (rd < 0)
270
        if (rd < 0)
217
            stream->error = true;
271
            stream->error = true;
218
        else if (rd == 0)
272
        else if (rd == 0)
219
            stream->eof = true;
273
            stream->eof = true;
220
        else {
274
        else {
221
            left -= rd;
275
            left -= rd;
222
            done += rd;
276
            done += rd;
223
        }
277
        }
224
    }
278
    }
225
   
279
   
226
    return (done / size);
280
    return (done / size);
227
}
281
}
228
 
282
 
229
/** Write to a stream.
283
/** Write to a stream.
230
 *
284
 *
231
 * @param buf    Source buffer.
285
 * @param buf    Source buffer.
232
 * @param size   Size of each record.
286
 * @param size   Size of each record.
233
 * @param nmemb  Number of records to write.
287
 * @param nmemb  Number of records to write.
234
 * @param stream Pointer to the stream.
288
 * @param stream Pointer to the stream.
235
 *
289
 *
236
 */
290
 */
237
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
291
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
238
{
292
{
239
    size_t left = size * nmemb;
293
    size_t left = size * nmemb;
240
    size_t done = 0;
294
    size_t done = 0;
241
   
295
   
242
    while ((left > 0) && (!stream->error)) {
296
    while ((left > 0) && (!stream->error)) {
243
        ssize_t wr;
297
        ssize_t wr;
244
       
298
       
245
        if (stream->klog)
299
        if (stream->klog)
246
            wr = klog_write(buf + done, left);
300
            wr = klog_write(buf + done, left);
247
        else
301
        else
248
            wr = write(stream->fd, buf + done, left);
302
            wr = write(stream->fd, buf + done, left);
249
       
303
       
250
        if (wr <= 0)
304
        if (wr <= 0)
251
            stream->error = true;
305
            stream->error = true;
252
        else {
306
        else {
253
            left -= wr;
307
            left -= wr;
254
            done += wr;
308
            done += wr;
255
        }
309
        }
256
    }
310
    }
257
   
311
   
258
    return (done / size);
312
    return (done / size);
259
}
313
}
260
 
314
 
261
int fputc(wchar_t c, FILE *stream)
315
int fputc(wchar_t c, FILE *stream)
262
{
316
{
263
    char buf[STR_BOUNDS(1)];
317
    char buf[STR_BOUNDS(1)];
264
    size_t sz = 0;
318
    size_t sz = 0;
265
   
319
   
266
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
320
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
267
        size_t wr = fwrite(buf, sz, 1, stream);
321
        size_t wr = fwrite(buf, sz, 1, stream);
268
       
322
       
269
        if (wr < sz)
323
        if (wr < sz)
270
            return EOF;
324
            return EOF;
271
       
325
       
272
        return (int) c;
326
        return (int) c;
273
    }
327
    }
274
   
328
   
275
    return EOF;
329
    return EOF;
276
}
330
}
277
 
331
 
278
int putchar(wchar_t c)
332
int putchar(wchar_t c)
279
{
333
{
280
    return fputc(c, stdout);
334
    return fputc(c, stdout);
281
}
335
}
282
 
336
 
283
int fputs(const char *str, FILE *stream)
337
int fputs(const char *str, FILE *stream)
284
{
338
{
285
    return fwrite(str, str_size(str), 1, stream);
339
    return fwrite(str, str_size(str), 1, stream);
286
}
340
}
287
 
341
 
288
int puts(const char *str)
342
int puts(const char *str)
289
{
343
{
290
    return fputs(str, stdout);
344
    return fputs(str, stdout);
291
}
345
}
292
 
346
 
293
int fgetc(FILE *stream)
347
int fgetc(FILE *stream)
294
{
348
{
295
    char c;
349
    char c;
296
   
350
   
297
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
351
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
298
        return EOF;
352
        return EOF;
299
   
353
   
300
    return (int) c;
354
    return (int) c;
301
}
355
}
302
 
356
 
303
int getchar(void)
357
int getchar(void)
304
{
358
{
305
    return fgetc(stdin);
359
    return fgetc(stdin);
306
}
360
}
307
 
361
 
308
int fseek(FILE *stream, long offset, int origin)
362
int fseek(FILE *stream, long offset, int origin)
309
{
363
{
310
    off_t rc = lseek(stream->fd, offset, origin);
364
    off_t rc = lseek(stream->fd, offset, origin);
311
    if (rc == (off_t) (-1)) {
365
    if (rc == (off_t) (-1)) {
312
        /* errno has been set by lseek. */
366
        /* errno has been set by lseek. */
313
        return -1;
367
        return -1;
314
    }
368
    }
315
   
369
   
316
    stream->eof = false;
370
    stream->eof = false;
317
   
371
   
318
    return 0;
372
    return 0;
319
}
373
}
320
 
374
 
321
int fflush(FILE *stream)
375
int fflush(FILE *stream)
322
{
376
{
323
    if (stream->klog) {
377
    if (stream->klog) {
324
        klog_update();
378
        klog_update();
325
        return EOK;
379
        return EOK;
326
    }
380
    }
327
   
381
   
328
    if (stream->fd >= 0)
382
    if (stream->fd >= 0)
329
        return fsync(stream->fd);
383
        return fsync(stream->fd);
330
   
384
   
331
    return ENOENT;
385
    return ENOENT;
332
}
386
}
333
 
387
 
334
int feof(FILE *stream)
388
int feof(FILE *stream)
335
{
389
{
336
    return stream->eof;
390
    return stream->eof;
337
}
391
}
338
 
392
 
339
int ferror(FILE *stream)
393
int ferror(FILE *stream)
340
{
394
{
341
    return stream->error;
395
    return stream->error;
342
}
396
}
343
 
397
 
344
int fphone(FILE *stream)
398
int fphone(FILE *stream)
345
{
399
{
346
    if (stream->fd >= 0) {
400
    if (stream->fd >= 0) {
347
        if (stream->phone < 0)
401
        if (stream->phone < 0)
348
            stream->phone = fd_phone(stream->fd);
402
            stream->phone = fd_phone(stream->fd);
349
       
403
       
350
        return stream->phone;
404
        return stream->phone;
351
    }
405
    }
352
   
406
   
353
    return -1;
407
    return -1;
354
}
408
}
355
 
409
 
356
void fnode(FILE *stream, fdi_node_t *node)
410
int fnode(FILE *stream, fdi_node_t *node)
357
{
411
{
358
    if (stream->fd >= 0) {
412
    if (stream->fd >= 0)
359
        fd_node(stream->fd, node);
413
        return fd_node(stream->fd, node);
360
    } else {
-
 
361
        node->fs_handle = 0;
-
 
362
        node->dev_handle = 0;
-
 
363
        node->index = 0;
-
 
364
    }
414
   
-
 
415
    return ENOENT;
365
}
416
}
366
 
417
 
367
/** @}
418
/** @}
368
 */
419
 */
369
 
420