10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <sys/select.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
18 static const char *guess_repo_name(const char *path);
19 static void sighandler(int s);
20 static int parse_args(int argc, char **argv);
22 static const char *repo_name;
24 static int port = 64357;
27 static struct client *clients;
29 const char *repo_path;
32 int main(int argc, char **argv)
34 struct sockaddr_in addr;
36 if(parse_args(argc, argv) == -1) {
40 signal(SIGINT, sighandler);
41 signal(SIGQUIT, sighandler);
42 signal(SIGILL, sighandler);
43 signal(SIGSEGV, sighandler);
44 signal(SIGTERM, sighandler);
45 signal(SIGPIPE, SIG_IGN);
47 if(repo_init(repo_path) == -1) {
53 if(!(repo_name = guess_repo_name(repo_path))) {
58 printf("Serving %s from %s\n", repo_name, repo_path);
60 if(!(lis = socket(PF_INET, SOCK_STREAM, 0))) {
61 fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
64 fcntl(lis, F_SETFL, fcntl(lis, F_GETFL) | O_NONBLOCK);
66 memset(&addr, 0, sizeof addr);
67 addr.sin_family = AF_INET;
68 addr.sin_port = htons(port);
69 addr.sin_addr.s_addr = INADDR_ANY;
71 if(bind(lis, (struct sockaddr*)&addr, sizeof addr) == -1) {
72 fprintf(stderr, "failed to bind listening socket to port %d\n", port);
80 struct client *c, dummy;
88 if(c->s > max_fd) max_fd = c->s;
92 if((res = select(max_fd + 1, &rdset, 0, 0, 0)) == -1 && errno != EINTR) {
93 perror("select failed");
97 if(res <= 0) continue;
102 if(FD_ISSET(c->next->s, &rdset)) {
103 if(handle_client(c->next) == -1) {
104 struct client *tmp = c->next;
107 printf("Client %s disconnected\n", tmp->addr ? tmp->addr : "unknown");
116 clients = dummy.next;
118 if(FD_ISSET(lis, &rdset)) {
119 struct sockaddr_in addr;
120 unsigned int addrsz = sizeof addr;
122 if((s = accept(lis, (struct sockaddr*)&addr, &addrsz)) == -1) {
123 perror("failed to accept connection");
126 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
128 if(!(c = calloc(1, sizeof *c))) {
129 perror("failed to allocate memory for client structure");
135 c->addr = strdup(inet_ntoa(addr.sin_addr));
138 send_string(c, "reposerve-0.1 protocol:0\n");
140 printf("Connection from: %s\n", c->addr ? c->addr : "unknown");
144 printf("Shutting down\n");
148 static const char *guess_repo_name(const char *path)
150 static char pathbuf[PATH_MAX];
154 if(!realpath(path, pathbuf)) {
157 len = strlen(pathbuf);
159 if(len > 0 && pathbuf[len - 1] == '/') {
162 if(len <= 0) goto fail;
164 if((last_slash = strrchr(pathbuf, '/'))) {
165 return last_slash + 1;
170 fprintf(stderr, "failed to resolve path %s while determining the repo name. Please specify an explicit name with -id\n", repo_path);
174 static void sighandler(int s)
179 static void print_usage(const char *argv0)
181 printf("Usage: %s [options] [repo path]\n", argv0);
182 printf("options:\n");
183 printf(" -id <name>: repo identifier (defaults to directory name)\n");
184 printf(" -h,-help: print help and exit\n");
187 static int parse_args(int argc, char **argv)
191 for(i=1; i<argc; i++) {
192 if(argv[i][0] == '-') {
193 if(strcmp(argv[i], "-id") == 0) {
194 repo_name = argv[++i];
195 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
196 print_usage(argv[0]);
199 fprintf(stderr, "invalid option: %s\n", argv[i]);
204 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
211 if(!repo_path) repo_path = ".";