@@ -9,48 +9,114 @@ static int unix_stream_socket(void)
99 return fd ;
1010}
1111
12- static void unix_sockaddr_init (struct sockaddr_un * sa , const char * path )
12+ static int chdir_len (const char * orig , int len )
13+ {
14+ char * path = xmemdupz (orig , len );
15+ int r = chdir (path );
16+ free (path );
17+ return r ;
18+ }
19+
20+ struct unix_sockaddr_context {
21+ char orig_dir [PATH_MAX ];
22+ };
23+
24+ static void unix_sockaddr_cleanup (struct unix_sockaddr_context * ctx )
25+ {
26+ if (!ctx -> orig_dir [0 ])
27+ return ;
28+ /*
29+ * If we fail, we can't just return an error, since we have
30+ * moved the cwd of the whole process, which could confuse calling
31+ * code. We are better off to just die.
32+ */
33+ if (chdir (ctx -> orig_dir ) < 0 )
34+ die ("unable to restore original working directory" );
35+ }
36+
37+ static int unix_sockaddr_init (struct sockaddr_un * sa , const char * path ,
38+ struct unix_sockaddr_context * ctx )
1339{
1440 int size = strlen (path ) + 1 ;
15- if (size > sizeof (sa -> sun_path ))
16- die ("socket path is too long to fit in sockaddr" );
41+
42+ ctx -> orig_dir [0 ] = '\0' ;
43+ if (size > sizeof (sa -> sun_path )) {
44+ const char * slash = find_last_dir_sep (path );
45+ const char * dir ;
46+
47+ if (!slash ) {
48+ errno = ENAMETOOLONG ;
49+ return -1 ;
50+ }
51+
52+ dir = path ;
53+ path = slash + 1 ;
54+ size = strlen (path ) + 1 ;
55+ if (size > sizeof (sa -> sun_path )) {
56+ errno = ENAMETOOLONG ;
57+ return -1 ;
58+ }
59+
60+ if (!getcwd (ctx -> orig_dir , sizeof (ctx -> orig_dir ))) {
61+ errno = ENAMETOOLONG ;
62+ return -1 ;
63+ }
64+ if (chdir_len (dir , slash - dir ) < 0 )
65+ return -1 ;
66+ }
67+
1768 memset (sa , 0 , sizeof (* sa ));
1869 sa -> sun_family = AF_UNIX ;
1970 memcpy (sa -> sun_path , path , size );
71+ return 0 ;
2072}
2173
2274int unix_stream_connect (const char * path )
2375{
24- int fd ;
76+ int fd , saved_errno ;
2577 struct sockaddr_un sa ;
78+ struct unix_sockaddr_context ctx ;
2679
27- unix_sockaddr_init (& sa , path );
28- fd = unix_stream_socket ();
29- if (connect (fd , (struct sockaddr * )& sa , sizeof (sa )) < 0 ) {
30- close (fd );
80+ if (unix_sockaddr_init (& sa , path , & ctx ) < 0 )
3181 return -1 ;
32- }
82+ fd = unix_stream_socket ();
83+ if (connect (fd , (struct sockaddr * )& sa , sizeof (sa )) < 0 )
84+ goto fail ;
85+ unix_sockaddr_cleanup (& ctx );
3386 return fd ;
87+
88+ fail :
89+ saved_errno = errno ;
90+ unix_sockaddr_cleanup (& ctx );
91+ close (fd );
92+ errno = saved_errno ;
93+ return -1 ;
3494}
3595
3696int unix_stream_listen (const char * path )
3797{
38- int fd ;
98+ int fd , saved_errno ;
3999 struct sockaddr_un sa ;
100+ struct unix_sockaddr_context ctx ;
40101
41- unix_sockaddr_init (& sa , path );
102+ if (unix_sockaddr_init (& sa , path , & ctx ) < 0 )
103+ return -1 ;
42104 fd = unix_stream_socket ();
43105
44106 unlink (path );
45- if (bind (fd , (struct sockaddr * )& sa , sizeof (sa )) < 0 ) {
46- close (fd );
47- return -1 ;
48- }
107+ if (bind (fd , (struct sockaddr * )& sa , sizeof (sa )) < 0 )
108+ goto fail ;
49109
50- if (listen (fd , 5 ) < 0 ) {
51- close (fd );
52- return -1 ;
53- }
110+ if (listen (fd , 5 ) < 0 )
111+ goto fail ;
54112
113+ unix_sockaddr_cleanup (& ctx );
55114 return fd ;
115+
116+ fail :
117+ saved_errno = errno ;
118+ unix_sockaddr_cleanup (& ctx );
119+ close (fd );
120+ errno = saved_errno ;
121+ return -1 ;
56122}
0 commit comments