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
add_pointer(mftsd_t * tsdp,const char * fn,const char * pname,uchar_t * hash)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 *
get_thread_specific_data()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
process(const char * fn,const struct stat * sp,int ftw_type,struct FTW * ftws)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
find_manifests(scf_handle_t * hndl,const char * dir,manifest_info_t *** arrayp,int flags)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
free_manifest_array(manifest_info_t ** array)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