1+ /* 9pfs.c - Main 9P filesystem translator
2+ *
3+ * Copyright (C) 2024 Free Software Foundation, Inc.
4+ *
5+ * This file implements the main entry point and initialization
6+ * for the 9P filesystem translator for GNU Hurd.
7+ */
8+
9+ #include "9pfs.h"
10+ #include <argp.h>
11+ #include <error.h>
12+ #include <stdlib.h>
13+ #include <string.h>
14+
15+ /* Global variables */
16+ struct p9_connection * p9_conn = NULL ;
17+ struct p9_namespace * p9_ns = NULL ;
18+ char * p9_server_addr = NULL ;
19+ int p9_server_port = 564 ; /* Default 9P port */
20+ char * p9_username = "root" ;
21+ char * p9_attach_name = "" ;
22+
23+ /* Command line options */
24+ static const struct argp_option options [] =
25+ {
26+ {"server" , 's' , "ADDRESS" , 0 , "9P server address" , 0 },
27+ {"port" , 'p' , "PORT" , 0 , "9P server port (default: 564)" , 0 },
28+ {"user" , 'u' , "USER" , 0 , "Username for 9P connection" , 0 },
29+ {"attach" , 'a' , "NAME" , 0 , "Attachment name" , 0 },
30+ {0 }
31+ };
32+
33+ static const char doc [] = "9P filesystem translator for GNU Hurd" ;
34+ static const char args_doc [] = "UNDERLYING" ;
35+
36+ /* Parse command line arguments */
37+ static error_t
38+ parse_opt (int key , char * arg , struct argp_state * state )
39+ {
40+ switch (key )
41+ {
42+ case 's' :
43+ p9_server_addr = strdup (arg );
44+ break ;
45+ case 'p' :
46+ p9_server_port = atoi (arg );
47+ break ;
48+ case 'u' :
49+ p9_username = strdup (arg );
50+ break ;
51+ case 'a' :
52+ p9_attach_name = strdup (arg );
53+ break ;
54+ case ARGP_KEY_ARG :
55+ if (state -> arg_num >= 1 )
56+ argp_usage (state );
57+ /* Store underlying node - not used in this implementation */
58+ break ;
59+ case ARGP_KEY_NO_ARGS :
60+ if (!p9_server_addr )
61+ argp_error (state , "server address is required" );
62+ break ;
63+ default :
64+ return ARGP_ERR_UNKNOWN ;
65+ }
66+ return 0 ;
67+ }
68+
69+ static const struct argp argp = { options , parse_opt , args_doc , doc };
70+
71+ /* Initialize the 9P filesystem */
72+ error_t
73+ p9fs_init (void )
74+ {
75+ error_t err ;
76+ struct p9_fid * root_fid ;
77+
78+ /* Create namespace */
79+ p9_ns = p9_namespace_create ();
80+ if (!p9_ns )
81+ return p9_to_hurd_error (p9_errno );
82+
83+ /* Connect to 9P server */
84+ p9_conn = p9_connect (p9_server_addr , p9_server_port );
85+ if (!p9_conn ) {
86+ p9_namespace_destroy (p9_ns );
87+ return p9_to_hurd_error (p9_errno );
88+ }
89+
90+ /* Negotiate protocol version */
91+ if (p9_version (p9_conn , P9_VERSION , 8192 ) < 0 ) {
92+ err = p9_to_hurd_error (p9_errno );
93+ goto cleanup ;
94+ }
95+
96+ /* Attach to filesystem root */
97+ root_fid = p9_attach (p9_conn , p9_username , p9_attach_name );
98+ if (!root_fid ) {
99+ err = p9_to_hurd_error (p9_errno );
100+ goto cleanup ;
101+ }
102+
103+ /* Create root netfs node */
104+ netfs_root_node = p9fs_make_node (root_fid );
105+ if (!netfs_root_node ) {
106+ p9_clunk (root_fid );
107+ err = ENOMEM ;
108+ goto cleanup ;
109+ }
110+
111+ return 0 ;
112+
113+ cleanup :
114+ p9_disconnect (p9_conn );
115+ p9_namespace_destroy (p9_ns );
116+ return err ;
117+ }
118+
119+ /* Shutdown the 9P filesystem */
120+ void
121+ p9fs_shutdown (void )
122+ {
123+ if (p9_conn ) {
124+ p9_disconnect (p9_conn );
125+ p9_conn = NULL ;
126+ }
127+
128+ if (p9_ns ) {
129+ p9_namespace_destroy (p9_ns );
130+ p9_ns = NULL ;
131+ }
132+ }
133+
134+ /* Convert 9P errors to Hurd errors */
135+ error_t
136+ p9_to_hurd_error (int p9_error )
137+ {
138+ switch (p9_error ) {
139+ case 0 :
140+ return 0 ;
141+ case P9_EIO :
142+ return EIO ;
143+ case P9_EPROTO :
144+ return EPROTO ;
145+ case P9_ENOMEM :
146+ return ENOMEM ;
147+ case P9_EINVAL :
148+ return EINVAL ;
149+ case P9_ENOENT :
150+ return ENOENT ;
151+ case P9_EACCES :
152+ return EACCES ;
153+ case P9_EEXIST :
154+ return EEXIST ;
155+ case P9_EISDIR :
156+ return EISDIR ;
157+ case P9_ENOTDIR :
158+ return ENOTDIR ;
159+ case P9_EMFILE :
160+ return EMFILE ;
161+ default :
162+ return EIO ;
163+ }
164+ }
165+
166+ /* Convert 9P mode to Hurd mode */
167+ mode_t
168+ p9_to_hurd_mode (uint32_t p9_mode )
169+ {
170+ mode_t mode = 0 ;
171+
172+ /* File type */
173+ if (p9_mode & P9_DMDIR )
174+ mode |= S_IFDIR ;
175+ else
176+ mode |= S_IFREG ;
177+
178+ /* Permissions */
179+ mode |= (p9_mode & 0777 );
180+
181+ return mode ;
182+ }
183+
184+ /* Convert Hurd mode to 9P mode */
185+ uint32_t
186+ hurd_to_p9_mode (mode_t mode )
187+ {
188+ uint32_t p9_mode = 0 ;
189+
190+ /* File type */
191+ if (S_ISDIR (mode ))
192+ p9_mode |= P9_DMDIR ;
193+
194+ /* Permissions */
195+ p9_mode |= (mode & 0777 );
196+
197+ return p9_mode ;
198+ }
199+
200+ /* Main function */
201+ int
202+ main (int argc , char * * argv )
203+ {
204+ error_t err ;
205+
206+ /* Parse arguments */
207+ argp_parse (& argp , argc , argv , 0 , 0 , 0 );
208+
209+ /* Set default server if not specified */
210+ if (!p9_server_addr )
211+ p9_server_addr = "localhost" ;
212+
213+ /* Initialize netfs */
214+ netfs_init ();
215+
216+ /* Initialize 9P filesystem */
217+ err = p9fs_init ();
218+ if (err )
219+ error (1 , err , "cannot initialize 9P filesystem" );
220+
221+ /* Set up signal handlers for clean shutdown */
222+ signal (SIGINT , (void (* )(int ))p9fs_shutdown );
223+ signal (SIGTERM , (void (* )(int ))p9fs_shutdown );
224+
225+ /* Start netfs server */
226+ netfs_server_loop ();
227+
228+ /* Cleanup */
229+ p9fs_shutdown ();
230+
231+ return 0 ;
232+ }
0 commit comments