]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/dbd/cnid_dbd.c
add nodev volume option (always use 0 for device number).
[netatalk.git] / libatalk / cnid / dbd / cnid_dbd.c
1 /*
2  * $Id: cnid_dbd.c,v 1.1.4.9 2004-01-03 22:21:09 didg Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 /*
9  *  Replacement functions for cnid_xxx if we use the cnid_dbd database
10  *  daemon. Basically we just check parameters for obvious errors and then pass
11  *  the request to the daemon for further processing.
12  *  
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #ifdef CNID_BACKEND_DBD
20
21 #include <stdlib.h>
22 #ifdef HAVE_SYS_STAT_H
23 #include <sys/stat.h>
24 #endif /* HAVE_SYS_STAT_H */
25 #ifdef HAVE_SYS_UIO_H
26 #include <sys/uio.h>
27 #endif /* HAVE_SYS_UIO_H */
28 #ifdef HAVE_STRINGS_H
29 #include <strings.h>
30 #endif
31 #include <sys/time.h>
32 #include <sys/un.h>
33 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <errno.h>
36 #include <netinet/in.h>
37 #include <net/if.h>
38 #include <netinet/tcp.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <errno.h>
42 #include <netdb.h>
43
44 #include <netatalk/endian.h>
45 #include <atalk/logger.h>
46 #include <atalk/adouble.h>
47 #include <atalk/cnid.h>
48 #include "cnid_dbd.h"
49 #include <atalk/cnid_dbd_private.h>
50
51 #ifndef SOL_TCP
52 #define SOL_TCP IPPROTO_TCP
53 #endif /* ! SOL_TCP */
54
55 static void RQST_RESET(struct cnid_dbd_rqst  *r) 
56
57    memset(r, 0, sizeof(struct cnid_dbd_rqst ));
58 }
59
60 /* ----------- */
61 extern char             *Cnid_srv;
62 extern int              Cnid_port;
63
64 static int tsock_getfd(char *host, int port, int silent)
65 {
66 int sock;
67 struct sockaddr_in server;
68 struct hostent* hp;
69 int attr;
70  
71     server.sin_family=AF_INET;
72     server.sin_port=htons((unsigned short)port);
73     if (!host) {
74         LOG(log_error, logtype_cnid, "transmit: -cnidserver not defined");
75         return -1;
76     }
77     
78     hp=gethostbyname(host);
79     if (!hp) {
80         unsigned long int addr=inet_addr(host);
81         if (addr!= (unsigned)-1)
82             hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
83  
84         if (!hp) {
85             if (!silent)
86                 LOG(log_error, logtype_cnid, "transmit: get_fd %s: %s", host, strerror(errno));
87             return(-1);
88         }
89     }
90     memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
91     sock=socket(PF_INET,SOCK_STREAM,0);
92     if (sock==-1) {
93         if (!silent)
94             LOG(log_error, logtype_cnid, "transmit: socket %s: %s", host, strerror(errno));
95         return(-1);
96     }
97     attr = 1;
98     setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr));
99     if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
100         struct timeval tv;
101         switch (errno) {
102         case ENETUNREACH:
103         case ECONNREFUSED: 
104             
105             tv.tv_usec = 0;
106             tv.tv_sec  = 5;
107             select(0, NULL, NULL, NULL, &tv);
108             break;
109         }
110         close(sock);
111         sock=-1;
112         if (!silent)
113             LOG(log_error, logtype_cnid, "transmit: connect %s: %s", host, strerror(errno));
114     }
115     return(sock);
116 }
117
118 /* --------------------- */
119 static int init_tsockfn(CNID_private *db)
120 {
121     int fd;
122     int len;
123     
124     if ((fd = tsock_getfd(Cnid_srv, Cnid_port, 0)) < 0) 
125         return -1;
126     len = strlen(db->db_dir);
127     if (write(fd, &len, sizeof(int)) != sizeof(int)) {
128         LOG(log_error, logtype_cnid, "get_usock: Error/short write: %s", strerror(errno));
129         close(fd);
130         return -1;
131     }
132     if (write(fd, db->db_dir, len) != len) {
133         LOG(log_error, logtype_cnid, "get_usock: Error/short write dir: %s", strerror(errno));
134         close(fd);
135         return -1;
136     }
137     return fd;
138 }
139
140 /* --------------------- */
141 static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
142 {
143     struct iovec iov[2];
144     size_t towrite;
145     ssize_t len;
146   
147     iov[0].iov_base = rqst;
148     iov[0].iov_len  = sizeof(struct cnid_dbd_rqst);
149     
150     if (!rqst->namelen) {
151         if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
152             return -1;
153         }
154         return 0;
155     }
156     iov[1].iov_base = rqst->name;
157     iov[1].iov_len  = rqst->namelen;
158
159     towrite = sizeof(struct cnid_dbd_rqst) +rqst->namelen;
160     while (towrite > 0) {
161         if (((len = writev(db->fd, iov, 2)) == -1 && errno == EINTR) || !len)
162             continue;
163  
164         if (len == towrite) /* wrote everything out */
165             break;
166         else if (len < 0) { /* error */
167             return -1;
168         }
169  
170         towrite -= len;
171         if (towrite > rqst->namelen) { /* skip part of header */
172             iov[0].iov_base = (char *) iov[0].iov_base + len;
173             iov[0].iov_len -= len;
174         } else { /* skip to data */
175             if (iov[0].iov_len) {
176                 len -= iov[0].iov_len;
177                 iov[0].iov_len = 0;
178             }
179             iov[1].iov_base = (char *) iov[1].iov_base + len;
180             iov[1].iov_len -= len;
181         }
182     }
183     return 0;
184 }
185
186 /* --------------------- */
187 static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
188 {
189     char *nametmp;
190     int  ret;
191     
192     while (1) {
193
194         if (db->fd == -1 && (db->fd = init_tsockfn(db)) < 0) {
195             goto transmit_fail;
196         }
197         if (send_packet(db, rqst) < 0) {
198             goto transmit_fail;
199         }
200         nametmp = rply->name;
201         if ((ret = read(db->fd, rply, sizeof(struct cnid_dbd_rply))) != sizeof(struct cnid_dbd_rply)) {
202             LOG(log_error, logtype_cnid, "transmit: Error reading header from fd for usock %s: %s",
203                 db->usock_file, ret == -1?strerror(errno):"closed");
204             rply->name = nametmp;
205             goto transmit_fail;
206         }
207         rply->name = nametmp;
208         if (rply->namelen && (ret = read(db->fd, rply->name, rply->namelen)) != rply->namelen) {
209             LOG(log_error, logtype_cnid, "transmit: Error reading name from fd for usock %s: %s",
210                 db->usock_file, ret == -1?strerror(errno):"closed");
211             goto transmit_fail;
212         }
213         return 0;
214  
215  transmit_fail:
216 {
217         struct timeval tv;
218             tv.tv_usec = 0;
219             tv.tv_sec  = 5;
220             select(0, NULL, NULL, NULL, &tv);
221 }
222
223         if (db->fd != -1) {
224             close(db->fd);
225         }
226         db->fd = -1;
227     }
228     return -1;
229 }
230
231 static struct _cnid_db *cnid_dbd_new(const char *volpath)
232 {
233     struct _cnid_db *cdb;
234     
235     if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
236         return NULL;
237         
238     if ((cdb->volpath = strdup(volpath)) == NULL) {
239         free(cdb);
240         return NULL;
241     }
242     
243     cdb->flags = CNID_FLAG_PERSISTENT;
244     
245     cdb->cnid_add = cnid_dbd_add;
246     cdb->cnid_delete = cnid_dbd_delete;
247     cdb->cnid_get = cnid_dbd_get;
248     cdb->cnid_lookup = cnid_dbd_lookup;
249     cdb->cnid_nextid = NULL;
250     cdb->cnid_resolve = cnid_dbd_resolve;
251     cdb->cnid_getstamp = cnid_dbd_getstamp;
252     cdb->cnid_update = cnid_dbd_update;
253     cdb->cnid_close = cnid_dbd_close;
254     
255     return cdb;
256 }
257
258 /* ---------------------- */
259 struct _cnid_db *cnid_dbd_open(const char *dir, mode_t mask)
260 {
261     CNID_private *db = NULL;
262     struct _cnid_db *cdb = NULL;
263
264     if (!dir) {
265          return NULL;
266     }
267     
268     if ((cdb = cnid_dbd_new(dir)) == NULL) {
269         LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
270         return NULL;
271     }
272         
273     if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
274         LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
275         goto cnid_dbd_open_fail;
276     }
277     
278     cdb->_private = db;
279
280     /* We keep a copy of the directory in the db structure so that we can
281        transparently reconnect later. */
282     strcpy(db->db_dir, dir);
283     db->usock_file[0] = '\0';
284     db->magic = CNID_DB_MAGIC;
285     db->fd = -1;
286 #ifdef DEBUG
287     LOG(log_info, logtype_cnid, "opening database connection to %s", db->db_dir); 
288 #endif
289     return cdb;
290
291 cnid_dbd_open_fail:
292     if (cdb != NULL) {
293         if (cdb->volpath != NULL) {
294             free(cdb->volpath);
295         }
296         free(cdb);
297     }
298     if (db != NULL)
299         free(db);
300         
301     return NULL;
302 }
303
304 /* ---------------------- */
305 void cnid_dbd_close(struct _cnid_db *cdb)
306 {
307     CNID_private *db;
308
309     if (!cdb) {
310         LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
311         return;
312     }
313
314     if ((db = cdb->_private) != NULL) {
315 #ifdef DEBUG 
316         LOG(log_info, logtype_cnid, "closing database connection to %s", db->db_dir);
317 #endif  
318         if (db->fd >= 0)
319             close(db->fd);
320         free(db);
321     }
322     
323     free(cdb->volpath);
324     free(cdb);
325     
326     return;
327 }
328
329 /* ---------------------- */
330 cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
331                 const cnid_t did, const char *name, const int len,
332                 cnid_t hint)
333 {
334     CNID_private *db;
335     struct cnid_dbd_rqst rqst;
336     struct cnid_dbd_rply rply;
337     cnid_t id;
338
339     if (!cdb || !(db = cdb->_private) || !st || !name) {
340         LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
341         errno = CNID_ERR_PARAM;
342         return CNID_INVALID;
343     }
344
345     if (len > MAXPATHLEN) {
346         LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
347         errno = CNID_ERR_PATH;
348         return CNID_INVALID;
349     }
350
351     RQST_RESET(&rqst);
352     rqst.op = CNID_DBD_OP_ADD;
353
354     if (!(cdb->flags & CNID_FLAG_NODEV)) {
355         rqst.dev = st->st_dev;
356     }
357
358     rqst.ino = st->st_ino;
359     rqst.type = S_ISDIR(st->st_mode)?1:0;
360     rqst.did = did;
361     rqst.name = name;
362     rqst.namelen = len;
363
364     if (transmit(db, &rqst, &rply) < 0) {
365         errno = CNID_ERR_DB;
366         return CNID_INVALID;
367     }
368     
369     switch(rply.result) {
370     case CNID_DBD_RES_OK:
371         id = rply.cnid;
372         break;
373     case CNID_DBD_RES_ERR_MAX:
374         errno = CNID_ERR_MAX;
375         id = CNID_INVALID;
376         break;
377     case CNID_DBD_RES_ERR_DB:
378     case CNID_DBD_RES_ERR_DUPLCNID:
379         errno = CNID_ERR_DB;
380         id = CNID_INVALID;
381         break;
382     default:
383         abort();
384     }
385     return id;
386 }
387
388 /* ---------------------- */
389 cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, const char *name,
390                 const int len)
391 {
392     CNID_private *db;
393     struct cnid_dbd_rqst rqst;
394     struct cnid_dbd_rply rply;
395     cnid_t id;
396
397
398     if (!cdb || !(db = cdb->_private) || !name) {
399         LOG(log_error, logtype_cnid, "cnid_get: Parameter error");
400         errno = CNID_ERR_PARAM;        
401         return CNID_INVALID;
402     }
403
404     if (len > MAXPATHLEN) {
405         LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
406         errno = CNID_ERR_PATH;
407         return CNID_INVALID;
408     }
409
410     RQST_RESET(&rqst);
411     rqst.op = CNID_DBD_OP_GET;
412     rqst.did = did;
413     rqst.name = name;
414     rqst.namelen = len;
415
416     if (transmit(db, &rqst, &rply) < 0) {
417         errno = CNID_ERR_DB;
418         return CNID_INVALID;
419     }
420     
421     switch(rply.result) {
422     case CNID_DBD_RES_OK:
423         id = rply.cnid;
424         break;
425     case CNID_DBD_RES_NOTFOUND:
426         id = CNID_INVALID;
427         break;
428     case CNID_DBD_RES_ERR_DB:
429         id = CNID_INVALID;
430         errno = CNID_ERR_DB;
431         break;
432     default: 
433         abort();
434     }
435
436     return id;
437 }
438
439 /* ---------------------- */
440 char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
441 {
442     CNID_private *db;
443     struct cnid_dbd_rqst rqst;
444     struct cnid_dbd_rply rply;
445     char *name;
446
447     if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
448         LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
449         errno = CNID_ERR_PARAM;                
450         return NULL;
451     }
452
453     /* TODO: We should maybe also check len. At the moment we rely on the caller
454        to provide a buffer that is large enough for MAXPATHLEN plus
455        CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
456        can come from the database. */
457
458     RQST_RESET(&rqst);
459     rqst.op = CNID_DBD_OP_RESOLVE;
460     rqst.cnid = *id;
461
462     /* This mimicks the behaviour of the "regular" cnid_resolve. So far,
463        nobody uses the content of buffer. It only provides space for the
464        name in the caller. */
465     rply.name = buffer + CNID_HEADER_LEN;
466
467     if (transmit(db, &rqst, &rply) < 0) {
468         errno = CNID_ERR_DB;
469         *id = CNID_INVALID;
470         return NULL;
471     }
472
473     switch (rply.result) {
474     case CNID_DBD_RES_OK:
475         *id = rply.did;
476         name = rply.name;
477         break;
478     case CNID_DBD_RES_NOTFOUND:
479         *id = CNID_INVALID;
480         name = NULL;
481         break;
482     case CNID_DBD_RES_ERR_DB:
483         errno = CNID_ERR_DB;
484         *id = CNID_INVALID;
485         name = NULL;
486         break;
487     default:
488         abort();
489     }
490
491     return name;
492 }
493
494 /* ---------------------- */
495 cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
496                    const char *name, const int len)
497 {
498     CNID_private *db;
499     struct cnid_dbd_rqst rqst;
500     struct cnid_dbd_rply rply;
501     cnid_t id;
502
503     if (!cdb || !(db = cdb->_private) || !st || !name) {
504         LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
505         errno = CNID_ERR_PARAM;        
506         return CNID_INVALID;
507     }
508
509     if (len > MAXPATHLEN) {
510         LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long");
511         errno = CNID_ERR_PATH;
512         return CNID_INVALID;
513     }
514
515     RQST_RESET(&rqst);
516     rqst.op = CNID_DBD_OP_LOOKUP;
517
518     if (!(cdb->flags & CNID_FLAG_NODEV)) {
519         rqst.dev = st->st_dev;
520     }
521
522     rqst.ino = st->st_ino;
523     rqst.type = S_ISDIR(st->st_mode)?1:0;
524     rqst.did = did;
525     rqst.name = name;
526     rqst.namelen = len;
527
528     if (transmit(db, &rqst, &rply) < 0) {
529         errno = CNID_ERR_DB;
530         return CNID_INVALID;
531     }
532
533     switch (rply.result) {
534     case CNID_DBD_RES_OK:
535         id = rply.cnid;
536         break;
537     case CNID_DBD_RES_NOTFOUND:
538         id = CNID_INVALID;
539         break;
540     case CNID_DBD_RES_ERR_DB:
541         errno = CNID_ERR_DB;
542         id = CNID_INVALID;
543         break;
544     default:
545         abort();
546     }
547
548     return id;
549 }
550
551 /* ---------------------- */
552 int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
553                 const cnid_t did, const char *name, const int len)
554 {
555     CNID_private *db;
556     struct cnid_dbd_rqst rqst;
557     struct cnid_dbd_rply rply;
558
559     
560     if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
561         LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
562         errno = CNID_ERR_PARAM;        
563         return -1;
564     }
565
566     if (len > MAXPATHLEN) {
567         LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
568         errno = CNID_ERR_PATH;
569         return -1;
570     }
571
572     RQST_RESET(&rqst);
573     rqst.op = CNID_DBD_OP_UPDATE;
574     rqst.cnid = id;
575     if (!(cdb->flags & CNID_FLAG_NODEV)) {
576         rqst.dev = st->st_dev;
577     }
578     rqst.ino = st->st_ino;
579     rqst.type = S_ISDIR(st->st_mode)?1:0;
580     rqst.did = did;
581     rqst.name = name;
582     rqst.namelen = len;
583
584     if (transmit(db, &rqst, &rply) < 0) {
585         errno = CNID_ERR_DB;
586         return -1;
587     }
588
589     switch (rply.result) {
590     case CNID_DBD_RES_OK:
591     case CNID_DBD_RES_NOTFOUND:
592         return 0;
593     case CNID_DBD_RES_ERR_DB:
594         errno = CNID_ERR_DB;
595         return -1;
596     default:
597         abort();
598     }
599 }
600
601 /* ---------------------- */
602 int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id) 
603 {
604     CNID_private *db;
605     struct cnid_dbd_rqst rqst;
606     struct cnid_dbd_rply rply;
607
608
609     if (!cdb || !(db = cdb->_private) || !id) {
610         LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
611         errno = CNID_ERR_PARAM;        
612         return -1;
613     }
614
615     RQST_RESET(&rqst);
616     rqst.op = CNID_DBD_OP_DELETE;
617     rqst.cnid = id;
618
619     if (transmit(db, &rqst, &rply) < 0) {
620         errno = CNID_ERR_DB;
621         return -1;
622     }
623
624     switch (rply.result) {
625     case CNID_DBD_RES_OK:
626     case CNID_DBD_RES_NOTFOUND:
627         return 0;
628     case CNID_DBD_RES_ERR_DB:
629         errno = CNID_ERR_DB;
630         return -1;
631     default:
632         abort();
633     }
634 }
635
636 /* ---------------------- */
637 int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
638 {
639     CNID_private *db;
640     struct cnid_dbd_rqst rqst;
641     struct cnid_dbd_rply rply;
642
643     /* FIXME: We rely on len == ADEDLEN_PRIVSYN == CNID_DEV_LEN here as well as
644        in the backend. There should really be a constant for that value that is
645        used throughout. Also, returning the stamp via the name field is somewhat
646        fishy. */
647
648     if (!cdb || !(db = cdb->_private)) {
649         LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
650         errno = CNID_ERR_PARAM;                
651         return -1;
652     }
653
654
655     RQST_RESET(&rqst);
656     rqst.op = CNID_DBD_OP_GETSTAMP;
657     memset(buffer, 0, len);
658
659     rply.name = buffer;
660
661     if (transmit(db, &rqst, &rply) < 0) {
662         errno = CNID_ERR_DB;
663         return -1;
664     }
665
666     switch (rply.result) {
667     case CNID_DBD_RES_OK:
668         break;
669     case CNID_DBD_RES_NOTFOUND:
670         return -1;
671     case CNID_DBD_RES_ERR_DB:
672         errno = CNID_ERR_DB;
673         return -1;
674     default:
675         abort();
676     }
677     return 0;
678 }
679
680 struct _cnid_module cnid_dbd_module = {
681     "dbd",
682     {NULL, NULL},
683     cnid_dbd_open,
684 };
685
686 #endif /* CNID_DBD */