~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/usb/usbip/src/usbipd.c

Version: ~ [ linux-5.8-rc4 ] ~ [ linux-5.7.7 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.50 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.131 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.187 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.229 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.229 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  3  *               2005-2007 Takahiro Hirofuchi
  4  * Copyright (C) 2015-2016 Samsung Electronics
  5  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
  6  *               Krzysztof Opasiak <k.opasiak@samsung.com>
  7  *
  8  * This program is free software: you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation, either version 2 of the License, or
 11  * (at your option) any later version.
 12  *
 13  * This program is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 16  * GNU General Public License for more details.
 17  *
 18  * You should have received a copy of the GNU General Public License
 19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
 20  */
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include "../config.h"
 24 #endif
 25 
 26 #define _GNU_SOURCE
 27 #include <errno.h>
 28 #include <unistd.h>
 29 #include <netdb.h>
 30 #include <string.h>
 31 #include <stdlib.h>
 32 #include <sys/types.h>
 33 #include <sys/stat.h>
 34 #include <arpa/inet.h>
 35 #include <sys/socket.h>
 36 #include <netinet/in.h>
 37 
 38 #ifdef HAVE_LIBWRAP
 39 #include <tcpd.h>
 40 #endif
 41 
 42 #include <getopt.h>
 43 #include <signal.h>
 44 #include <poll.h>
 45 
 46 #include "usbip_host_driver.h"
 47 #include "usbip_host_common.h"
 48 #include "usbip_device_driver.h"
 49 #include "usbip_common.h"
 50 #include "usbip_network.h"
 51 #include "list.h"
 52 
 53 #undef  PROGNAME
 54 #define PROGNAME "usbipd"
 55 #define MAXSOCKFD 20
 56 
 57 #define MAIN_LOOP_TIMEOUT 10
 58 
 59 #define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
 60 
 61 static const char usbip_version_string[] = PACKAGE_STRING;
 62 
 63 static const char usbipd_help_string[] =
 64         "usage: usbipd [options]\n"
 65         "\n"
 66         "       -4, --ipv4\n"
 67         "               Bind to IPv4. Default is both.\n"
 68         "\n"
 69         "       -6, --ipv6\n"
 70         "               Bind to IPv6. Default is both.\n"
 71         "\n"
 72         "       -e, --device\n"
 73         "               Run in device mode.\n"
 74         "               Rather than drive an attached device, create\n"
 75         "               a virtual UDC to bind gadgets to.\n"
 76         "\n"
 77         "       -D, --daemon\n"
 78         "               Run as a daemon process.\n"
 79         "\n"
 80         "       -d, --debug\n"
 81         "               Print debugging information.\n"
 82         "\n"
 83         "       -PFILE, --pid FILE\n"
 84         "               Write process id to FILE.\n"
 85         "               If no FILE specified, use " DEFAULT_PID_FILE "\n"
 86         "\n"
 87         "       -tPORT, --tcp-port PORT\n"
 88         "               Listen on TCP/IP port PORT.\n"
 89         "\n"
 90         "       -h, --help\n"
 91         "               Print this help.\n"
 92         "\n"
 93         "       -v, --version\n"
 94         "               Show version.\n";
 95 
 96 static struct usbip_host_driver *driver;
 97 
 98 static void usbipd_help(void)
 99 {
100         printf("%s\n", usbipd_help_string);
101 }
102 
103 static int recv_request_import(int sockfd)
104 {
105         struct op_import_request req;
106         struct usbip_exported_device *edev;
107         struct usbip_usb_device pdu_udev;
108         struct list_head *i;
109         int found = 0;
110         int status = ST_OK;
111         int rc;
112 
113         memset(&req, 0, sizeof(req));
114 
115         rc = usbip_net_recv(sockfd, &req, sizeof(req));
116         if (rc < 0) {
117                 dbg("usbip_net_recv failed: import request");
118                 return -1;
119         }
120         PACK_OP_IMPORT_REQUEST(0, &req);
121 
122         list_for_each(i, &driver->edev_list) {
123                 edev = list_entry(i, struct usbip_exported_device, node);
124                 if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
125                         info("found requested device: %s", req.busid);
126                         found = 1;
127                         break;
128                 }
129         }
130 
131         if (found) {
132                 /* should set TCP_NODELAY for usbip */
133                 usbip_net_set_nodelay(sockfd);
134 
135                 /* export device needs a TCP/IP socket descriptor */
136                 status = usbip_export_device(edev, sockfd);
137                 if (status < 0)
138                         status = ST_NA;
139         } else {
140                 info("requested device not found: %s", req.busid);
141                 status = ST_NODEV;
142         }
143 
144         rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, status);
145         if (rc < 0) {
146                 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
147                 return -1;
148         }
149 
150         if (status) {
151                 dbg("import request busid %s: failed", req.busid);
152                 return -1;
153         }
154 
155         memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
156         usbip_net_pack_usb_device(1, &pdu_udev);
157 
158         rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
159         if (rc < 0) {
160                 dbg("usbip_net_send failed: devinfo");
161                 return -1;
162         }
163 
164         dbg("import request busid %s: complete", req.busid);
165 
166         return 0;
167 }
168 
169 static int send_reply_devlist(int connfd)
170 {
171         struct usbip_exported_device *edev;
172         struct usbip_usb_device pdu_udev;
173         struct usbip_usb_interface pdu_uinf;
174         struct op_devlist_reply reply;
175         struct list_head *j;
176         int rc, i;
177 
178         /*
179          * Exclude devices that are already exported to a client from
180          * the exportable device list to avoid:
181          *      - import requests for devices that are exported only to
182          *        fail the request.
183          *      - revealing devices that are imported by a client to
184          *        another client.
185          */
186 
187         reply.ndev = 0;
188         /* number of exported devices */
189         list_for_each(j, &driver->edev_list) {
190                 edev = list_entry(j, struct usbip_exported_device, node);
191                 if (edev->status != SDEV_ST_USED)
192                         reply.ndev += 1;
193         }
194         info("exportable devices: %d", reply.ndev);
195 
196         rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
197         if (rc < 0) {
198                 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
199                 return -1;
200         }
201         PACK_OP_DEVLIST_REPLY(1, &reply);
202 
203         rc = usbip_net_send(connfd, &reply, sizeof(reply));
204         if (rc < 0) {
205                 dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
206                 return -1;
207         }
208 
209         list_for_each(j, &driver->edev_list) {
210                 edev = list_entry(j, struct usbip_exported_device, node);
211                 if (edev->status == SDEV_ST_USED)
212                         continue;
213 
214                 dump_usb_device(&edev->udev);
215                 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
216                 usbip_net_pack_usb_device(1, &pdu_udev);
217 
218                 rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
219                 if (rc < 0) {
220                         dbg("usbip_net_send failed: pdu_udev");
221                         return -1;
222                 }
223 
224                 for (i = 0; i < edev->udev.bNumInterfaces; i++) {
225                         dump_usb_interface(&edev->uinf[i]);
226                         memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
227                         usbip_net_pack_usb_interface(1, &pdu_uinf);
228 
229                         rc = usbip_net_send(connfd, &pdu_uinf,
230                                         sizeof(pdu_uinf));
231                         if (rc < 0) {
232                                 err("usbip_net_send failed: pdu_uinf");
233                                 return -1;
234                         }
235                 }
236         }
237 
238         return 0;
239 }
240 
241 static int recv_request_devlist(int connfd)
242 {
243         struct op_devlist_request req;
244         int rc;
245 
246         memset(&req, 0, sizeof(req));
247 
248         rc = usbip_net_recv(connfd, &req, sizeof(req));
249         if (rc < 0) {
250                 dbg("usbip_net_recv failed: devlist request");
251                 return -1;
252         }
253 
254         rc = send_reply_devlist(connfd);
255         if (rc < 0) {
256                 dbg("send_reply_devlist failed");
257                 return -1;
258         }
259 
260         return 0;
261 }
262 
263 static int recv_pdu(int connfd)
264 {
265         uint16_t code = OP_UNSPEC;
266         int ret;
267         int status;
268 
269         ret = usbip_net_recv_op_common(connfd, &code, &status);
270         if (ret < 0) {
271                 dbg("could not receive opcode: %#0x", code);
272                 return -1;
273         }
274 
275         ret = usbip_refresh_device_list(driver);
276         if (ret < 0) {
277                 dbg("could not refresh device list: %d", ret);
278                 return -1;
279         }
280 
281         info("received request: %#0x(%d)", code, connfd);
282         switch (code) {
283         case OP_REQ_DEVLIST:
284                 ret = recv_request_devlist(connfd);
285                 break;
286         case OP_REQ_IMPORT:
287                 ret = recv_request_import(connfd);
288                 break;
289         case OP_REQ_DEVINFO:
290         case OP_REQ_CRYPKEY:
291         default:
292                 err("received an unknown opcode: %#0x", code);
293                 ret = -1;
294         }
295 
296         if (ret == 0)
297                 info("request %#0x(%d): complete", code, connfd);
298         else
299                 info("request %#0x(%d): failed", code, connfd);
300 
301         return ret;
302 }
303 
304 #ifdef HAVE_LIBWRAP
305 static int tcpd_auth(int connfd)
306 {
307         struct request_info request;
308         int rc;
309 
310         request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
311         fromhost(&request);
312         rc = hosts_access(&request);
313         if (rc == 0)
314                 return -1;
315 
316         return 0;
317 }
318 #endif
319 
320 static int do_accept(int listenfd)
321 {
322         int connfd;
323         struct sockaddr_storage ss;
324         socklen_t len = sizeof(ss);
325         char host[NI_MAXHOST], port[NI_MAXSERV];
326         int rc;
327 
328         memset(&ss, 0, sizeof(ss));
329 
330         connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
331         if (connfd < 0) {
332                 err("failed to accept connection");
333                 return -1;
334         }
335 
336         rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
337                          port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
338         if (rc)
339                 err("getnameinfo: %s", gai_strerror(rc));
340 
341 #ifdef HAVE_LIBWRAP
342         rc = tcpd_auth(connfd);
343         if (rc < 0) {
344                 info("denied access from %s", host);
345                 close(connfd);
346                 return -1;
347         }
348 #endif
349         info("connection from %s:%s", host, port);
350 
351         return connfd;
352 }
353 
354 int process_request(int listenfd)
355 {
356         pid_t childpid;
357         int connfd;
358 
359         connfd = do_accept(listenfd);
360         if (connfd < 0)
361                 return -1;
362         childpid = fork();
363         if (childpid == 0) {
364                 close(listenfd);
365                 recv_pdu(connfd);
366                 exit(0);
367         }
368         close(connfd);
369         return 0;
370 }
371 
372 static void addrinfo_to_text(struct addrinfo *ai, char buf[],
373                              const size_t buf_size)
374 {
375         char hbuf[NI_MAXHOST];
376         char sbuf[NI_MAXSERV];
377         int rc;
378 
379         buf[0] = '\0';
380 
381         rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
382                          sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
383         if (rc)
384                 err("getnameinfo: %s", gai_strerror(rc));
385 
386         snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
387 }
388 
389 static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
390                              int maxsockfd)
391 {
392         struct addrinfo *ai;
393         int ret, nsockfd = 0;
394         const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
395         char ai_buf[ai_buf_size];
396 
397         for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
398                 int sock;
399 
400                 addrinfo_to_text(ai, ai_buf, ai_buf_size);
401                 dbg("opening %s", ai_buf);
402                 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
403                 if (sock < 0) {
404                         err("socket: %s: %d (%s)",
405                             ai_buf, errno, strerror(errno));
406                         continue;
407                 }
408 
409                 usbip_net_set_reuseaddr(sock);
410                 usbip_net_set_nodelay(sock);
411                 /* We use seperate sockets for IPv4 and IPv6
412                  * (see do_standalone_mode()) */
413                 usbip_net_set_v6only(sock);
414 
415                 ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
416                 if (ret < 0) {
417                         err("bind: %s: %d (%s)",
418                             ai_buf, errno, strerror(errno));
419                         close(sock);
420                         continue;
421                 }
422 
423                 ret = listen(sock, SOMAXCONN);
424                 if (ret < 0) {
425                         err("listen: %s: %d (%s)",
426                             ai_buf, errno, strerror(errno));
427                         close(sock);
428                         continue;
429                 }
430 
431                 info("listening on %s", ai_buf);
432                 sockfdlist[nsockfd++] = sock;
433         }
434 
435         return nsockfd;
436 }
437 
438 static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
439 {
440         struct addrinfo hints, *ai_head;
441         int rc;
442 
443         memset(&hints, 0, sizeof(hints));
444         hints.ai_family   = ai_family;
445         hints.ai_socktype = SOCK_STREAM;
446         hints.ai_flags    = AI_PASSIVE;
447 
448         rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
449         if (rc) {
450                 err("failed to get a network address %s: %s", usbip_port_string,
451                     gai_strerror(rc));
452                 return NULL;
453         }
454 
455         return ai_head;
456 }
457 
458 static void signal_handler(int i)
459 {
460         dbg("received '%s' signal", strsignal(i));
461 }
462 
463 static void set_signal(void)
464 {
465         struct sigaction act;
466 
467         memset(&act, 0, sizeof(act));
468         act.sa_handler = signal_handler;
469         sigemptyset(&act.sa_mask);
470         sigaction(SIGTERM, &act, NULL);
471         sigaction(SIGINT, &act, NULL);
472         act.sa_handler = SIG_IGN;
473         sigaction(SIGCHLD, &act, NULL);
474 }
475 
476 static const char *pid_file;
477 
478 static void write_pid_file(void)
479 {
480         if (pid_file) {
481                 dbg("creating pid file %s", pid_file);
482                 FILE *fp;
483 
484                 fp = fopen(pid_file, "w");
485                 if (!fp) {
486                         err("pid_file: %s: %d (%s)",
487                             pid_file, errno, strerror(errno));
488                         return;
489                 }
490                 fprintf(fp, "%d\n", getpid());
491                 fclose(fp);
492         }
493 }
494 
495 static void remove_pid_file(void)
496 {
497         if (pid_file) {
498                 dbg("removing pid file %s", pid_file);
499                 unlink(pid_file);
500         }
501 }
502 
503 static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
504 {
505         struct addrinfo *ai_head;
506         int sockfdlist[MAXSOCKFD];
507         int nsockfd, family;
508         int i, terminate;
509         struct pollfd *fds;
510         struct timespec timeout;
511         sigset_t sigmask;
512 
513         if (usbip_driver_open(driver))
514                 return -1;
515 
516         if (daemonize) {
517                 if (daemon(0, 0) < 0) {
518                         err("daemonizing failed: %s", strerror(errno));
519                         usbip_driver_close(driver);
520                         return -1;
521                 }
522                 umask(0);
523                 usbip_use_syslog = 1;
524         }
525         set_signal();
526         write_pid_file();
527 
528         info("starting " PROGNAME " (%s)", usbip_version_string);
529 
530         /*
531          * To suppress warnings on systems with bindv6only disabled
532          * (default), we use seperate sockets for IPv6 and IPv4 and set
533          * IPV6_V6ONLY on the IPv6 sockets.
534          */
535         if (ipv4 && ipv6)
536                 family = AF_UNSPEC;
537         else if (ipv4)
538                 family = AF_INET;
539         else
540                 family = AF_INET6;
541 
542         ai_head = do_getaddrinfo(NULL, family);
543         if (!ai_head) {
544                 usbip_driver_close(driver);
545                 return -1;
546         }
547         nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
548                 sizeof(sockfdlist) / sizeof(*sockfdlist));
549         freeaddrinfo(ai_head);
550         if (nsockfd <= 0) {
551                 err("failed to open a listening socket");
552                 usbip_driver_close(driver);
553                 return -1;
554         }
555 
556         dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
557 
558         fds = calloc(nsockfd, sizeof(struct pollfd));
559         for (i = 0; i < nsockfd; i++) {
560                 fds[i].fd = sockfdlist[i];
561                 fds[i].events = POLLIN;
562         }
563         timeout.tv_sec = MAIN_LOOP_TIMEOUT;
564         timeout.tv_nsec = 0;
565 
566         sigfillset(&sigmask);
567         sigdelset(&sigmask, SIGTERM);
568         sigdelset(&sigmask, SIGINT);
569 
570         terminate = 0;
571         while (!terminate) {
572                 int r;
573 
574                 r = ppoll(fds, nsockfd, &timeout, &sigmask);
575                 if (r < 0) {
576                         dbg("%s", strerror(errno));
577                         terminate = 1;
578                 } else if (r) {
579                         for (i = 0; i < nsockfd; i++) {
580                                 if (fds[i].revents & POLLIN) {
581                                         dbg("read event on fd[%d]=%d",
582                                             i, sockfdlist[i]);
583                                         process_request(sockfdlist[i]);
584                                 }
585                         }
586                 } else {
587                         dbg("heartbeat timeout on ppoll()");
588                 }
589         }
590 
591         info("shutting down " PROGNAME);
592         free(fds);
593         usbip_driver_close(driver);
594 
595         return 0;
596 }
597 
598 int main(int argc, char *argv[])
599 {
600         static const struct option longopts[] = {
601                 { "ipv4",     no_argument,       NULL, '4' },
602                 { "ipv6",     no_argument,       NULL, '6' },
603                 { "daemon",   no_argument,       NULL, 'D' },
604                 { "daemon",   no_argument,       NULL, 'D' },
605                 { "debug",    no_argument,       NULL, 'd' },
606                 { "device",   no_argument,       NULL, 'e' },
607                 { "pid",      optional_argument, NULL, 'P' },
608                 { "tcp-port", required_argument, NULL, 't' },
609                 { "help",     no_argument,       NULL, 'h' },
610                 { "version",  no_argument,       NULL, 'v' },
611                 { NULL,       0,                 NULL,  0  }
612         };
613 
614         enum {
615                 cmd_standalone_mode = 1,
616                 cmd_help,
617                 cmd_version
618         } cmd;
619 
620         int daemonize = 0;
621         int ipv4 = 0, ipv6 = 0;
622         int opt, rc = -1;
623 
624         pid_file = NULL;
625 
626         usbip_use_stderr = 1;
627         usbip_use_syslog = 0;
628 
629         if (geteuid() != 0)
630                 err("not running as root?");
631 
632         cmd = cmd_standalone_mode;
633         driver = &host_driver;
634         for (;;) {
635                 opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL);
636 
637                 if (opt == -1)
638                         break;
639 
640                 switch (opt) {
641                 case '4':
642                         ipv4 = 1;
643                         break;
644                 case '6':
645                         ipv6 = 1;
646                         break;
647                 case 'D':
648                         daemonize = 1;
649                         break;
650                 case 'd':
651                         usbip_use_debug = 1;
652                         break;
653                 case 'h':
654                         cmd = cmd_help;
655                         break;
656                 case 'P':
657                         pid_file = optarg ? optarg : DEFAULT_PID_FILE;
658                         break;
659                 case 't':
660                         usbip_setup_port_number(optarg);
661                         break;
662                 case 'v':
663                         cmd = cmd_version;
664                         break;
665                 case 'e':
666                         driver = &device_driver;
667                         break;
668                 case '?':
669                         usbipd_help();
670                 default:
671                         goto err_out;
672                 }
673         }
674 
675         if (!ipv4 && !ipv6)
676                 ipv4 = ipv6 = 1;
677 
678         switch (cmd) {
679         case cmd_standalone_mode:
680                 rc = do_standalone_mode(daemonize, ipv4, ipv6);
681                 remove_pid_file();
682                 break;
683         case cmd_version:
684                 printf(PROGNAME " (%s)\n", usbip_version_string);
685                 rc = 0;
686                 break;
687         case cmd_help:
688                 usbipd_help();
689                 rc = 0;
690                 break;
691         default:
692                 usbipd_help();
693                 goto err_out;
694         }
695 
696 err_out:
697         return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
698 }
699 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp