2 * $Id: cnid_dbd.c,v 1.1.4.9 2004-01-03 22:21:09 didg Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * All Rights Reserved. See COPYRIGHT.
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.
17 #endif /* HAVE_CONFIG_H */
19 #ifdef CNID_BACKEND_DBD
22 #ifdef HAVE_SYS_STAT_H
24 #endif /* HAVE_SYS_STAT_H */
27 #endif /* HAVE_SYS_UIO_H */
33 #include <sys/socket.h>
34 #include <sys/param.h>
36 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
44 #include <netatalk/endian.h>
45 #include <atalk/logger.h>
46 #include <atalk/adouble.h>
47 #include <atalk/cnid.h>
49 #include <atalk/cnid_dbd_private.h>
52 #define SOL_TCP IPPROTO_TCP
53 #endif /* ! SOL_TCP */
55 static void RQST_RESET(struct cnid_dbd_rqst *r)
57 memset(r, 0, sizeof(struct cnid_dbd_rqst ));
61 extern char *Cnid_srv;
64 static int tsock_getfd(char *host, int port, int silent)
67 struct sockaddr_in server;
71 server.sin_family=AF_INET;
72 server.sin_port=htons((unsigned short)port);
74 LOG(log_error, logtype_cnid, "transmit: -cnidserver not defined");
78 hp=gethostbyname(host);
80 unsigned long int addr=inet_addr(host);
81 if (addr!= (unsigned)-1)
82 hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
86 LOG(log_error, logtype_cnid, "transmit: get_fd %s: %s", host, strerror(errno));
90 memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
91 sock=socket(PF_INET,SOCK_STREAM,0);
94 LOG(log_error, logtype_cnid, "transmit: socket %s: %s", host, strerror(errno));
98 setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr));
99 if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
107 select(0, NULL, NULL, NULL, &tv);
113 LOG(log_error, logtype_cnid, "transmit: connect %s: %s", host, strerror(errno));
118 /* --------------------- */
119 static int init_tsockfn(CNID_private *db)
124 if ((fd = tsock_getfd(Cnid_srv, Cnid_port, 0)) < 0)
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));
132 if (write(fd, db->db_dir, len) != len) {
133 LOG(log_error, logtype_cnid, "get_usock: Error/short write dir: %s", strerror(errno));
140 /* --------------------- */
141 static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
147 iov[0].iov_base = rqst;
148 iov[0].iov_len = sizeof(struct cnid_dbd_rqst);
150 if (!rqst->namelen) {
151 if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
156 iov[1].iov_base = rqst->name;
157 iov[1].iov_len = rqst->namelen;
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)
164 if (len == towrite) /* wrote everything out */
166 else if (len < 0) { /* error */
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;
179 iov[1].iov_base = (char *) iov[1].iov_base + len;
180 iov[1].iov_len -= len;
186 /* --------------------- */
187 static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
194 if (db->fd == -1 && (db->fd = init_tsockfn(db)) < 0) {
197 if (send_packet(db, rqst) < 0) {
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;
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");
220 select(0, NULL, NULL, NULL, &tv);
231 static struct _cnid_db *cnid_dbd_new(const char *volpath)
233 struct _cnid_db *cdb;
235 if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
238 if ((cdb->volpath = strdup(volpath)) == NULL) {
243 cdb->flags = CNID_FLAG_PERSISTENT;
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;
258 /* ---------------------- */
259 struct _cnid_db *cnid_dbd_open(const char *dir, mode_t mask)
261 CNID_private *db = NULL;
262 struct _cnid_db *cdb = NULL;
268 if ((cdb = cnid_dbd_new(dir)) == NULL) {
269 LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
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;
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;
287 LOG(log_info, logtype_cnid, "opening database connection to %s", db->db_dir);
293 if (cdb->volpath != NULL) {
304 /* ---------------------- */
305 void cnid_dbd_close(struct _cnid_db *cdb)
310 LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
314 if ((db = cdb->_private) != NULL) {
316 LOG(log_info, logtype_cnid, "closing database connection to %s", db->db_dir);
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,
335 struct cnid_dbd_rqst rqst;
336 struct cnid_dbd_rply rply;
339 if (!cdb || !(db = cdb->_private) || !st || !name) {
340 LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
341 errno = CNID_ERR_PARAM;
345 if (len > MAXPATHLEN) {
346 LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
347 errno = CNID_ERR_PATH;
352 rqst.op = CNID_DBD_OP_ADD;
354 if (!(cdb->flags & CNID_FLAG_NODEV)) {
355 rqst.dev = st->st_dev;
358 rqst.ino = st->st_ino;
359 rqst.type = S_ISDIR(st->st_mode)?1:0;
364 if (transmit(db, &rqst, &rply) < 0) {
369 switch(rply.result) {
370 case CNID_DBD_RES_OK:
373 case CNID_DBD_RES_ERR_MAX:
374 errno = CNID_ERR_MAX;
377 case CNID_DBD_RES_ERR_DB:
378 case CNID_DBD_RES_ERR_DUPLCNID:
388 /* ---------------------- */
389 cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, const char *name,
393 struct cnid_dbd_rqst rqst;
394 struct cnid_dbd_rply rply;
398 if (!cdb || !(db = cdb->_private) || !name) {
399 LOG(log_error, logtype_cnid, "cnid_get: Parameter error");
400 errno = CNID_ERR_PARAM;
404 if (len > MAXPATHLEN) {
405 LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
406 errno = CNID_ERR_PATH;
411 rqst.op = CNID_DBD_OP_GET;
416 if (transmit(db, &rqst, &rply) < 0) {
421 switch(rply.result) {
422 case CNID_DBD_RES_OK:
425 case CNID_DBD_RES_NOTFOUND:
428 case CNID_DBD_RES_ERR_DB:
439 /* ---------------------- */
440 char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
443 struct cnid_dbd_rqst rqst;
444 struct cnid_dbd_rply rply;
447 if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
448 LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
449 errno = CNID_ERR_PARAM;
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. */
459 rqst.op = CNID_DBD_OP_RESOLVE;
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;
467 if (transmit(db, &rqst, &rply) < 0) {
473 switch (rply.result) {
474 case CNID_DBD_RES_OK:
478 case CNID_DBD_RES_NOTFOUND:
482 case CNID_DBD_RES_ERR_DB:
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)
499 struct cnid_dbd_rqst rqst;
500 struct cnid_dbd_rply rply;
503 if (!cdb || !(db = cdb->_private) || !st || !name) {
504 LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
505 errno = CNID_ERR_PARAM;
509 if (len > MAXPATHLEN) {
510 LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long");
511 errno = CNID_ERR_PATH;
516 rqst.op = CNID_DBD_OP_LOOKUP;
518 if (!(cdb->flags & CNID_FLAG_NODEV)) {
519 rqst.dev = st->st_dev;
522 rqst.ino = st->st_ino;
523 rqst.type = S_ISDIR(st->st_mode)?1:0;
528 if (transmit(db, &rqst, &rply) < 0) {
533 switch (rply.result) {
534 case CNID_DBD_RES_OK:
537 case CNID_DBD_RES_NOTFOUND:
540 case CNID_DBD_RES_ERR_DB:
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)
556 struct cnid_dbd_rqst rqst;
557 struct cnid_dbd_rply rply;
560 if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
561 LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
562 errno = CNID_ERR_PARAM;
566 if (len > MAXPATHLEN) {
567 LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
568 errno = CNID_ERR_PATH;
573 rqst.op = CNID_DBD_OP_UPDATE;
575 if (!(cdb->flags & CNID_FLAG_NODEV)) {
576 rqst.dev = st->st_dev;
578 rqst.ino = st->st_ino;
579 rqst.type = S_ISDIR(st->st_mode)?1:0;
584 if (transmit(db, &rqst, &rply) < 0) {
589 switch (rply.result) {
590 case CNID_DBD_RES_OK:
591 case CNID_DBD_RES_NOTFOUND:
593 case CNID_DBD_RES_ERR_DB:
601 /* ---------------------- */
602 int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
605 struct cnid_dbd_rqst rqst;
606 struct cnid_dbd_rply rply;
609 if (!cdb || !(db = cdb->_private) || !id) {
610 LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
611 errno = CNID_ERR_PARAM;
616 rqst.op = CNID_DBD_OP_DELETE;
619 if (transmit(db, &rqst, &rply) < 0) {
624 switch (rply.result) {
625 case CNID_DBD_RES_OK:
626 case CNID_DBD_RES_NOTFOUND:
628 case CNID_DBD_RES_ERR_DB:
636 /* ---------------------- */
637 int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
640 struct cnid_dbd_rqst rqst;
641 struct cnid_dbd_rply rply;
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
648 if (!cdb || !(db = cdb->_private)) {
649 LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
650 errno = CNID_ERR_PARAM;
656 rqst.op = CNID_DBD_OP_GETSTAMP;
657 memset(buffer, 0, len);
661 if (transmit(db, &rqst, &rply) < 0) {
666 switch (rply.result) {
667 case CNID_DBD_RES_OK:
669 case CNID_DBD_RES_NOTFOUND:
671 case CNID_DBD_RES_ERR_DB:
680 struct _cnid_module cnid_dbd_module = {
686 #endif /* CNID_DBD */