@@ -52,6 +52,25 @@ static void __init find_tempdir(void)
52
52
strcat (tempdir , "/" );
53
53
}
54
54
55
+ /*
56
+ * Remove bytes from the front of the buffer and refill it so that if there's a
57
+ * partial string that we care about, it will be completed, and we can recognize
58
+ * it.
59
+ */
60
+ static int pop (int fd , char * buf , size_t size , size_t npop )
61
+ {
62
+ ssize_t n ;
63
+ size_t len = strlen (& buf [npop ]);
64
+
65
+ memmove (buf , & buf [npop ], len + 1 );
66
+ n = read (fd , & buf [len ], size - len - 1 );
67
+ if (n < 0 )
68
+ return - errno ;
69
+
70
+ buf [len + n ] = '\0' ;
71
+ return 1 ;
72
+ }
73
+
55
74
/*
56
75
* This will return 1, with the first character in buf being the
57
76
* character following the next instance of c in the file. This will
@@ -61,7 +80,6 @@ static void __init find_tempdir(void)
61
80
static int next (int fd , char * buf , size_t size , char c )
62
81
{
63
82
ssize_t n ;
64
- size_t len ;
65
83
char * ptr ;
66
84
67
85
while ((ptr = strchr (buf , c )) == NULL ) {
@@ -74,20 +92,129 @@ static int next(int fd, char *buf, size_t size, char c)
74
92
buf [n ] = '\0' ;
75
93
}
76
94
77
- ptr ++ ;
78
- len = strlen (ptr );
79
- memmove (buf , ptr , len + 1 );
95
+ return pop (fd , buf , size , ptr - buf + 1 );
96
+ }
97
+
98
+ /*
99
+ * Decode an octal-escaped and space-terminated path of the form used by
100
+ * /proc/mounts. May be used to decode a path in-place. "out" must be at least
101
+ * as large as the input. The output is always null-terminated. "len" gets the
102
+ * length of the output, excluding the trailing null. Returns 0 if a full path
103
+ * was successfully decoded, otherwise an error.
104
+ */
105
+ static int decode_path (const char * in , char * out , size_t * len )
106
+ {
107
+ char * first = out ;
108
+ int c ;
109
+ int i ;
110
+ int ret = - EINVAL ;
111
+ while (1 ) {
112
+ switch (* in ) {
113
+ case '\0' :
114
+ goto out ;
115
+
116
+ case ' ' :
117
+ ret = 0 ;
118
+ goto out ;
119
+
120
+ case '\\' :
121
+ in ++ ;
122
+ c = 0 ;
123
+ for (i = 0 ; i < 3 ; i ++ ) {
124
+ if (* in < '0' || * in > '7' )
125
+ goto out ;
126
+ c = (c << 3 ) | (* in ++ - '0' );
127
+ }
128
+ * (unsigned char * )out ++ = (unsigned char ) c ;
129
+ break ;
130
+
131
+ default :
132
+ * out ++ = * in ++ ;
133
+ break ;
134
+ }
135
+ }
136
+
137
+ out :
138
+ * out = '\0' ;
139
+ * len = out - first ;
140
+ return ret ;
141
+ }
142
+
143
+ /*
144
+ * Computes the length of s when encoded with three-digit octal escape sequences
145
+ * for the characters in chars.
146
+ */
147
+ static size_t octal_encoded_length (const char * s , const char * chars )
148
+ {
149
+ size_t len = strlen (s );
150
+ while ((s = strpbrk (s , chars )) != NULL ) {
151
+ len += 3 ;
152
+ s ++ ;
153
+ }
154
+
155
+ return len ;
156
+ }
157
+
158
+ enum {
159
+ OUTCOME_NOTHING_MOUNTED ,
160
+ OUTCOME_TMPFS_MOUNT ,
161
+ OUTCOME_NON_TMPFS_MOUNT ,
162
+ };
163
+
164
+ /* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
165
+ static int read_mount (int fd , char * buf , size_t bufsize , const char * path ,
166
+ int * outcome )
167
+ {
168
+ int found ;
169
+ int match ;
170
+ char * space ;
171
+ size_t len ;
172
+
173
+ enum {
174
+ MATCH_NONE ,
175
+ MATCH_EXACT ,
176
+ MATCH_PARENT ,
177
+ };
178
+
179
+ found = next (fd , buf , bufsize , ' ' );
180
+ if (found != 1 )
181
+ return found ;
80
182
81
183
/*
82
- * Refill the buffer so that if there's a partial string that we care
83
- * about, it will be completed, and we can recognize it .
184
+ * If there's no following space in the buffer, then this path is
185
+ * truncated, so it can't be the one we're looking for .
84
186
*/
85
- n = read (fd , & buf [len ], size - len - 1 );
86
- if (n < 0 )
87
- return - errno ;
187
+ space = strchr (buf , ' ' );
188
+ if (space ) {
189
+ match = MATCH_NONE ;
190
+ if (!decode_path (buf , buf , & len )) {
191
+ if (!strcmp (buf , path ))
192
+ match = MATCH_EXACT ;
193
+ else if (!strncmp (buf , path , len )
194
+ && (path [len ] == '/' || !strcmp (buf , "/" )))
195
+ match = MATCH_PARENT ;
196
+ }
197
+
198
+ found = pop (fd , buf , bufsize , space - buf + 1 );
199
+ if (found != 1 )
200
+ return found ;
201
+
202
+ switch (match ) {
203
+ case MATCH_EXACT :
204
+ if (!strncmp (buf , "tmpfs" , strlen ("tmpfs" )))
205
+ * outcome = OUTCOME_TMPFS_MOUNT ;
206
+ else
207
+ * outcome = OUTCOME_NON_TMPFS_MOUNT ;
208
+ break ;
88
209
89
- buf [len + n ] = '\0' ;
90
- return 1 ;
210
+ case MATCH_PARENT :
211
+ /* This mount obscures any previous ones. */
212
+ * outcome = OUTCOME_NOTHING_MOUNTED ;
213
+ break ;
214
+ }
215
+ }
216
+
217
+ return next (fd , buf , bufsize , '\n' );
91
218
}
92
219
93
220
/* which_tmpdir is called only during early boot */
@@ -106,8 +233,12 @@ static int checked_tmpdir = 0;
106
233
*/
107
234
static void which_tmpdir (void )
108
235
{
109
- int fd , found ;
110
- char buf [128 ] = { '\0' };
236
+ int fd ;
237
+ int found ;
238
+ int outcome ;
239
+ char * path ;
240
+ char * buf ;
241
+ size_t bufsize ;
111
242
112
243
if (checked_tmpdir )
113
244
return ;
@@ -116,49 +247,66 @@ static void which_tmpdir(void)
116
247
117
248
printf ("Checking for tmpfs mount on /dev/shm..." );
118
249
250
+ path = realpath ("/dev/shm" , NULL );
251
+ if (!path ) {
252
+ printf ("failed to check real path, errno = %d\n" , errno );
253
+ return ;
254
+ }
255
+ printf ("%s..." , path );
256
+
257
+ /*
258
+ * The buffer needs to be able to fit the full octal-escaped path, a
259
+ * space, and a trailing null in order to successfully decode it.
260
+ */
261
+ bufsize = octal_encoded_length (path , " \t\n\\" ) + 2 ;
262
+
263
+ if (bufsize < 128 )
264
+ bufsize = 128 ;
265
+
266
+ buf = malloc (bufsize );
267
+ if (!buf ) {
268
+ printf ("malloc failed, errno = %d\n" , errno );
269
+ goto out ;
270
+ }
271
+ buf [0 ] = '\0' ;
272
+
119
273
fd = open ("/proc/mounts" , O_RDONLY );
120
274
if (fd < 0 ) {
121
275
printf ("failed to open /proc/mounts, errno = %d\n" , errno );
122
- return ;
276
+ goto out1 ;
123
277
}
124
278
279
+ outcome = OUTCOME_NOTHING_MOUNTED ;
125
280
while (1 ) {
126
- found = next (fd , buf , ARRAY_SIZE (buf ), ' ' );
127
- if (found != 1 )
128
- break ;
129
-
130
- if (!strncmp (buf , "/dev/shm" , strlen ("/dev/shm" )))
131
- goto found ;
132
-
133
- found = next (fd , buf , ARRAY_SIZE (buf ), '\n' );
281
+ found = read_mount (fd , buf , bufsize , path , & outcome );
134
282
if (found != 1 )
135
283
break ;
136
284
}
137
285
138
- err :
139
- if (found == 0 )
140
- printf ("nothing mounted on /dev/shm\n" );
141
- else if (found < 0 )
286
+ if (found < 0 ) {
142
287
printf ("read returned errno %d\n" , - found );
288
+ } else {
289
+ switch (outcome ) {
290
+ case OUTCOME_TMPFS_MOUNT :
291
+ printf ("OK\n" );
292
+ default_tmpdir = "/dev/shm" ;
293
+ break ;
143
294
144
- out :
145
- close (fd );
146
-
147
- return ;
148
-
149
- found :
150
- found = next (fd , buf , ARRAY_SIZE (buf ), ' ' );
151
- if (found != 1 )
152
- goto err ;
295
+ case OUTCOME_NON_TMPFS_MOUNT :
296
+ printf ("not tmpfs\n" );
297
+ break ;
153
298
154
- if (strncmp (buf , "tmpfs" , strlen ("tmpfs" ))) {
155
- printf ("not tmpfs\n" );
156
- goto out ;
299
+ default :
300
+ printf ("nothing mounted on /dev/shm\n" );
301
+ break ;
302
+ }
157
303
}
158
304
159
- printf ("OK\n" );
160
- default_tmpdir = "/dev/shm" ;
161
- goto out ;
305
+ close (fd );
306
+ out1 :
307
+ free (buf );
308
+ out :
309
+ free (path );
162
310
}
163
311
164
312
static int __init make_tempfile (const char * template , char * * out_tempname ,
0 commit comments