Bug Summary

File:obj-scan-build/ftpfs/../../ftpfs/ftpfs.c
Location:line 244, column 20
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/* Ftp filesystem
2
3 Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
4 Written by Miles Bader <miles@gnu.org>
5 This file is part of the GNU Hurd.
6
7 The GNU Hurd is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 The GNU Hurd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
20
21#include <string.h>
22#include <unistd.h>
23#include <argp.h>
24#include <error.h>
25#include <argz.h>
26#include <netdb.h>
27#include <sys/stat.h>
28
29#include <version.h>
30
31#include <hurd/netfs.h>
32
33#include "ftpfs.h"
34
35char *netfs_server_name = "ftpfs";
36char *netfs_server_version = HURD_VERSION"0.5";
37
38const char *argp_program_version = STANDARD_HURD_VERSION (ftpfs)"ftpfs" " (GNU Hurd) " "0.5";
39
40static char *args_doc = "REMOTE_FS [SERVER]";
41static char *doc = "Hurd ftp filesystem translator."
42"\vIf SERVER is not specified, an attempt is made to extract"
43" it from REMOTE_FS, using `SERVER:FS' notation."
44" SERVER can be a hostname, in which case anonymous ftp is used,"
45" or may include a user and password like `USER:PASSWORD@HOST' (the"
46" `:PASSWORD' part is optional).";
47
48/* The filesystem. */
49struct ftpfs *ftpfs;
50
51/* Parameters describing the server we're connecting to. */
52struct ftp_conn_params *ftpfs_ftp_params = 0;
53
54/* customization hooks. */
55struct ftp_conn_hooks ftpfs_ftp_hooks = { interrupt_check: ports_self_interrupted };
56
57/* The (user-specified) name of the SERVER:FILESYSTEM we're connected too. */
58char *ftpfs_remote_fs;
59
60/* The FILESYSTEM component of FTPFS_REMOTE_FS. */
61char *ftpfs_remote_root;
62
63/* Random parameters for the filesystem. */
64struct ftpfs_params ftpfs_params;
65
66volatile struct mapped_time_value *ftpfs_maptime;
67
68int netfs_maxsymlinks = 12;
69
70extern error_t lookup_server (const char *server,
71 struct ftp_conn_params **params, int *h_err);
72
73static FILE *debug_stream = 0;
74static char *debug_stream_name = 0;
75static pthread_mutex_t debug_lock = PTHREAD_MUTEX_INITIALIZER{ ((__pthread_spinlock_t) 0), ((__pthread_spinlock_t) 0), 0, 0
, 0, 0, 0, 0 }
;
76
77/* Prints ftp connection log to DEBUG_STREAM. */
78static void
79cntl_debug (struct ftp_conn *conn, int type, const char *txt)
80{
81 char *type_str;
82
83 switch (type)
84 {
85 case FTP_CONN_CNTL_DEBUG_CMD1: type_str = ">"; break;
86 case FTP_CONN_CNTL_DEBUG_REPLY2: type_str = "="; break;
87 default: type_str = "?"; break;
88 }
89
90 pthread_mutex_lock (&debug_lock);
91 if (debug_stream)
92 {
93 fprintf (debug_stream, "%u.%s%s\n",
94 (unsigned)(uintptr_t)conn->hook, type_str, txt);
95 fflush (debug_stream);
96 }
97 pthread_mutex_unlock (&debug_lock);
98}
99
100/* Various default parameters. */
101#define DEFAULT_NAME_TIMEOUT300 300
102#define DEFAULT_STAT_TIMEOUT120 120
103
104#define DEFAULT_BULK_STAT_PERIOD10 10
105#define DEFAULT_BULK_STAT_THRESHOLD5 5
106
107#define DEFAULT_NODE_CACHE_MAX50 50
108
109/* Return a string corresponding to the printed rep of DEFAULT_what */
110#define ___D(what)"what" #what
111#define __D(what)"what" ___D(what)"what"
112#define _D(what)"DEFAULT_what" __D(DEFAULT_ ## what)"DEFAULT_ ## what"
113
114/* Common (runtime & startup) options. */
115
116#define OPT_NO_DEBUG1 1
117
118#define OPT_NAME_TIMEOUT5 5
119#define OPT_STAT_TIMEOUT7 7
120#define OPT_NODE_CACHE_MAX8 8
121#define OPT_BULK_STAT_PERIOD9 9
122#define OPT_BULK_STAT_THRESHOLD10 10
123
124/* Options usable both at startup and at runtime. */
125static const struct argp_option common_options[] =
126{
127 {"debug", 'D', "FILE", OPTION_ARG_OPTIONAL0x1, "Print debug output to FILE"},
128 {"no-debug", OPT_NO_DEBUG1, 0, OPTION_HIDDEN0x2 },
129
130 {0,0,0,0, "Parameters:"},
131 {"name-timeout", OPT_NAME_TIMEOUT5, "SECS", 0,
132 "Time directory names are cached (default " _D(NAME_TIMEOUT)"300" ")"},
133 {"stat-timeout", OPT_STAT_TIMEOUT7, "SECS", 0,
134 "Time stat information is cached (default " _D(STAT_TIMEOUT)"120" ")"},
135 {"node-cache-size", OPT_NODE_CACHE_MAX8, "ENTRIES", 0,
136 "Number of recently used filesystem nodes that are cached (default "
137 _D(NODE_CACHE_MAX)"50" ")"},
138
139 {"bulk-stat-period", OPT_BULK_STAT_PERIOD9, "SECS", 0,
140 "Period for detecting bulk stats (default " _D(BULK_STAT_PERIOD)"10" ")"},
141 {"bulk-stat-threshold", OPT_BULK_STAT_THRESHOLD10, "SECS", 0,
142 "Number of stats within the bulk-stat-period that trigger a bulk stat"
143 " (default " _D(BULK_STAT_THRESHOLD)"5" ")"},
144
145 {0, 0}
146};
147
148static error_t
149parse_common_opt (int key, char *arg, struct argp_state *state)
150{
151 error_t err = 0;
152 struct ftpfs_params *params = state->input;
153
154 switch (key)
155 {
156 case 'D':
157 pthread_mutex_lock (&debug_lock);
158
159 if (debug_stream && debug_stream != stderrstderr)
160 fclose (debug_stream);
161 if (debug_stream_name)
162 {
163 free (debug_stream_name);
164 debug_stream_name = 0;
165 }
166
167 if (arg)
168 {
169 debug_stream_name = strdup (arg);
170 if (! debug_stream_name)
171 {
172 argp_failure (state, 0, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s: Cannot open debugging file", arg);
173 err = ENOMEM((0x10 << 26) | ((12) & 0x3fff));
174 }
175
176 if (! err)
177 {
178 debug_stream = fopen (arg, "w+");
179 if (! debug_stream)
180 {
181 err = errno(*__errno_location ());
182 argp_failure (state, 0, err, "%s: Cannot open debugging file", arg);
183 }
184 }
185 }
186 else
187 debug_stream = stderrstderr;
188
189 if (! err)
190 ftpfs_ftp_hooks.cntl_debug = cntl_debug;
191
192 pthread_mutex_unlock (&debug_lock);
193
194 return err;
195
196 case OPT_NO_DEBUG1:
197 pthread_mutex_lock (&debug_lock);
198 if (debug_stream && debug_stream != stderrstderr)
199 fclose (debug_stream);
200 ftpfs_ftp_hooks.cntl_debug = 0;
201 pthread_mutex_unlock (&debug_lock);
202 break;
203
204 case OPT_NODE_CACHE_MAX8:
205 params->node_cache_max = atoi (arg); break;
206 case OPT_NAME_TIMEOUT5:
207 params->name_timeout = atoi (arg); break;
208 case OPT_STAT_TIMEOUT7:
209 params->stat_timeout = atoi (arg); break;
210 default:
211 return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff));
212 }
213
214 return 0;
215}
216
217static struct argp common_argp = { common_options, parse_common_opt };
218
219/* Startup options. */
220
221static const struct argp_option startup_options[] =
222{
223 { 0 }
224};
225
226/* Parse a single command line option/argument. */
227static error_t
228parse_startup_opt (int key, char *arg, struct argp_state *state)
229{
230 switch (key)
1
Control jumps to 'case 0:' at line 232
231 {
232 case ARGP_KEY_ARG0:
233 if (state->arg_num > 1)
2
Taking false branch
234 argp_usage (state);
235 else if (state->arg_num == 0)
3
Taking false branch
236 ftpfs_remote_fs = arg;
237 else
238 /* If the fs & server are two separate args, glom them together into the
239 ":" notation. */
240 {
241 char *rfs = malloc (strlen (ftpfs_remote_fs) + 1 + strlen (arg) + 1);
4
Variable 'rfs' initialized here
242 if (! rfs)
5
Assuming 'rfs' is null
6
Taking true branch
243 argp_failure (state, 99, ENOMEM((0x10 << 26) | ((12) & 0x3fff)), "%s", arg);
244 stpcpy (stpcpy (stpcpy (rfs, arg), ":"), ftpfs_remote_fs);
7
Null pointer passed as an argument to a 'nonnull' parameter
245 ftpfs_remote_fs = rfs;
246 }
247 break;
248
249 case ARGP_KEY_SUCCESS0x1000004:
250 /* Validate the remote fs arg; at this point FTPFS_REMOTE_FS is in
251 SERVER:FS notation. */
252 if (state->arg_num == 0)
253 argp_error (state, "No remote filesystem specified");
254 else
255 {
256 int h_err; /* Host lookup error. */
257 error_t err;
258 char *sep = strrchr (ftpfs_remote_fs, '@');
259
260 if (sep)
261 /* FTPFS_REMOTE_FS includes a '@', which means that it's in
262 USER[:PASS]@HOST:FS notation, so we have to be careful not to
263 choose the wrong `:' as the SERVER-FS separator. */
264 sep = strchr (sep, ':');
265 else
266 sep = strchr (ftpfs_remote_fs, ':');
267
268 if (! sep)
269 /* We have just a host name, so treat it as "HOST:/". */
270 ftpfs_remote_root = "/";
271 else
272 ftpfs_remote_root = sep + 1;
273
274 /* Lookup the ftp server (the part before the `:'). */
275 if (sep)
276 *sep = '\0';
277 err = lookup_server (ftpfs_remote_fs, &ftpfs_ftp_params, &h_err);
278 if (err == EINVAL((0x10 << 26) | ((22) & 0x3fff)))
279 argp_failure (state, 10, 0, "%s: %s",
280 ftpfs_remote_fs, hstrerror (h_err));
281 else if (err)
282 argp_failure (state, 11, err, "%s", ftpfs_remote_fs);
283 if (sep)
284 *sep = ':';
285 }
286
287 case ARGP_KEY_INIT0x1000003:
288 /* Setup up state for our first child parser (common options). */
289 state->child_inputs[0] = &ftpfs_params;
290 break;
291
292 default:
293 return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff));
294 }
295
296 return 0;
297}
298
299/* Runtime options. */
300
301/* Parse a single command line option/argument. */
302static error_t
303parse_runtime_opt (int key, char *arg, struct argp_state *state)
304{
305 if (key == ARGP_KEY_INIT0x1000003)
306 /* Setup up state for our first child parser (common options). */
307 {
308 state->child_inputs[0] = &ftpfs->params;
309 return 0;
310 }
311 else
312 return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff));
313}
314
315static const struct argp_child runtime_argp_children[] =
316 { {&common_argp}, {&netfs_std_runtime_argp}, {0} };
317static struct argp runtime_argp =
318 { 0, parse_runtime_opt, 0, 0, runtime_argp_children };
319
320/* Use by netfs_set_options to handle runtime option parsing. */
321struct argp *netfs_runtime_argp = &runtime_argp;
322
323/* Return an argz string describing the current options. Fill *ARGZ
324 with a pointer to newly malloced storage holding the list and *LEN
325 to the length of that storage. */
326error_t
327netfs_append_args (char **argz, size_t *argz_len)
328{
329 char buf[80];
330 error_t err = 0;
331
332#define FOPT(fmt, arg)do { if (! err) { snprintf (buf, sizeof buf, fmt, arg); err =
argz_add (argz, argz_len, buf); } } while (0)
\
333 do { \
334 if (! err) \
335 { \
336 snprintf (buf, sizeof buf, fmt, arg); \
337 err = argz_add (argz, argz_len, buf); \
338 } \
339 } while (0)
340
341 pthread_mutex_lock (&debug_lock);
342 if (ftpfs_ftp_hooks.cntl_debug && debug_stream)
343 {
344 if (debug_stream != stderrstderr)
345 {
346 char *rep;
347 asprintf (&rep, "--debug=%s", debug_stream_name);
348 err = argz_add (argz, argz_len, rep);
349 free (rep);
350 }
351 else
352 err = argz_add (argz, argz_len, "--debug");
353 }
354 pthread_mutex_unlock (&debug_lock);
355
356 if (ftpfs->params.name_timeout != DEFAULT_NAME_TIMEOUT300)
357 FOPT ("--name-timeout=%ld", ftpfs->params.name_timeout)do { if (! err) { snprintf (buf, sizeof buf, "--name-timeout=%ld"
, ftpfs->params.name_timeout); err = argz_add (argz, argz_len
, buf); } } while (0)
;
358 if (ftpfs->params.stat_timeout != DEFAULT_STAT_TIMEOUT120)
359 FOPT ("--stat-timeout=%ld", ftpfs->params.stat_timeout)do { if (! err) { snprintf (buf, sizeof buf, "--stat-timeout=%ld"
, ftpfs->params.stat_timeout); err = argz_add (argz, argz_len
, buf); } } while (0)
;
360 if (ftpfs->params.node_cache_max != DEFAULT_NODE_CACHE_MAX50)
361 FOPT ("--node-cache-size=%Zu", ftpfs->params.node_cache_max)do { if (! err) { snprintf (buf, sizeof buf, "--node-cache-size=%Zu"
, ftpfs->params.node_cache_max); err = argz_add (argz, argz_len
, buf); } } while (0)
;
362 if (ftpfs->params.bulk_stat_period != DEFAULT_BULK_STAT_PERIOD10)
363 FOPT ("--bulk-stat-period=%ld", ftpfs->params.bulk_stat_period)do { if (! err) { snprintf (buf, sizeof buf, "--bulk-stat-period=%ld"
, ftpfs->params.bulk_stat_period); err = argz_add (argz, argz_len
, buf); } } while (0)
;
364 if (ftpfs->params.bulk_stat_threshold != DEFAULT_BULK_STAT_THRESHOLD5)
365 FOPT ("--bulk-stat-threshold=%d", ftpfs->params.bulk_stat_threshold)do { if (! err) { snprintf (buf, sizeof buf, "--bulk-stat-threshold=%d"
, ftpfs->params.bulk_stat_threshold); err = argz_add (argz
, argz_len, buf); } } while (0)
;
366
367 return argz_add (argz, argz_len, ftpfs_remote_fs);
368}
369
370/* Program entry point. */
371int
372main (int argc, char **argv)
373{
374 error_t err;
375 mach_port_t bootstrap, underlying_node;
376 struct stat underlying_stat;
377 const struct argp_child argp_children[] =
378 { {&common_argp}, {&netfs_std_startup_argp}, {0} };
379 struct argp argp =
380 { startup_options, parse_startup_opt, args_doc, doc, argp_children };
381
382 ftpfs_params.name_timeout = DEFAULT_NAME_TIMEOUT300;
383 ftpfs_params.stat_timeout = DEFAULT_STAT_TIMEOUT120;
384 ftpfs_params.node_cache_max = DEFAULT_NODE_CACHE_MAX50;
385 ftpfs_params.bulk_stat_period = DEFAULT_BULK_STAT_PERIOD10;
386 ftpfs_params.bulk_stat_threshold = DEFAULT_BULK_STAT_THRESHOLD5;
387
388 argp_parse (&argp, argc, argv, 0, 0, 0);
389
390 task_get_bootstrap_port (mach_task_self (), &bootstrap)(task_get_special_port((((__mach_task_self_ + 0))), 4, (&
bootstrap)))
;
391
392 netfs_init ();
393
394 err = maptime_map (0, 0, &ftpfs_maptime);
395 if (err)
396 error (3, err, "mapping time");
397
398 err = ftpfs_create (ftpfs_remote_root, getpid (),
399 ftpfs_ftp_params, &ftpfs_ftp_hooks,
400 &ftpfs_params, &ftpfs);
401 if (err)
402 error (4, err, "%s", ftpfs_remote_fs);
403
404 netfs_root_node = ftpfs->root;
405
406 underlying_node = netfs_startup (bootstrap, 0);
407 err = io_stat (underlying_node, &underlying_stat);
408 if (err)
409 error (1, err, "cannot stat underling node");
410
411 /* Initialize stat information of the root node. */
412 netfs_root_node->nn_stat = underlying_stat;
413 netfs_root_node->nn_stat.st_mode =
414 S_IFDIR0040000 | (underlying_stat.st_mode & ~S_IFMT0170000 & ~S_ITRANS000070000000);
415
416 /* If the underlying node isn't a directory, propagate read permission to
417 execute permission since we need that for lookups. */
418 if (! S_ISDIR (underlying_stat.st_mode)((((underlying_stat.st_mode)) & 0170000) == (0040000)))
419 {
420 if (underlying_stat.st_mode & S_IRUSR00400)
421 netfs_root_node->nn_stat.st_mode |= S_IXUSR00100;
422 if (underlying_stat.st_mode & S_IRGRP(00400 >> 3))
423 netfs_root_node->nn_stat.st_mode |= S_IXGRP(00100 >> 3);
424 if (underlying_stat.st_mode & S_IROTH((00400 >> 3) >> 3))
425 netfs_root_node->nn_stat.st_mode |= S_IXOTH((00100 >> 3) >> 3);
426 }
427
428 for (;;)
429 netfs_server_loop ();
430}