@@ -9,48 +9,114 @@ static int unix_stream_socket(void)
9
9
return fd ;
10
10
}
11
11
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 )
13
39
{
14
40
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
+
17
68
memset (sa , 0 , sizeof (* sa ));
18
69
sa -> sun_family = AF_UNIX ;
19
70
memcpy (sa -> sun_path , path , size );
71
+ return 0 ;
20
72
}
21
73
22
74
int unix_stream_connect (const char * path )
23
75
{
24
- int fd ;
76
+ int fd , saved_errno ;
25
77
struct sockaddr_un sa ;
78
+ struct unix_sockaddr_context ctx ;
26
79
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 )
31
81
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 );
33
86
return fd ;
87
+
88
+ fail :
89
+ saved_errno = errno ;
90
+ unix_sockaddr_cleanup (& ctx );
91
+ close (fd );
92
+ errno = saved_errno ;
93
+ return -1 ;
34
94
}
35
95
36
96
int unix_stream_listen (const char * path )
37
97
{
38
- int fd ;
98
+ int fd , saved_errno ;
39
99
struct sockaddr_un sa ;
100
+ struct unix_sockaddr_context ctx ;
40
101
41
- unix_sockaddr_init (& sa , path );
102
+ if (unix_sockaddr_init (& sa , path , & ctx ) < 0 )
103
+ return -1 ;
42
104
fd = unix_stream_socket ();
43
105
44
106
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 ;
49
109
50
- if (listen (fd , 5 ) < 0 ) {
51
- close (fd );
52
- return -1 ;
53
- }
110
+ if (listen (fd , 5 ) < 0 )
111
+ goto fail ;
54
112
113
+ unix_sockaddr_cleanup (& ctx );
55
114
return fd ;
115
+
116
+ fail :
117
+ saved_errno = errno ;
118
+ unix_sockaddr_cleanup (& ctx );
119
+ close (fd );
120
+ errno = saved_errno ;
121
+ return -1 ;
56
122
}
0 commit comments