Fix a gcc 4.6 warning.
[usmb.git] / usmb.c
blobc8c454e42c3f94ff8b5ad9f52a6b2adf95ce40d2
1 /* usmb - mount SMB shares via FUSE and Samba
2 * Copyright (C) 2006-2010 Geoff Johnstone
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "config.h"
18 #include <sys/time.h> // struct timeval needed by libsmbclient.h
19 #include <unistd.h>
20 #include <libsmbclient.h>
21 #include "samba3x-compat.h"
22 #include <fuse.h>
23 #include <assert.h>
24 #include <limits.h>
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdbool.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "conffile.h"
33 #include "options.h"
34 #include "password.h"
35 #include "usmb.h"
36 #include "usmb_dir.h"
37 #include "usmb_file.h"
38 #include "utils.h"
39 #include "version.h"
42 SMBCCTX *ctx;
43 static char *server, *share, *mountpoint, *options,
44 *domain, *username, *password;
47 char * make_url (const char *path)
49 assert (NULL != share);
51 if ((NULL == path) || ('\0' == path[0]))
52 return xstrdup (share);
53 else
54 return concat_strings (2, share, path);
58 static inline void do_strncpy (char *to, const char *from, int tolen)
60 strncpy (to, from, tolen);
61 to[tolen - 1] = '\0';
65 static void auth_fn (const char *srv UNUSED, const char *shr UNUSED,
66 char *wg, int wglen, char *un, int unlen,
67 char *pw, int pwlen)
69 DEBUG (fprintf (stderr, "Authenticating for \\\\%s\\%s\n", srv, shr));
70 DEBUG (fprintf (stderr, "Domain: %s; User: %s; Password: %s\n",
71 domain, username, password));
73 if (NULL != domain)
74 do_strncpy (wg, domain, wglen);
76 do_strncpy (un, username, unlen);
77 do_strncpy (pw, password, pwlen);
81 void destroy_smb_context (SMBCCTX *ctx_, int shutdown)
83 // Samba frees the workgroup and user strings but we want to persist them.
84 smbc_setWorkgroup (ctx_, NULL);
85 smbc_setUser (ctx_, NULL);
86 smbc_free_context (ctx_, shutdown);
90 bool create_smb_context (SMBCCTX **pctx)
92 *pctx = smbc_new_context();
94 if (NULL == *pctx)
96 perror ("Cannot create SMB context");
97 return false;
100 smbc_setWorkgroup (*pctx, domain);
101 smbc_setUser (*pctx, username);
102 smbc_setTimeout (*pctx, 5000);
103 smbc_setFunctionAuthData (*pctx, auth_fn);
105 if (NULL == smbc_init_context (*pctx))
107 perror ("Cannot initialise SMB context");
108 destroy_smb_context (*pctx, 1);
109 return false;
112 return true;
116 static void * usmb_init (struct fuse_conn_info *conn UNUSED)
118 DEBUG (fputs ("usmb_init()\n", stderr));
119 return NULL;
123 static void usmb_destroy (void *unused UNUSED)
125 DEBUG (fputs ("usmb_destroy()\n", stderr));
129 // probably won't (can't ?) implement these:
130 // readlink mknod symlink flush fsync
132 // no easy way of implementing these:
133 // access
135 #ifdef __lint
136 #define SET_ELEMENT(name,value) value
137 #else
138 #define SET_ELEMENT(name,value) name = value
139 #endif
140 static struct fuse_operations fuse_ops = {
141 SET_ELEMENT (.getattr, usmb_getattr),
142 SET_ELEMENT (.readlink, NULL),
143 SET_ELEMENT (.getdir, NULL),
144 SET_ELEMENT (.mknod, NULL),
145 SET_ELEMENT (.mkdir, usmb_mkdir),
146 SET_ELEMENT (.unlink, usmb_unlink),
147 SET_ELEMENT (.rmdir, usmb_rmdir),
148 SET_ELEMENT (.symlink, NULL),
149 SET_ELEMENT (.rename, usmb_rename),
150 SET_ELEMENT (.link, NULL),
151 SET_ELEMENT (.chmod, usmb_chmod),
152 SET_ELEMENT (.chown, NULL), // usmb_chown, --not implemented in libsmbclient
153 SET_ELEMENT (.truncate, usmb_truncate),
154 SET_ELEMENT (.utime, usmb_utime),
155 SET_ELEMENT (.open, usmb_open),
156 SET_ELEMENT (.read, usmb_read),
157 SET_ELEMENT (.write, usmb_write),
158 SET_ELEMENT (.statfs, usmb_statfs),
159 SET_ELEMENT (.flush, NULL),
160 SET_ELEMENT (.release, usmb_release),
161 SET_ELEMENT (.fsync, NULL),
162 SET_ELEMENT (.setxattr, usmb_setxattr),
163 SET_ELEMENT (.getxattr, usmb_getxattr),
164 SET_ELEMENT (.listxattr, usmb_listxattr),
165 SET_ELEMENT (.removexattr, usmb_removexattr),
166 SET_ELEMENT (.opendir, usmb_opendir),
167 SET_ELEMENT (.readdir, usmb_readdir),
168 SET_ELEMENT (.releasedir, usmb_releasedir),
169 SET_ELEMENT (.fsyncdir, NULL),
170 SET_ELEMENT (.init, usmb_init),
171 SET_ELEMENT (.destroy, usmb_destroy),
172 SET_ELEMENT (.access, NULL),
173 SET_ELEMENT (.create, usmb_create),
174 SET_ELEMENT (.ftruncate, usmb_ftruncate),
175 SET_ELEMENT (.fgetattr, usmb_fgetattr),
176 SET_ELEMENT (.lock, NULL), // TODO: implement
177 SET_ELEMENT (.utimens, NULL), // TODO: implement
178 SET_ELEMENT (.bmap, NULL), // TODO: implement
182 static bool create_share_name (const char *server_, const char *sharename)
184 size_t len = strlen ("smb:///") +
185 strlen (server_) +
186 strlen (sharename) + 1;
188 if (NULL == (share = malloc (len)))
190 perror ("Cannot allocate share name");
191 return false;
194 if (!bsnprintf (share, len, "smb://%s/%s", server_, sharename))
196 fputs ("Share server and/or name are too long.\n", stderr);
197 free (share);
198 return false;
201 DEBUG (fprintf (stderr, "Share URL: %s\n", share));
202 return true;
206 static void free_strings (char *sharename)
208 xfree (sharename);
209 clear_and_free (password);
210 xfree (username);
211 xfree (domain);
212 xfree (options);
213 xfree (mountpoint);
214 xfree (share);
215 xfree (server);
219 static bool check_credentials (void)
221 char *url = make_url ("");
222 if (NULL == url)
224 errno = ENOMEM;
225 return false;
228 DEBUG (fprintf (stderr, "URL: %s\n", url));
230 struct stat stat_;
231 bool ret = (0 == (smbc_getFunctionStat (ctx) (ctx, url, &stat_)));
233 free_errno (url);
234 return ret;
238 static bool get_context (void)
240 ctx = NULL;
242 unsigned attempts = 3;
244 while (0 != attempts--)
246 if ((NULL == password) && !password_read (&password))
247 break;
249 if (!create_smb_context (&ctx))
251 clear_and_free (password);
252 password = NULL;
253 ctx = NULL;
254 break;
257 if (check_credentials())
258 break;
260 perror ("Connection failed");
261 clear_and_free (password);
262 password = NULL;
264 destroy_smb_context (ctx, 1);
265 ctx = NULL;
268 return (NULL != ctx);
272 int main (int argc, char **argv)
274 const char *conffile, *mountid;
275 bool umount;
276 char *sharename = NULL;
277 int ret = EXIT_FAILURE;
279 if (sizeof (uint64_t) < sizeof (uintptr_t))
281 fputs ("usmb is not supported on this platform.\n", stderr);
282 return EXIT_FAILURE;
286 static char conf[PATH_MAX];
287 const char * const HOME = getenv ("HOME");
288 if (NULL == HOME)
290 fputs ("Please set the HOME environment variable.\n", stderr);
291 return EXIT_FAILURE;
294 if (!bsnprintf (conf, sizeof (conf), "%s/.usmb.conf", HOME))
296 fputs ("Configuration file path is too long.\n", stderr);
297 return EXIT_FAILURE;
300 conffile = conf;
303 if (!parse_args (&argc, &argv, &mountid, &conffile, &umount))
304 return EXIT_FAILURE;
306 if (!umount)
307 show_about (stdout);
309 if (!conffile_get_mount (conffile, mountid,
310 &server, &sharename, &mountpoint, &options,
311 &domain, &username, &password))
312 return EXIT_FAILURE;
314 DEBUG (fprintf (stderr, "Mountpoint: %s\n", mountpoint));
316 if (umount)
318 execlp ("fusermount", "fusermount", "-u", mountpoint, NULL);
319 perror ("Failed to execute fusermount");
322 else if (create_share_name (server, sharename) && get_context())
324 DEBUG (fprintf (stderr, "Username: %s\\%s\n", domain, username));
326 int fuse_argc;
327 char **fuse_argv;
328 build_fuse_args (options, mountpoint, &fuse_argc, &fuse_argv);
329 ret = fuse_main (fuse_argc, fuse_argv, &fuse_ops, NULL);
330 destroy_smb_context (ctx, 1);
333 free_strings (sharename);
334 return ret;