Fdisk needs to unmount partition before trying to delete it
[helenos.git] / uspace / lib / posix / src / stdio.c
blobe67afd0f0d1f408bb752c648c800b050b93fd684
1 /*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * Copyright (c) 2011 Petr Koupy
4 * Copyright (c) 2018 Jiri Svoboda
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 /** @addtogroup libposix
32 * @{
34 /** @file Standard buffered input/output.
37 #define _LARGEFILE64_SOURCE
38 #undef _FILE_OFFSET_BITS
40 #include "internal/common.h"
41 #include <stdio.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <stdbool.h>
46 #include <tmpfile.h>
48 #include <fcntl.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sys/stat.h>
52 #include <sys/types.h>
53 #include <unistd.h>
55 #include <printf_core.h>
56 #include <str.h>
57 #include <stdlib.h>
58 #include <adt/list.h>
60 /**
61 * Generate a pathname for the controlling terminal.
63 * @param s Allocated buffer to which the pathname shall be put.
64 * @return Either s or static location filled with the requested pathname.
66 char *ctermid(char *s)
68 /* Currently always returns an error value (empty string). */
69 // TODO: return a real terminal path
71 static char dummy_path[L_ctermid] = { '\0' };
73 if (s == NULL) {
74 return dummy_path;
77 s[0] = '\0';
78 return s;
81 /**
82 * Read a stream until the delimiter (or EOF) is encountered.
84 * @param lineptr Pointer to the output buffer in which there will be stored
85 * nul-terminated string together with the delimiter (if encountered).
86 * Will be resized if necessary.
87 * @param n Pointer to the size of the output buffer. Will be increased if
88 * necessary.
89 * @param delimiter Delimiter on which to finish reading the stream.
90 * @param stream Input stream.
91 * @return Number of fetched characters (including delimiter if encountered)
92 * or -1 on error (set in errno).
94 ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
95 int delimiter, FILE *restrict stream)
97 /* Check arguments for sanity. */
98 if (!lineptr || !n) {
99 errno = EINVAL;
100 return -1;
103 size_t alloc_step = 80; /* Buffer size gain during reallocation. */
104 char *pos = *lineptr; /* Next free byte of the output buffer. */
105 size_t cnt = 0; /* Number of fetched characters. */
106 int c = fgetc(stream); /* Current input character. Might be EOF. */
108 do {
109 /* Mask EOF as NUL to terminate string. */
110 if (c == EOF) {
111 c = '\0';
114 /* Ensure there is still space left in the buffer. */
115 if (pos == *lineptr + *n) {
116 *lineptr = realloc(*lineptr, *n + alloc_step);
117 if (*lineptr) {
118 pos = *lineptr + *n;
119 *n += alloc_step;
120 } else {
121 errno = ENOMEM;
122 return -1;
126 /* Store the fetched character. */
127 *pos = c;
129 /* Fetch the next character according to the current character. */
130 if (c != '\0') {
131 ++pos;
132 ++cnt;
133 if (c == delimiter) {
135 * Delimiter was just stored. Provide EOF as the next
136 * character - it will be masked as NUL and output string
137 * will be properly terminated.
139 c = EOF;
140 } else {
142 * Neither delimiter nor EOF were encountered. Just fetch
143 * the next character from the stream.
145 c = fgetc(stream);
148 } while (c != '\0');
150 if (errno == EOK && cnt > 0) {
151 return cnt;
152 } else {
153 /* Either some error occured or the stream was already at EOF. */
154 return -1;
159 * Read a stream until the newline (or EOF) is encountered.
161 * @param lineptr Pointer to the output buffer in which there will be stored
162 * nul-terminated string together with the delimiter (if encountered).
163 * Will be resized if necessary.
164 * @param n Pointer to the size of the output buffer. Will be increased if
165 * necessary.
166 * @param stream Input stream.
167 * @return Number of fetched characters (including newline if encountered)
168 * or -1 on error (set in errno).
170 ssize_t getline(char **restrict lineptr, size_t *restrict n,
171 FILE *restrict stream)
173 return getdelim(lineptr, n, '\n', stream);
177 * Reposition a file-position indicator in a stream.
179 * @param stream Stream to seek in.
180 * @param offset Direction and amount of bytes to seek.
181 * @param whence From where to seek.
182 * @return Zero on success, -1 otherwise.
184 int fseeko(FILE *stream, off_t offset, int whence)
186 return fseek(stream, offset, whence);
190 * Discover current file offset in a stream.
192 * @param stream Stream for which the offset shall be retrieved.
193 * @return Current offset or -1 if not possible.
195 off_t ftello(FILE *stream)
197 return ftell(stream);
200 int fseeko64(FILE *stream, off64_t offset, int whence)
202 return fseek64(stream, offset, whence);
205 off64_t ftello64(FILE *stream)
207 return ftell64(stream);
211 * Print formatted output to the opened file.
213 * @param fildes File descriptor of the opened file.
214 * @param format Format description.
215 * @return Either the number of printed characters or negative value on error.
217 int dprintf(int fildes, const char *restrict format, ...)
219 va_list list;
220 va_start(list, format);
221 int result = vdprintf(fildes, format, list);
222 va_end(list);
223 return result;
227 * Write ordinary string to the opened file.
229 * @param str String to be written.
230 * @param size Size of the string (in bytes)..
231 * @param fd File descriptor of the opened file.
232 * @return The number of written characters.
234 static int _dprintf_str_write(const char *str, size_t size, void *fd)
236 const int fildes = *(int *) fd;
237 size_t wr;
238 if (failed(vfs_write(fildes, &posix_pos[fildes], str, size, &wr)))
239 return -1;
240 return str_nlength(str, wr);
244 * Write wide string to the opened file.
246 * @param str String to be written.
247 * @param size Size of the string (in bytes).
248 * @param fd File descriptor of the opened file.
249 * @return The number of written characters.
251 static int _dprintf_wstr_write(const char32_t *str, size_t size, void *fd)
253 size_t offset = 0;
254 size_t chars = 0;
255 size_t sz;
256 char buf[4];
258 while (offset < size) {
259 sz = 0;
260 if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
261 break;
264 const int fildes = *(int *) fd;
265 size_t nwr;
266 if (vfs_write(fildes, &posix_pos[fildes], buf, sz, &nwr) != EOK)
267 break;
269 chars++;
270 offset += sizeof(char32_t);
273 return chars;
277 * Print formatted output to the opened file.
279 * @param fildes File descriptor of the opened file.
280 * @param format Format description.
281 * @param ap Print arguments.
282 * @return Either the number of printed characters or negative value on error.
284 int vdprintf(int fildes, const char *restrict format, va_list ap)
286 printf_spec_t spec = {
287 .str_write = _dprintf_str_write,
288 .wstr_write = _dprintf_wstr_write,
289 .data = &fildes
292 return printf_core(format, &spec, ap);
296 * Acquire file stream for the thread.
298 * @param file File stream to lock.
300 void flockfile(FILE *file)
302 /* dummy */
306 * Acquire file stream for the thread (non-blocking).
308 * @param file File stream to lock.
309 * @return Zero for success and non-zero if the lock cannot be acquired.
311 int ftrylockfile(FILE *file)
313 /* dummy */
314 return 0;
318 * Relinquish the ownership of the locked file stream.
320 * @param file File stream to unlock.
322 void funlockfile(FILE *file)
324 /* dummy */
328 * Get a byte from a stream (thread-unsafe).
330 * @param stream Input file stream.
331 * @return Either read byte or EOF.
333 int getc_unlocked(FILE *stream)
335 return getc(stream);
339 * Get a byte from the standard input stream (thread-unsafe).
341 * @return Either read byte or EOF.
343 int getchar_unlocked(void)
345 return getchar();
349 * Put a byte on a stream (thread-unsafe).
351 * @param c Byte to output.
352 * @param stream Output file stream.
353 * @return Either written byte or EOF.
355 int putc_unlocked(int c, FILE *stream)
357 return putc(c, stream);
361 * Put a byte on the standard output stream (thread-unsafe).
363 * @param c Byte to output.
364 * @return Either written byte or EOF.
366 int putchar_unlocked(int c)
368 return putchar(c);
371 /** Determine if directory is an 'appropriate' temporary directory.
373 * @param dir Directory path
374 * @return @c true iff directory is appropriate.
376 static bool is_appropriate_tmpdir(const char *dir)
378 struct stat sbuf;
380 /* Must not be NULL */
381 if (dir == NULL)
382 return false;
384 /* Must not be empty */
385 if (dir[0] == '\0')
386 return false;
388 if (stat(dir, &sbuf) != 0)
389 return false;
391 /* Must be a directory */
392 if ((sbuf.st_mode & S_IFMT) != S_IFDIR)
393 return false;
395 /* Must be writable */
396 if (access(dir, W_OK) != 0)
397 return false;
399 return true;
402 /** Construct unique file name.
404 * Never use this function.
406 * @param dir Path to directory, where the file should be created.
407 * @param pfx Optional prefix up to 5 characters long.
408 * @return Newly allocated unique path for temporary file. NULL on failure.
410 char *tempnam(const char *dir, const char *pfx)
412 const char *dpref;
413 char *d;
414 char *buf;
415 int rc;
417 d = getenv("TMPDIR");
418 if (is_appropriate_tmpdir(d))
419 dpref = d;
420 else if (is_appropriate_tmpdir(dir))
421 dpref = dir;
422 else if (is_appropriate_tmpdir(P_tmpdir))
423 dpref = P_tmpdir;
424 else
425 dpref = "/";
427 if (dpref[strlen(dpref) - 1] != '/')
428 rc = asprintf(&buf, "%s/%sXXXXXX", dpref, pfx);
429 else
430 rc = asprintf(&buf, "%s%sXXXXXX", dpref, pfx);
432 if (rc < 0)
433 return NULL;
435 rc = __tmpfile_templ(buf, false);
436 if (rc != 0) {
437 free(buf);
438 return NULL;
441 return buf;
444 /** @}