conforming to the XSI-compliant version of strerror_r in sp_suerror.
[spfs.git] / libspclient / netmount.c
blob99db61410b502a8ffbf4689428f4fd641dc2eba2
1 /*
2 * Copyright (C) 2006 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netdb.h>
31 #include <arpa/inet.h>
32 #include "spfs.h"
33 #include "spclient.h"
34 #include "spcimpl.h"
36 /* this should be at least 3 functions. parse an address into
37 * sockaddr. make a socket. Mount a given sockaddr. This needs
38 * rewriting.
39 * oh, hell, let's just do it.
42 /* parse an address in plan 9 format into a sockaddr
43 * NOT a sockaddr_in yet if ever.
44 * if you want defaults, then put them in the string!
46 struct sockaddr *parse9net(const char *address, struct sockaddr *psaddr)
48 int port;
49 char *addr, *name, *p, *s;
50 struct sockaddr_in *saddr = (struct sockaddr_in *)psaddr;
51 struct hostent *hostinfo;
53 addr = strdup(address);
54 if (strncmp(addr, "tcp!", 4) == 0)
55 name = addr + 4;
56 else
57 name = addr;
59 port = 0;
60 p = strrchr(name, '!');
61 if (p) {
62 *p = '\0';
63 p++;
64 port = strtoul(p, &s, 0);
65 if (*s != '\0') {
66 sp_werror("invalid port format", EIO);
67 goto error;
71 hostinfo = gethostbyname(name);
72 if (!hostinfo) {
73 sp_werror("cannot resolve name: %s", EIO, name);
74 goto error;
77 free(addr);
79 saddr->sin_family = AF_INET;
80 saddr->sin_port = htons(port);
81 saddr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
83 return (struct sockaddr *) saddr;
85 error:
86 return NULL;
89 Spcfsys *
90 spc_netmount(char *address, Spuser *user, int dfltport,
91 int (*auth)(Spcfid *afid, Spuser *user, void *aux), void *aux)
93 int n, fd, port;
94 char *addr, *name, *p, *s;
95 struct sockaddr_in saddr;
96 struct hostent *hostinfo;
97 char buf[64];
98 Spcfsys *fs;
100 addr = strdup(address);
101 if (strncmp(addr, "tcp!", 4) == 0)
102 name = addr + 4;
103 else
104 name = addr;
106 port = dfltport;
107 p = strrchr(name, '!');
108 if (p) {
109 *p = '\0';
110 p++;
111 port = strtol(p, &s, 10);
112 if (*s != '\0') {
113 sp_werror("invalid port format", EIO);
114 goto error;
118 fd = socket(PF_INET, SOCK_STREAM, 0);
119 if (fd < 0) {
120 sp_uerror(errno);
121 goto error;
124 hostinfo = gethostbyname(name);
125 if (!hostinfo) {
126 sp_werror("cannot resolve name: %s", EIO, name);
127 goto error;
130 saddr.sin_family = AF_INET;
131 saddr.sin_port = htons(port);
132 saddr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
134 if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
135 /* real computers have errstr */
136 static char error[128];
137 /* too bad for f-ing gcc and friends */
138 unsigned char octet[4];
139 octet[0] = saddr.sin_addr.s_addr >> 24;
140 octet[1] = saddr.sin_addr.s_addr >>16;
141 octet[2] = saddr.sin_addr.s_addr >>8;
142 octet[3] = saddr.sin_addr.s_addr;
143 /* yeah, they broke this too
144 char *i = inet_ntoa(saddr.sin_addr);
147 memset(error, 0, sizeof(error));
148 //strerror_r(errno, error, sizeof(error));
149 strcpy(error, strerror(errno));
150 error[strlen(error)] = ':';
151 sprintf(&error[strlen(error)], "%d.%d.%d.%d", octet[3], octet[2], octet[1], octet[0]);
152 // sp_werror("Host :%s:%s", errno, i, error);
153 sp_werror(error, errno);
154 goto error;
157 free(addr);
158 fs = spc_mount(fd, NULL, user, auth, aux);
159 if (fs) {
160 snprintf(buf, sizeof(buf), "%s", inet_ntoa(saddr.sin_addr));
161 fs->raddr = strdup(buf);
163 n = sizeof(saddr);
164 if (getsockname(fd, (struct sockaddr *) &saddr, (socklen_t *) &n) >= 0) {
165 snprintf(buf, sizeof(buf), "%s", inet_ntoa(saddr.sin_addr));
166 fs->laddr = strdup(buf);
169 if (spc_chatty)
170 fprintf(stderr, "connection %p to %s opened\n", fs, fs->raddr);
173 return fs;
175 error:
176 free(addr);
177 return NULL;