]> git.proxmox.com Git - mirror_lxc.git/blob - src/include/lxcmntent.c
lxcmntent: coding rules
[mirror_lxc.git] / src / include / lxcmntent.c
1 /* Utilities for reading/writing fstab, mtab, etc.
2 * Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
3 * Free Software Foundation, Inc.
4 * This file is part of the GNU C Library.
5 *
6 * The GNU C Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * The GNU C Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE 1
23 #endif
24 #include <alloca.h>
25 #include <macro.h>
26 #include <mntent.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 /* Since the values in a line are separated by spaces, a name cannot
31 * contain a space. Therefore some programs encode spaces in names
32 * by the strings "\040". We undo the encoding when reading an entry.
33 * The decoding happens in place.
34 */
35 static char *decode_name(char *buf)
36 {
37 char *rp = buf;
38 char *wp = buf;
39
40 do {
41 if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' &&
42 rp[3] == '0') {
43 /* \040 is a SPACE. */
44 *wp++ = ' ';
45 rp += 3;
46 } else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' &&
47 rp[3] == '1') {
48 /* \011 is a TAB. */
49 *wp++ = '\t';
50 rp += 3;
51 } else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' &&
52 rp[3] == '2') {
53 /* \012 is a NEWLINE. */
54 *wp++ = '\n';
55 rp += 3;
56 } else if (rp[0] == '\\' && rp[1] == '\\') {
57 /* We have to escape \\ to be able to represent all characters. */
58 *wp++ = '\\';
59 rp += 1;
60 } else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' &&
61 rp[3] == '4') {
62 /* \134 is also \\. */
63 *wp++ = '\\';
64 rp += 3;
65 } else {
66 *wp++ = *rp;
67 }
68 } while (*rp++ != '\0');
69
70 return buf;
71 }
72
73 /* Read one mount table entry from STREAM. Returns a pointer to storage
74 * reused on the next call, or null for EOF or error (use feof/ferror to check).
75 */
76 struct mntent *getmntent_r(FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
77 {
78 char *cp;
79 char *head;
80
81 do {
82 char *end_ptr;
83
84 if (!fgets(buffer, bufsiz, stream))
85 return NULL;
86
87 end_ptr = strchr(buffer, '\n');
88 if (end_ptr != NULL) {
89 /* chop newline */
90 *end_ptr = '\0';
91 } else {
92 /* Not the whole line was read. Do it now but forget it. */
93 char tmp[1024] = {0};
94
95 while (fgets(tmp, sizeof tmp, stream))
96 if (strchr(tmp, '\n') != NULL)
97 break;
98 }
99
100 head = buffer + strspn(buffer, " \t");
101 /* skip empty lines and comment lines: */
102 } while (head[0] == '\0' || head[0] == '#');
103
104 cp = strsep(&head, " \t");
105 mp->mnt_fsname = cp ? decode_name(cp) : (char *)"";
106 if (head)
107 head += strspn(head, " \t");
108
109 cp = strsep(&head, " \t");
110 mp->mnt_dir = cp ? decode_name(cp) : (char *)"";
111 if (head)
112 head += strspn(head, " \t");
113
114 cp = strsep(&head, " \t");
115 mp->mnt_type = cp ? decode_name(cp) : (char *)"";
116 if (head)
117 head += strspn(head, " \t");
118
119 cp = strsep(&head, " \t");
120 mp->mnt_opts = cp ? decode_name(cp) : (char *)"";
121 if (head) {
122 int ret = sscanf(head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno);
123
124 switch (ret) {
125 case 0:
126 mp->mnt_freq = 0;
127 case 1:
128 mp->mnt_passno = 0;
129 case 2:
130 break;
131 }
132 } else {
133 mp->mnt_freq = 0;
134 }
135
136 return mp;
137 }
138
139 struct mntent *getmntent(FILE *stream)
140 {
141 static struct mntent m;
142 static char *getmntent_buffer;
143
144 if (!getmntent_buffer) {
145 getmntent_buffer = (char *)malloc(LXC_MAX_BUFFER);
146 if (!getmntent_buffer)
147 return NULL;
148 }
149
150 return getmntent_r(stream, &m, getmntent_buffer, LXC_MAX_BUFFER);
151 }
152
153 /* Prepare to begin reading and/or writing mount table entries from the
154 * beginning of FILE. MODE is as for `fopen'.
155 */
156 FILE *setmntent(const char *file, const char *mode)
157 {
158 /* Extend the mode parameter with "c" to disable cancellation in the
159 * I/O functions and "e" to set FD_CLOEXEC.
160 */
161 size_t modelen = strlen(mode);
162 char *newmode;
163
164 newmode = alloca(modelen + 3);
165
166 memcpy(newmode, mode, modelen);
167 memcpy(newmode + modelen, "ce", 3);
168
169 return fopen (file, newmode);
170 }
171
172 /* Close a stream opened with `setmntent'. */
173 int endmntent(FILE *stream)
174 {
175 /* SunOS 4.x allows for NULL stream */
176 if (stream)
177 fclose(stream);
178
179 /* SunOS 4.x says to always return 1 */
180 return 1;
181 }
182
183 /* Search MNT->mnt_opts for an option matching OPT.
184 * Returns the address of the substring, or null if none found.
185 */
186 char *hasmntopt(const struct mntent *mnt, const char *opt)
187 {
188 const size_t optlen = strlen(opt);
189 char *rest = mnt->mnt_opts, *p;
190
191 while ((p = strstr(rest, opt))) {
192 if ((p == rest || p[-1] == ',') &&
193 (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
194 return p;
195
196 rest = strchr(p, ',');
197 if (!rest)
198 break;
199
200 ++rest;
201 }
202
203 return NULL;
204 }