19444c26fSTom Whitten /* 29444c26fSTom Whitten * CDDL HEADER START 39444c26fSTom Whitten * 49444c26fSTom Whitten * The contents of this file are subject to the terms of the 59444c26fSTom Whitten * Common Development and Distribution License (the "License"). 69444c26fSTom Whitten * You may not use this file except in compliance with the License. 79444c26fSTom Whitten * 89444c26fSTom Whitten * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99444c26fSTom Whitten * or http://www.opensolaris.org/os/licensing. 109444c26fSTom Whitten * See the License for the specific language governing permissions 119444c26fSTom Whitten * and limitations under the License. 129444c26fSTom Whitten * 139444c26fSTom Whitten * When distributing Covered Code, include this CDDL HEADER in each 149444c26fSTom Whitten * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159444c26fSTom Whitten * If applicable, add the following below this CDDL HEADER, with the 169444c26fSTom Whitten * fields enclosed by brackets "[]" replaced with your own identifying 179444c26fSTom Whitten * information: Portions Copyright [yyyy] [name of copyright owner] 189444c26fSTom Whitten * 199444c26fSTom Whitten * CDDL HEADER END 209444c26fSTom Whitten */ 219444c26fSTom Whitten 229444c26fSTom Whitten /* 23adfc3118STruong Nguyen * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 249444c26fSTom Whitten */ 259444c26fSTom Whitten 269444c26fSTom Whitten /* 279444c26fSTom Whitten * The primary role of this file is to obtain a list of manifests that are 289444c26fSTom Whitten * located in a specified directory or one of its subdirectories. The 299444c26fSTom Whitten * find_manifests() function provides this service, and 309444c26fSTom Whitten * free_manifest_array() is used to free the memory associated with the 319444c26fSTom Whitten * returned list. 329444c26fSTom Whitten * 339444c26fSTom Whitten * The find_manifests() function can return an array consisting of all the 349444c26fSTom Whitten * .xml files in the directory and its subdirectories. Alternatively, 359444c26fSTom Whitten * find_manifests() can be asked to only return new manifests based on the 369444c26fSTom Whitten * return of mhash_test_file(). The list that is returned is an array of 379444c26fSTom Whitten * pointers to manifest_info structures. 389444c26fSTom Whitten * 399444c26fSTom Whitten * Implementation Notes: 409444c26fSTom Whitten * ==================== 419444c26fSTom Whitten * This module makes use of the nftw(3C) function to scan the directory. 429444c26fSTom Whitten * nftw() calls a processing function for every file that it finds. 439444c26fSTom Whitten * Unfortunately, nftw does not allow us to pass in any structure pointers 449444c26fSTom Whitten * to the processing function, and that makes it hard to accumulate a list. 459444c26fSTom Whitten * Thus, we will use the thread specific data area to hold data that must 469444c26fSTom Whitten * be retained between calls to the processing function. This will allow 479444c26fSTom Whitten * this module to be used in multi-threaded applications if the need 489444c26fSTom Whitten * arises. 499444c26fSTom Whitten */ 509444c26fSTom Whitten 519444c26fSTom Whitten #include <assert.h> 529444c26fSTom Whitten #include <errno.h> 539444c26fSTom Whitten #include <ftw.h> 549444c26fSTom Whitten #include <libscf.h> 559444c26fSTom Whitten #include <libuutil.h> 569444c26fSTom Whitten #include <pthread.h> 579444c26fSTom Whitten #include <stdlib.h> 589444c26fSTom Whitten #include <string.h> 599444c26fSTom Whitten #include "manifest_find.h" 609444c26fSTom Whitten #include "manifest_hash.h" 619444c26fSTom Whitten 629444c26fSTom Whitten #define MAX_DEPTH 24 639444c26fSTom Whitten 649444c26fSTom Whitten /* Thread specific data */ 659444c26fSTom Whitten typedef struct mftsd { 669444c26fSTom Whitten manifest_info_t ** tsd_array; /* Array of manifest_info structs */ 679444c26fSTom Whitten int tsd_count; /* Number items in list */ 689444c26fSTom Whitten int tsd_max; /* Number of pointers allocated */ 699444c26fSTom Whitten /* at tsd_array. */ 709444c26fSTom Whitten int tsd_flags; /* Check flags for hash and extension */ 719444c26fSTom Whitten scf_handle_t *tsd_hndl; /* Handle for libscf. */ 729444c26fSTom Whitten } mftsd_t; 739444c26fSTom Whitten 749444c26fSTom Whitten static pthread_key_t tsd_key = PTHREAD_ONCE_KEY_NP; 759444c26fSTom Whitten 769444c26fSTom Whitten /* 779444c26fSTom Whitten * Add the manifest info consisting of filename (fn), hash property name 789444c26fSTom Whitten * (pname) and hash to the array at tsd_array. If necessary, realloc() 799444c26fSTom Whitten * will be called to increase the size of the buffer at tsd_array. 809444c26fSTom Whitten * 819444c26fSTom Whitten * Returns 0 on success and -1 on failure. If a failure occurs, errno will 829444c26fSTom Whitten * be set. 839444c26fSTom Whitten */ 849444c26fSTom Whitten static int 859444c26fSTom Whitten add_pointer(mftsd_t *tsdp, const char *fn, const char *pname, uchar_t *hash) 869444c26fSTom Whitten { 879444c26fSTom Whitten manifest_info_t *info; 889444c26fSTom Whitten manifest_info_t **newblock; 899444c26fSTom Whitten int new_max; 909444c26fSTom Whitten 919444c26fSTom Whitten if (tsdp->tsd_count >= (tsdp->tsd_max - 1)) { 929444c26fSTom Whitten /* Need more memory. */ 939444c26fSTom Whitten new_max = (tsdp->tsd_max == 0) ? 16 : 2 * tsdp->tsd_max; 949444c26fSTom Whitten newblock = realloc(tsdp->tsd_array, 959444c26fSTom Whitten new_max * sizeof (*tsdp->tsd_array)); 969444c26fSTom Whitten if (newblock == NULL) 979444c26fSTom Whitten return (-1); 989444c26fSTom Whitten tsdp->tsd_array = newblock; 999444c26fSTom Whitten /* NULL terminate list in case allocations fail below. */ 1009444c26fSTom Whitten *(tsdp->tsd_array + tsdp->tsd_count) = NULL; 1019444c26fSTom Whitten tsdp->tsd_max = new_max; 1029444c26fSTom Whitten } 1039444c26fSTom Whitten info = uu_zalloc(sizeof (*info)); 1049444c26fSTom Whitten if (info == NULL) { 1059444c26fSTom Whitten errno = ENOMEM; 1069444c26fSTom Whitten return (-1); 1079444c26fSTom Whitten } 1089444c26fSTom Whitten info->mi_path = uu_strdup(fn); 1099444c26fSTom Whitten if (info->mi_path == NULL) { 1109444c26fSTom Whitten uu_free(info); 1119444c26fSTom Whitten errno = ENOMEM; 1129444c26fSTom Whitten return (-1); 1139444c26fSTom Whitten } 1149444c26fSTom Whitten info->mi_prop = pname; 1159444c26fSTom Whitten if (hash != NULL) 1169444c26fSTom Whitten (void) memcpy(info->mi_hash, hash, MHASH_SIZE); 1179444c26fSTom Whitten *(tsdp->tsd_array + tsdp->tsd_count) = info; 1189444c26fSTom Whitten tsdp->tsd_count++; 1199444c26fSTom Whitten 1209444c26fSTom Whitten /* NULL terminate the list. */ 1219444c26fSTom Whitten *(tsdp->tsd_array + tsdp->tsd_count) = NULL; 1229444c26fSTom Whitten 1239444c26fSTom Whitten return (0); 1249444c26fSTom Whitten } 1259444c26fSTom Whitten 1269444c26fSTom Whitten /* 1279444c26fSTom Whitten * If necessary initialize the thread specific data key at tsd_key, and 1289444c26fSTom Whitten * allocate a mftsd_t structure to hold our thread specific data. Upon 1299444c26fSTom Whitten * success, the address the thread specific data is returned. On failure, 1309444c26fSTom Whitten * NULL is returned and errno is set. 1319444c26fSTom Whitten */ 1329444c26fSTom Whitten static mftsd_t * 1339444c26fSTom Whitten get_thread_specific_data() 1349444c26fSTom Whitten { 1359444c26fSTom Whitten mftsd_t *tsdp; 1369444c26fSTom Whitten 1379444c26fSTom Whitten if (pthread_key_create_once_np(&tsd_key, NULL) != 0) 1389444c26fSTom Whitten return (NULL); 1399444c26fSTom Whitten tsdp = (mftsd_t *)pthread_getspecific(tsd_key); 1409444c26fSTom Whitten if (tsdp == NULL) { 1419444c26fSTom Whitten /* 1429444c26fSTom Whitten * First time for this thread. We need to allocate memory 1439444c26fSTom Whitten * for our thread specific data. 1449444c26fSTom Whitten */ 1459444c26fSTom Whitten tsdp = uu_zalloc(sizeof (*tsdp)); 1469444c26fSTom Whitten if (tsdp == NULL) { 1479444c26fSTom Whitten errno = ENOMEM; 1489444c26fSTom Whitten return (NULL); 1499444c26fSTom Whitten } 1509444c26fSTom Whitten errno = pthread_setspecific(tsd_key, tsdp); 1519444c26fSTom Whitten if (errno != 0) { 1529444c26fSTom Whitten /* 1539444c26fSTom Whitten * EINVAL means that our key is invalid, which 1549444c26fSTom Whitten * would be a coding error. 1559444c26fSTom Whitten */ 1569444c26fSTom Whitten assert(errno != EINVAL); 1579444c26fSTom Whitten return (NULL); 1589444c26fSTom Whitten } 1599444c26fSTom Whitten } 1609444c26fSTom Whitten return (tsdp); 1619444c26fSTom Whitten } 1629444c26fSTom Whitten 1639444c26fSTom Whitten /* 1649444c26fSTom Whitten * This function is called by nftw(3C) every time that it finds an object 1659444c26fSTom Whitten * in a directory of interest. If the object is a file, process() checks 166adfc3118STruong Nguyen * to see if it is a service bundle file by insuring that it has a .xml 1679444c26fSTom Whitten * extension. 1689444c26fSTom Whitten * 169adfc3118STruong Nguyen * If the file is a service bundle file, and the CHECKHASH flag is set process() 170adfc3118STruong Nguyen * calls mhash_test_file() to see if it is a new bundle. Bundle file data 171adfc3118STruong Nguyen * for selected bundles is added to tsd_array in our thread specific data. 172adfc3118STruong Nguyen * 173adfc3118STruong Nguyen * Assume given file is a manifest unless BUNDLE_PROF flag is set to indicate 174adfc3118STruong Nguyen * it's a profile. For profile bundles, call mhash_test_file() with the 175adfc3118STruong Nguyen * appropriate argument. 1769444c26fSTom Whitten * 1779444c26fSTom Whitten * The CHECKEXT flag may be set if this was not a directory search request 178adfc3118STruong Nguyen * but a single service bundle file check that was determined by the caller to 1799444c26fSTom Whitten * be found based not on the extension of the file. 1809444c26fSTom Whitten */ 1819444c26fSTom Whitten /*ARGSUSED*/ 1829444c26fSTom Whitten static int 1839444c26fSTom Whitten process(const char *fn, const struct stat *sp, int ftw_type, 1849444c26fSTom Whitten struct FTW *ftws) 1859444c26fSTom Whitten { 186adfc3118STruong Nguyen int is_profile; 1879444c26fSTom Whitten char *suffix_match; 1889444c26fSTom Whitten uchar_t hash[MHASH_SIZE]; 1899444c26fSTom Whitten char *pname; 1909444c26fSTom Whitten mftsd_t *tsdp; 1919444c26fSTom Whitten 1929444c26fSTom Whitten if (ftw_type != FTW_F) 1939444c26fSTom Whitten return (0); 1949444c26fSTom Whitten 1959444c26fSTom Whitten tsdp = get_thread_specific_data(); 1969444c26fSTom Whitten if (tsdp == NULL) 1979444c26fSTom Whitten return (-1); 1989444c26fSTom Whitten 1999444c26fSTom Whitten /* 2009444c26fSTom Whitten * Only check the extension on the file when 2019444c26fSTom Whitten * requested. 2029444c26fSTom Whitten */ 2039444c26fSTom Whitten if (tsdp->tsd_flags & CHECKEXT) { 2049444c26fSTom Whitten suffix_match = strstr(fn, ".xml"); 2059444c26fSTom Whitten if (suffix_match == NULL || strcmp(suffix_match, ".xml") != 0) 2069444c26fSTom Whitten return (0); 2079444c26fSTom Whitten } 2089444c26fSTom Whitten 2099444c26fSTom Whitten if (tsdp->tsd_flags & CHECKHASH) { 210adfc3118STruong Nguyen is_profile = (tsdp->tsd_flags & BUNDLE_PROF) ? 1 : 0; 211adfc3118STruong Nguyen if (mhash_test_file(tsdp->tsd_hndl, fn, is_profile, &pname, 212adfc3118STruong Nguyen hash) == MHASH_NEWFILE) { 2139444c26fSTom Whitten return (add_pointer(tsdp, fn, pname, hash)); 2149444c26fSTom Whitten } 2159444c26fSTom Whitten } else { 2169444c26fSTom Whitten return (add_pointer(tsdp, fn, NULL, NULL)); 2179444c26fSTom Whitten } 2189444c26fSTom Whitten 2199444c26fSTom Whitten return (0); 2209444c26fSTom Whitten } 2219444c26fSTom Whitten 2229444c26fSTom Whitten /* 2239444c26fSTom Whitten * This function returns a pointer to an array of manifest_info_t pointers. 224adfc3118STruong Nguyen * There is one manifest_info_t pointer for each service bundle file in the 2259444c26fSTom Whitten * directory, dir, that satifies the selection criteria. The array is 2269444c26fSTom Whitten * returned to arrayp. The array will be terminated with a NULL pointer. 2279444c26fSTom Whitten * It is the responsibility of the caller to free the memory associated 2289444c26fSTom Whitten * with the array by calling free_manifest_array(). 2299444c26fSTom Whitten * 2309444c26fSTom Whitten * flags : 231adfc3118STruong Nguyen * 0x1 - CHECKHASH - do the hash check and only return bundle 2329444c26fSTom Whitten * files that do not have a hash entry in the smf/manifest table 233adfc3118STruong Nguyen * or the hash value has changed due to the bundle file having 234adfc3118STruong Nguyen * been modified. If not set then all service bundle files found 235adfc3118STruong Nguyen * are returned, regardless of the hash status. 2369444c26fSTom Whitten * 2379444c26fSTom Whitten * 0x2 - CHECKEXT - Check the extension of the file is .xml 2389444c26fSTom Whitten * 239adfc3118STruong Nguyen * On success a count of the number of selected bundles is returned. 2409444c26fSTom Whitten * Note, however, that *arrayp will be set to NULL if the selection is 2419444c26fSTom Whitten * empty, and a count of 0 will be returned. In the case of failure, -1 2429444c26fSTom Whitten * will be returned and errno will be set. 243293e3ab3STruong Q. Nguyen * 244293e3ab3STruong Q. Nguyen * This function takes a repository handle argument from the caller and saves 245293e3ab3STruong Q. Nguyen * that handle in a thread specific data structure. The thread specific 246293e3ab3STruong Q. Nguyen * repository handle is used in process() to communicate with the appropriate 247293e3ab3STruong Q. Nguyen * repository. Thus callers should take care of thread safety with respect to 248293e3ab3STruong Q. Nguyen * the repository handle. Currently, the two callers of find_manifests are both 249293e3ab3STruong Q. Nguyen * single threaded, i.e. svccfg and mfstscan, so thread safety not an issue. 2509444c26fSTom Whitten */ 2519444c26fSTom Whitten int 252293e3ab3STruong Q. Nguyen find_manifests(scf_handle_t *hndl, const char *dir, 253293e3ab3STruong Q. Nguyen manifest_info_t ***arrayp, int flags) 2549444c26fSTom Whitten { 2559444c26fSTom Whitten mftsd_t *tsdp; 2569444c26fSTom Whitten int status = -1; 2579444c26fSTom Whitten int count; 2589444c26fSTom Whitten 2599444c26fSTom Whitten tsdp = get_thread_specific_data(); 2609444c26fSTom Whitten if (tsdp == NULL) 261*23f76dc2SRichard Lowe return (-1); 2629444c26fSTom Whitten 2639444c26fSTom Whitten tsdp->tsd_flags = flags; 2649444c26fSTom Whitten 2659444c26fSTom Whitten if (tsdp->tsd_flags & CHECKHASH) { 266293e3ab3STruong Q. Nguyen tsdp->tsd_hndl = hndl; 2679444c26fSTom Whitten } 2689444c26fSTom Whitten 2699444c26fSTom Whitten if (nftw(dir, process, MAX_DEPTH, FTW_MOUNT) == 0) { 2709444c26fSTom Whitten status = 0; 2719444c26fSTom Whitten } 2729444c26fSTom Whitten 2739444c26fSTom Whitten out: 2749444c26fSTom Whitten if (status == 0) { 2759444c26fSTom Whitten *arrayp = tsdp->tsd_array; 2769444c26fSTom Whitten count = tsdp->tsd_count; 2779444c26fSTom Whitten } else { 2789444c26fSTom Whitten *arrayp = NULL; 2799444c26fSTom Whitten free_manifest_array(tsdp->tsd_array); 2809444c26fSTom Whitten count = -1; 2819444c26fSTom Whitten } 2829444c26fSTom Whitten 2839444c26fSTom Whitten /* Reset thread specific data. */ 2849444c26fSTom Whitten (void) memset(tsdp, 0, sizeof (*tsdp)); 2859444c26fSTom Whitten 2869444c26fSTom Whitten return (count); 2879444c26fSTom Whitten } 2889444c26fSTom Whitten 2899444c26fSTom Whitten /* 2909444c26fSTom Whitten * Free the memory associated with the array of manifest_info structures. 2919444c26fSTom Whitten */ 2929444c26fSTom Whitten void 2939444c26fSTom Whitten free_manifest_array(manifest_info_t **array) 2949444c26fSTom Whitten { 2959444c26fSTom Whitten manifest_info_t **entry; 2969444c26fSTom Whitten manifest_info_t *info; 2979444c26fSTom Whitten 2989444c26fSTom Whitten if (array == NULL) 2999444c26fSTom Whitten return; 3009444c26fSTom Whitten 3019444c26fSTom Whitten for (entry = array; *entry != NULL; entry++) { 3029444c26fSTom Whitten info = *entry; 3039444c26fSTom Whitten uu_free((void *) info->mi_path); 3049444c26fSTom Whitten uu_free((void *) info->mi_prop); 3059444c26fSTom Whitten uu_free(info); 3069444c26fSTom Whitten } 3079444c26fSTom Whitten 3089444c26fSTom Whitten /* 3099444c26fSTom Whitten * Array is allocated with realloc(3C), so it must be freed with 3109444c26fSTom Whitten * free(3c) rather than uu_free(). 3119444c26fSTom Whitten */ 3129444c26fSTom Whitten free(array); 3139444c26fSTom Whitten } 314