From patchwork Tue Nov 20 20:27:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 200508 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from userp1040.oracle.com (userp1040.oracle.com [156.151.31.81]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "userp1040.oracle.com", Issuer "VeriSign Class 3 International Server CA - G3" (not verified)) by ozlabs.org (Postfix) with ESMTPS id AA35D2C007C for ; Wed, 21 Nov 2012 07:27:25 +1100 (EST) Received: from acsinet21.oracle.com (acsinet21.oracle.com [141.146.126.237]) by userp1040.oracle.com (Sentrion-MTA-4.2.2/Sentrion-MTA-4.2.2) with ESMTP id qAKKRLLx027522 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 20 Nov 2012 20:27:22 GMT Received: from oss.oracle.com (oss-external.oracle.com [137.254.96.51]) by acsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id qAKKRLiM022182 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 20 Nov 2012 20:27:21 GMT Received: from localhost ([127.0.0.1] helo=oss.oracle.com) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1TauPg-0002Dj-Uy; Tue, 20 Nov 2012 12:27:20 -0800 Received: from ucsinet22.oracle.com ([156.151.31.94]) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1TauPQ-0002CP-DP for fedfs-utils-devel@oss.oracle.com; Tue, 20 Nov 2012 12:27:04 -0800 Received: from acsinet12.oracle.com (acsinet12.oracle.com [141.146.126.234]) by ucsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id qAKKR36B019605 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 20 Nov 2012 20:27:03 GMT Received: from mail-ia0-f171.google.com (mail-ia0-f171.google.com [209.85.210.171]) by acsinet12.oracle.com (Sentrion-MTA-4.2.2/Sentrion-MTA-4.2.2) with ESMTP id qAKKQjXC026864 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Tue, 20 Nov 2012 20:27:02 GMT Received: by mail-ia0-f171.google.com with SMTP id b35so2152578iac.2 for ; Tue, 20 Nov 2012 12:27:02 -0800 (PST) Received: by 10.42.249.138 with SMTP id mk10mr12144576icb.42.1353443222769; Tue, 20 Nov 2012 12:27:02 -0800 (PST) Received: from seurat.1015granger.net (adsl-99-26-161-222.dsl.sfldmi.sbcglobal.net. [99.26.161.222]) by mx.google.com with ESMTPS id kp4sm11227880igc.1.2012.11.20.12.27.01 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 20 Nov 2012 12:27:02 -0800 (PST) From: Chuck Lever To: fedfs-utils-devel@oss.oracle.com Date: Tue, 20 Nov 2012 15:27:01 -0500 Message-ID: <20121120202701.47389.69645.stgit@seurat.1015granger.net> In-Reply-To: <20121120201753.47389.51902.stgit@seurat.1015granger.net> References: <20121120201753.47389.51902.stgit@seurat.1015granger.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Flow-Control-Info: class=Default reputation=ipRepBelow100 ip=209.85.210.171 ct-class=R5 ct-vol1=0 ct-vol2=8 ct-vol3=7 ct-risk=50 ct-spam1=80 ct-spam2=7 ct-bulk=6 rcpts=1 size=11752 X-MM-CT-Classification: not spam X-MM-CT-RefID: str=0001.0A090206.50ABE797.001D,ss=1,re=-2.300,fgs=0 Subject: [fedfs-utils] [PATCH 4/7] libnsdb: Add nsdb_get_fsn() X-BeenThere: fedfs-utils-devel@oss.oracle.com X-Mailman-Version: 2.1.9 Precedence: list Reply-To: fedfs-utils Developers List-Id: fedfs-utils Developers List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: fedfs-utils-devel-bounces@oss.oracle.com Errors-To: fedfs-utils-devel-bounces@oss.oracle.com X-Source-IP: acsinet21.oracle.com [141.146.126.237] Resolving an FSN is a little different than reading just the information in an FSN record. Introduce nsdb_get_fsn(), which retrieves the contents of an FSN record without resolving it. Signed-off-by: Chuck Lever --- src/include/nsdb.h | 28 ++++ src/libnsdb/fileserver.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 370 insertions(+), 0 deletions(-) diff --git a/src/include/nsdb.h b/src/include/nsdb.h index 58a5d52..a115fae 100644 --- a/src/include/nsdb.h +++ b/src/include/nsdb.h @@ -48,6 +48,31 @@ struct fedfs_secdata { }; /** + * Object that contains FedFS Fileset Name data + * + * Derived from the fedfsFsn object class, defined in + * the NSDB protocol draft, chapter 4, section 2.2.2 + */ +struct fedfs_fsn { + char *fn_dn; + + char fn_fsnuuid[FEDFS_UUID_STRLEN]; + int fn_fsnttl; + char **fn_annotations; + char **fn_description; +}; + +/** + ** API to manage struct fedfs_fsn objects + **/ + +/** + * Release a struct fedfs_fsn + */ +void nsdb_free_fedfs_fsn(struct fedfs_fsn *fsn); + + +/** * Object that contains FedFS NFS fileset Location data * * Derived from the fedfsNfsFsl object class, defined in @@ -327,6 +352,9 @@ FedFsStatus nsdb_find_naming_context_s(nsdb_t host, const char *entry, FedFsStatus nsdb_resolve_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, struct fedfs_fsl **fsls, unsigned int *ldap_err); +FedFsStatus nsdb_get_fsn_s(nsdb_t host, const char *nce, + const char *fsn_uuid, struct fedfs_fsn **fsn, + unsigned int *ldap_err); /** ** NSDB fileserver operations defined by this implementation diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c index fe09604..a047aba 100644 --- a/src/libnsdb/fileserver.c +++ b/src/libnsdb/fileserver.c @@ -49,6 +49,34 @@ static struct timeval nsdb_ldap_timeout = { 5, 0 }; /** + * Free a single struct fedfs_fsn + * + * @param fsn pointer to struct fedfs_fsn to free + */ +void +nsdb_free_fedfs_fsn(struct fedfs_fsn *fsn) +{ + nsdb_free_string_array(fsn->fn_description); + nsdb_free_string_array(fsn->fn_annotations); + free(fsn->fn_dn); + free(fsn); +} + +/** + * Allocate a new struct fedfs_fsn + * + * @return a malloc'd struct fedfs_fsn, or NULL + * + * Caller must free the returned memory with free(3) + */ +__attribute_malloc__ +static struct fedfs_fsn * +nsdb_alloc_fedfs_fsn(void) +{ + return calloc(1, sizeof(struct fedfs_fsn)); +} + +/** * Free a single struct fedfs_fsl * * @param fsl pointer to struct fedfs_fsl to free @@ -972,6 +1000,320 @@ out: } /** + * Parse objectClass attribute of a fedfsFsn + * + * @param attr a NUL-terminated C string containing the name of an attribute + * @param values array of values for this attribute + * @return a FedFsStatus code + */ +static FedFsStatus +nsdb_get_fsn_parse_objectclass(char *attr, struct berval **values) +{ + char **objectclass; + FedFsStatus retval; + int i; + + retval = nsdb_parse_multivalue_str(attr, values, &objectclass); + if (retval != FEDFS_OK) + return retval; + + retval = FEDFS_ERR_NSDB_RESPONSE; + for (i = 0; objectclass[i] != NULL; i++) + if (strcasecmp(objectclass[i], "fedfsFsn") == 0) + retval = FEDFS_OK; + + nsdb_free_string_array(objectclass); + return retval; +} + + +/** + * Parse the values of each attribute in a fedfsFsn object + * + * @param ld an initialized LDAP server descriptor + * @param entry an LDAP search result message + * @param attr a NUL-terminated C string containing the name of an attribute + * @param fsn OUT: fedfs_fsn structure to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nsdb_get_fsn_parse_attribute(LDAP *ld, LDAPMessage *entry, char *attr, + struct fedfs_fsn *fsn) +{ + struct berval **values; + FedFsStatus retval; + + values = ldap_get_values_len(ld, entry, attr); + if (values == NULL) { + xlog(D_GENERAL, "%s: No values found for attribute %s", + __func__, attr); + return FEDFS_OK; + } + + if (strcasecmp(attr, "objectClass") == 0) + retval = nsdb_get_fsn_parse_objectclass(attr, values); + else if (strcasecmp(attr, "fedfsFsnUuid") == 0) + retval = nsdb_parse_singlevalue_str(attr, values, + fsn->fn_fsnuuid, sizeof(fsn->fn_fsnuuid)); + else if (strcasecmp(attr, "fedfsFsnTTL") == 0) + retval = nsdb_parse_singlevalue_int(attr, values, + &fsn->fn_fsnttl); + else if (strcasecmp(attr, "fedfsAnnotation") == 0) + retval = nsdb_parse_annotations(values, &fsn->fn_annotations); + else if (strcasecmp(attr, "fedfsDescr") == 0) + retval = nsdb_parse_multivalue_str(attr, values, + &fsn->fn_description); + else { + /* Ignore anything we don't recognize */ + xlog(D_GENERAL, "%s: Unrecognized attribute: %s", + __func__, attr); + retval = FEDFS_OK; + } + + ldap_value_free_len(values); + return retval; +} + +/** + * Construct a struct fedfs_fsn based on the returned "entry" + * + * @param ld an initialized LDAP server descriptor + * @param entry an LDAP_RES_SEARCH_ENTRY message + * @param fsn OUT: a fedfs_fsn structures + * @return a FedFsStatus code + * + * Caller must free the returned "fsn" using nsdb_free_fedfs_fsn(). + */ +static FedFsStatus +nsdb_get_fsn_parse_entry(LDAP *ld, LDAPMessage *entry, + struct fedfs_fsn **fsn) +{ + BerElement *field = NULL; + struct fedfs_fsn *new; + FedFsStatus retval; + char *attr, *dn; + + xlog(D_CALL, "%s: parsing entry", __func__); + + new = nsdb_alloc_fedfs_fsn(); + if (new == NULL) { + xlog(L_ERROR, "%s: Failed to allocate new fsn", __func__); + return FEDFS_ERR_SVRFAULT; + } + + dn = ldap_get_dn(ld, entry); + if (dn != NULL ) { + new->fn_dn = strdup(dn); + ldap_memfree(dn); + } + + for (attr = ldap_first_attribute(ld, entry, &field), retval = FEDFS_OK; + attr != NULL && retval == FEDFS_OK; + attr = ldap_next_attribute(ld, entry, field)) { + retval = nsdb_get_fsn_parse_attribute(ld, entry, attr, new); + ldap_memfree(attr); + } + + if (field != NULL) + ber_free(field, 0); + + if (retval != FEDFS_OK) { + xlog(D_CALL, "%s: parsing failed: %s", + __func__, nsdb_display_fedfsstatus(retval)); + free(new->fn_dn); + free(new); + return retval; + } + + *fsn = new; + xlog(D_CALL, "%s: parsing complete", __func__); + return FEDFS_OK; +} + +/** + * Retrieve an FSN entry associated with an FSN UUID + * + * @param ld an initialized LDAP server descriptor + * @param nce a NUL-terminated C string containing DN of NSDB container entry + * @param fsn_uuid a NUL-terminated C string containing FSN UUID + * @param fsn OUT: a fedfs_fsn structures + * @param ldap_err OUT: possibly an LDAP error code + * @return a FedFsStatus code + * + * Caller must free the returned "fsn" using nsdb_free_fedfs_fsn(). + * + * ldapsearch equivalent: + * + * @verbatim + + ldapsearch -b "nce" -s one + (&(objectClass=fedfsFsn)(fedfsFsnUuid="fsn_uuid")) + @endverbatim + */ +static FedFsStatus +nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, + struct fedfs_fsn **fsn, unsigned int *ldap_err) +{ + LDAPMessage *response, *message; + struct fedfs_fsn *tmp; + FedFsStatus retval; + char filter[128]; + int len, rc; + + /* watch out for buffer overflow */ + len = snprintf(filter, sizeof(filter), + "(&(objectClass=fedfsFsn)(fedfsFsnUuid=%s))", fsn_uuid); + if (len < 0 || (size_t)len > sizeof(filter)) { + xlog(D_GENERAL, "%s: filter is too long", __func__); + return FEDFS_ERR_INVAL; + } + + rc = ldap_search_ext_s(ld, nce, LDAP_SCOPE_ONE, + filter, NULL, 0, NULL, NULL, + NULL, LDAP_NO_LIMIT, &response); + switch (rc) { + case LDAP_SUCCESS: + break; + case LDAP_NO_SUCH_OBJECT: + xlog(D_GENERAL, "%s: No FSN record for FSN UUID %s exists", + __func__, fsn_uuid); + return FEDFS_ERR_NSDB_NOFSN; + default: + xlog(D_GENERAL, "%s: LDAP search failed: %s", + __func__, ldap_err2string(rc)); + *ldap_err = rc; + return FEDFS_ERR_NSDB_LDAP_VAL; + } + if (response == NULL) { + xlog(D_GENERAL, "%s: Empty LDAP response", __func__); + return FEDFS_ERR_NSDB_FAULT; + } + + rc = ldap_count_messages(ld, response); + switch (rc) { + case -1: + xlog(D_GENERAL, "%s: Empty LDAP response", __func__); + ldap_msgfree(response); + return FEDFS_ERR_NSDB_FAULT; + case 1: + xlog(D_GENERAL, "%s: No FSN record for FSN UUID %s exists", + __func__, fsn_uuid); + ldap_msgfree(response); + return FEDFS_ERR_NSDB_NOFSN; + default: + xlog(D_CALL, "%s: Received %d messages", __func__, rc); + break; + } + + tmp = NULL; + retval = FEDFS_OK; + for (message = ldap_first_message(ld, response); + message != NULL && retval == FEDFS_OK; + message = ldap_next_message(ld, message)) { + switch (ldap_msgtype(message)) { + case LDAP_RES_SEARCH_ENTRY: + retval = nsdb_get_fsn_parse_entry(ld, message, &tmp); + break; + case LDAP_RES_SEARCH_REFERENCE: + retval = nsdb_parse_reference(ld, message, ldap_err); + break; + case LDAP_RES_SEARCH_RESULT: + retval = nsdb_parse_result(ld, message, ldap_err); + break; + default: + xlog(L_ERROR, "%s: Unrecognized LDAP message type", + __func__); + retval = FEDFS_ERR_NSDB_FAULT; + } + } + ldap_msgfree(response); + + if (retval == FEDFS_OK) { + xlog(D_CALL, "%s: returning fsn", __func__); + *fsn = tmp; + } else + nsdb_free_fedfs_fsn(tmp); + return retval; +} + +/** + * Retrieve an FSN record under "nce" + * + * @param host an initialized and bound nsdb_t object + * @param nce a NUL-terminated C string containing DN of NSDB container entry + * @param fsn_uuid a NUL-terminated C string containing FSN UUID + * @param fsn OUT: a fedfs_fsn structures + * @param ldap_err OUT: possibly an LDAP error code + * @return a FedFsStatus code + * + * If caller did not provide an NCE, discover one by querying the NSDB. + * + * Caller must free the returned "fsn" using nsdb_free_fedfs_fsn(). + */ +FedFsStatus +nsdb_get_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, + struct fedfs_fsn **fsn, unsigned int *ldap_err) +{ + char **contexts, **nce_list; + FedFsStatus retval; + int i, j; + + if (host->fn_ldap == NULL) { + xlog(L_ERROR, "%s: NSDB not open", __func__); + return FEDFS_ERR_INVAL; + } + + if (fsn == NULL || ldap_err == NULL) { + xlog(L_ERROR, "%s: Invalid parameter", __func__); + return FEDFS_ERR_INVAL; + } + + if (nce != NULL) + return nsdb_get_fsn_find_entry_s(host->fn_ldap, nce, + fsn_uuid, fsn, ldap_err); + + /* + * Caller did not provide an nce. Generate a list + * of the server's NSDB container entries. + */ + retval = nsdb_get_naming_contexts_s(host, &contexts, ldap_err); + if (retval != FEDFS_OK) + return retval; + + for (i = 0; contexts[i] != NULL; i++); + nce_list = calloc(i + 1, sizeof(char *)); + if (nce_list == NULL) { + retval = FEDFS_ERR_INVAL; + goto out; + } + + /* + * Query only naming contexts that have an NCE prefix + */ + for (i = 0, j = 0; contexts[i] != NULL; i++) { + retval = nsdb_get_ncedn_s(host, contexts[i], + &nce_list[j], ldap_err); + if (retval == FEDFS_OK) + j++; + } + if (j == 0) + goto out; + + for (j = 0; nce_list[j] != NULL; j++) { + retval = nsdb_get_fsn_find_entry_s(host->fn_ldap, + nce_list[j], fsn_uuid, + fsn, ldap_err); + if (retval == FEDFS_OK) + break; + } + +out: + nsdb_free_string_array(nce_list); + nsdb_free_string_array(contexts); + return retval; +} + +/** * Parse fedfsFsn attributes * * @param ld an initialized LDAP descriptor