vscan_svc.c revision 53c110294d8b1410cabc201a52f94b03ae2ef448
911106dfb16696472af8c1b7b4c554a829354fa8jm * CDDL HEADER START
911106dfb16696472af8c1b7b4c554a829354fa8jm * The contents of this file are subject to the terms of the
911106dfb16696472af8c1b7b4c554a829354fa8jm * Common Development and Distribution License (the "License").
911106dfb16696472af8c1b7b4c554a829354fa8jm * You may not use this file except in compliance with the License.
911106dfb16696472af8c1b7b4c554a829354fa8jm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911106dfb16696472af8c1b7b4c554a829354fa8jm * See the License for the specific language governing permissions
911106dfb16696472af8c1b7b4c554a829354fa8jm * and limitations under the License.
911106dfb16696472af8c1b7b4c554a829354fa8jm * When distributing Covered Code, include this CDDL HEADER in each
911106dfb16696472af8c1b7b4c554a829354fa8jm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
911106dfb16696472af8c1b7b4c554a829354fa8jm * If applicable, add the following below this CDDL HEADER, with the
911106dfb16696472af8c1b7b4c554a829354fa8jm * fields enclosed by brackets "[]" replaced with your own identifying
911106dfb16696472af8c1b7b4c554a829354fa8jm * information: Portions Copyright [yyyy] [name of copyright owner]
911106dfb16696472af8c1b7b4c554a829354fa8jm * CDDL HEADER END
53c110294d8b1410cabc201a52f94b03ae2ef448jm * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Use is subject to license terms.
911106dfb16696472af8c1b7b4c554a829354fa8jm#pragma ident "%Z%%M% %I% %E% SMI"
911106dfb16696472af8c1b7b4c554a829354fa8jm#define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C))
911106dfb16696472af8c1b7b4c554a829354fa8jm/* represents request received from filesystem - currently only use vp */
911106dfb16696472af8c1b7b4c554a829354fa8jmtypedef struct vscan_fs_req {
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_files - table of files being scanned
911106dfb16696472af8c1b7b4c554a829354fa8jm * The index into this table is passed in the door call to
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscand. vscand uses the idx to determine which minor node
911106dfb16696472af8c1b7b4c554a829354fa8jm * to open to read the file data. Within the kernel driver
911106dfb16696472af8c1b7b4c554a829354fa8jm * the minor device number can thus be used to identify the
911106dfb16696472af8c1b7b4c554a829354fa8jm * table index to get the appropriate vnode.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Instance 0 is reserved for the daemon/driver control
911106dfb16696472af8c1b7b4c554a829354fa8jm * interface: enable/configure/disable
911106dfb16696472af8c1b7b4c554a829354fa8jmtypedef struct vscan_file {
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic vscan_file_t vscan_svc_files[VS_DRV_MAX_FILES + 1];
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic kcondvar_t vscan_svc_cv; /* wait for slot in vscan_svc_files */
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic int vscan_svc_wait_count = 0; /* # waiting for slot in vscan_svc_files */
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_mutex protects the data pertaining to scan requests:
911106dfb16696472af8c1b7b4c554a829354fa8jm * file table - vscan_svc_files
911106dfb16696472af8c1b7b4c554a829354fa8jm * counts - vscan_svc_wait_count, vscan_svc_req_count
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_cfg_mutex protects the configuration data:
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_config, vscan_svc_types
911106dfb16696472af8c1b7b4c554a829354fa8jm/* configuration data - for virus scan exemption */
911106dfb16696472af8c1b7b4c554a829354fa8jm/* local functions */
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic int vscan_svc_exempt_filetype(char *);
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic int vscan_svc_match_ext(char *, char *, int);
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic void vscan_svc_release_file(int);
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic int vscan_svc_find_slot(void);
53c110294d8b1410cabc201a52f94b03ae2ef448jmstatic void vscan_svc_process_scan_result(int);
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic void vscan_svc_notify_scan_complete(int);
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic int vscan_svc_getattr(int);
53c110294d8b1410cabc201a52f94b03ae2ef448jmstatic int vscan_svc_setattr(int, int);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_init
911106dfb16696472af8c1b7b4c554a829354fa8jm mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DRIVER, NULL);
911106dfb16696472af8c1b7b4c554a829354fa8jm (void) memset(&vscan_svc_files, 0, sizeof (vscan_svc_files));
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_fini
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_enable
53c110294d8b1410cabc201a52f94b03ae2ef448jm "will be processed synchronously");
53c110294d8b1410cabc201a52f94b03ae2ef448jm * vscan_svc_disable
53c110294d8b1410cabc201a52f94b03ae2ef448jm * vscan_svc_is_enabled
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_in_use
53c110294d8b1410cabc201a52f94b03ae2ef448jm * The vscan driver is considered to be in use if it is
53c110294d8b1410cabc201a52f94b03ae2ef448jm * enabled or if there are in-progress scan requests.
53c110294d8b1410cabc201a52f94b03ae2ef448jm * Used to determine whether the driver can be unloaded.
53c110294d8b1410cabc201a52f94b03ae2ef448jm rc = (vscan_svc_enabled == B_TRUE) || (vscan_svc_req_count > 0);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (rc);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_get_vnode
911106dfb16696472af8c1b7b4c554a829354fa8jm * Get the file vnode indexed by idx.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns NULL if idx not valid.
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_scan_file
911106dfb16696472af8c1b7b4c554a829354fa8jm * This function is the entry point for the file system to
911106dfb16696472af8c1b7b4c554a829354fa8jm * request that a file be virus scanned.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Asynchronous requests:
911106dfb16696472af8c1b7b4c554a829354fa8jm * If an async scan request cannot be queued it is discarded.
911106dfb16696472af8c1b7b4c554a829354fa8jm * By definition the caller of an async request is not dependent
911106dfb16696472af8c1b7b4c554a829354fa8jm * on the outcome of the result. Although the file will thus
911106dfb16696472af8c1b7b4c554a829354fa8jm * not be scanned at this time, it will be scanned
911106dfb16696472af8c1b7b4c554a829354fa8jm * (synchronously) on subsequent access.
911106dfb16696472af8c1b7b4c554a829354fa8jm * This scenario should not occur during normal operation.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Before queuing an async request do VN_HOLD(vp). VN_RELE(vp)
911106dfb16696472af8c1b7b4c554a829354fa8jm * will be done when the scan completes or if the request
911106dfb16696472af8c1b7b4c554a829354fa8jm * couldn't be queued.
911106dfb16696472af8c1b7b4c554a829354fa8jm * The vscan_fs_req_t, allocated to hold the request information
911106dfb16696472af8c1b7b4c554a829354fa8jm * passed from the fs, will be free'd when the scan completes.
911106dfb16696472af8c1b7b4c554a829354fa8jm if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL) {
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* check if size or type exempts file from scanning */
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm taskq_dispatch(vscan_svc_taskq, vscan_svc_taskq_callback,
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (rc);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_taskq_callback
911106dfb16696472af8c1b7b4c554a829354fa8jm * Callback function for async scan requests
911106dfb16696472af8c1b7b4c554a829354fa8jm VN_RELE(req->vsr_vp); /* VN_HOLD done before request queued */
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_do_scan
911106dfb16696472af8c1b7b4c554a829354fa8jm * Should never be called directly. Invoke via vscan_svc_scan_file()
911106dfb16696472af8c1b7b4c554a829354fa8jm * If scan is in progress wait for it to complete, otherwise
911106dfb16696472af8c1b7b4c554a829354fa8jm * initiate door call to scan the file.
911106dfb16696472af8c1b7b4c554a829354fa8jm * if a scan is in progress on the files vscan_svc_wait_for_scan will
911106dfb16696472af8c1b7b4c554a829354fa8jm * wait for it to complete and return the idx of the scan request.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Otherwise it will return -1 and we will initiate a scan here.
53c110294d8b1410cabc201a52f94b03ae2ef448jm if ((idx = vscan_svc_wait_for_scan(req->vsr_vp)) != -1) {
911106dfb16696472af8c1b7b4c554a829354fa8jm /* insert the scan request into vscan_svc_files */
911106dfb16696472af8c1b7b4c554a829354fa8jm /* valid scan_req ptr guaranteed */
53c110294d8b1410cabc201a52f94b03ae2ef448jm if (rc == 0)
53c110294d8b1410cabc201a52f94b03ae2ef448jm /* process scan result */
53c110294d8b1410cabc201a52f94b03ae2ef448jm /* if getattr fails: log error, deny access */
911106dfb16696472af8c1b7b4c554a829354fa8jm /* if vscan not enabled (shutting down), allow ACCESS */
911106dfb16696472af8c1b7b4c554a829354fa8jm /* When a scan completes the result is saved in vscan_svc_files */
53c110294d8b1410cabc201a52f94b03ae2ef448jm rc = (svc_file->vsf_access == VS_ACCESS_ALLOW) ? 0 : EACCES;
911106dfb16696472af8c1b7b4c554a829354fa8jm /* wake threads waiting for result, or for a slot in vscan_svc_files */
911106dfb16696472af8c1b7b4c554a829354fa8jm /* remove the entry from vscan_svc_files if nobody else is waiting */
911106dfb16696472af8c1b7b4c554a829354fa8jm return (rc);
53c110294d8b1410cabc201a52f94b03ae2ef448jm * vscan_svc_process_scan_result
53c110294d8b1410cabc201a52f94b03ae2ef448jm * Sets vsf_access and updates file attributes based on vsf_result,
53c110294d8b1410cabc201a52f94b03ae2ef448jm * as follows:
53c110294d8b1410cabc201a52f94b03ae2ef448jm * VS_STATUS_INFECTED
53c110294d8b1410cabc201a52f94b03ae2ef448jm * deny access, set quarantine attribute, clear scanstamp
53c110294d8b1410cabc201a52f94b03ae2ef448jm * VS_STATUS_CLEAN
53c110294d8b1410cabc201a52f94b03ae2ef448jm * allow access, set scanstamp,
53c110294d8b1410cabc201a52f94b03ae2ef448jm * if file not modified since scan initiated, clear modified attribute
53c110294d8b1410cabc201a52f94b03ae2ef448jm * VS_STATUS_NO_SCAN
53c110294d8b1410cabc201a52f94b03ae2ef448jm * deny access if file quarantined, otherwise allow access
53c110294d8b1410cabc201a52f94b03ae2ef448jm * VS_STATUS_UNDEFINED, VS_STATUS_ERROR
53c110294d8b1410cabc201a52f94b03ae2ef448jm * deny access if file quarantined, modified or no scanstamp
53c110294d8b1410cabc201a52f94b03ae2ef448jm * otherwise, allow access
53c110294d8b1410cabc201a52f94b03ae2ef448jmstatic void
53c110294d8b1410cabc201a52f94b03ae2ef448jm /* if mtime has changed, don't clear the modified attribute */
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_wait_for_scan
911106dfb16696472af8c1b7b4c554a829354fa8jm * Search for vp in vscan_svc_files. If vp already exists in
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_files scan is already in progress on file so wait
911106dfb16696472af8c1b7b4c554a829354fa8jm * for the inprogress scan to complete.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns: idx of file waited for
911106dfb16696472af8c1b7b4c554a829354fa8jm * -1 if file not already scanning
911106dfb16696472af8c1b7b4c554a829354fa8jm /* file not found in table thus not currently being scanned */
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* file found - wait for scan to complete */
53c110294d8b1410cabc201a52f94b03ae2ef448jm DTRACE_PROBE2(vscan__wait__scan, vscan_file_t *, svc_file, int, idx);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_find_slot
911106dfb16696472af8c1b7b4c554a829354fa8jm * Find empty slot in vscan_svc_files table.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns idx of slot, or -1 if not found
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_insert_file
911106dfb16696472af8c1b7b4c554a829354fa8jm * Find the next available flot in vscan_svc_files and
911106dfb16696472af8c1b7b4c554a829354fa8jm * initialize it for the scan request. If no slot is
911106dfb16696472af8c1b7b4c554a829354fa8jm * available, vscan_svc_find_slot will wait for one.
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns: idx of scan request in vscan_svc_files table
53c110294d8b1410cabc201a52f94b03ae2ef448jm DTRACE_PROBE1(vscan__wait__slot, char *, req->vsr_vp->v_path);
911106dfb16696472af8c1b7b4c554a829354fa8jm DTRACE_PROBE2(vscan__insert, char *, req->vsr_vp->v_path, int, idx);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_release_file
911106dfb16696472af8c1b7b4c554a829354fa8jm * Release the file (free the slot in vscan_svc_files)
911106dfb16696472af8c1b7b4c554a829354fa8jm * if no thread is waiting on it.
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic void
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_populate_req
911106dfb16696472af8c1b7b4c554a829354fa8jm * Allocate a scan request to be sent to vscand, populating it
911106dfb16696472af8c1b7b4c554a829354fa8jm * from the data in vscan_svc_files[idx].
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns: scan request object
911106dfb16696472af8c1b7b4c554a829354fa8jm scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP);
911106dfb16696472af8c1b7b4c554a829354fa8jm (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_parse_rsp
911106dfb16696472af8c1b7b4c554a829354fa8jm * Parse scan response data and save in vscan_svc_files[idx]
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic void
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_notify_scan_complete
53c110294d8b1410cabc201a52f94b03ae2ef448jm * signal vscan_svc_files.vsf_cv and vscan_svc_cv to wake
53c110294d8b1410cabc201a52f94b03ae2ef448jm * threads waiting for the scan result for the specified
53c110294d8b1410cabc201a52f94b03ae2ef448jm * file (vscan_svc_files[idx].vsf_cv) or for a slot in
53c110294d8b1410cabc201a52f94b03ae2ef448jm * vscan_svc_files table (vscan_svc_cv)
911106dfb16696472af8c1b7b4c554a829354fa8jmstatic void
911106dfb16696472af8c1b7b4c554a829354fa8jm /* if someone waiting for result, cv_signal */
911106dfb16696472af8c1b7b4c554a829354fa8jm /* signal vscan_svc_cv if any threads waiting for a slot */
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_getattr
53c110294d8b1410cabc201a52f94b03ae2ef448jm * Get the vscan related system attributes, AT_SIZE & AT_MTIME.
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* get the attributes */
911106dfb16696472af8c1b7b4c554a829354fa8jm if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm "file system does not support virus scanning");
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
53c110294d8b1410cabc201a52f94b03ae2ef448jm svc_file->vsf_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec;
53c110294d8b1410cabc201a52f94b03ae2ef448jm svc_file->vsf_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec;
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_setattr
911106dfb16696472af8c1b7b4c554a829354fa8jm * Set the vscan related system attributes.
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* update the attributes */
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* if access is denied, set mtime to invalidate client cache */
911106dfb16696472af8c1b7b4c554a829354fa8jm if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_configure
911106dfb16696472af8c1b7b4c554a829354fa8jm * store configuration in vscan_svc_config
911106dfb16696472af8c1b7b4c554a829354fa8jm * set up vscan_svc_types array of pointers into
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_config.vsc_types for efficient searching
911106dfb16696472af8c1b7b4c554a829354fa8jm (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types));
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_exempt_file
911106dfb16696472af8c1b7b4c554a829354fa8jm * check if a file's size or type exempts it from virus scanning
911106dfb16696472af8c1b7b4c554a829354fa8jm * If the file is exempt from virus scanning, allow will be set
911106dfb16696472af8c1b7b4c554a829354fa8jm * to define whether files access should be allowed (B_TRUE) or
911106dfb16696472af8c1b7b4c554a829354fa8jm * denied (B_FALSE)
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns: 1 exempt
911106dfb16696472af8c1b7b4c554a829354fa8jm * 0 scan required
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE;
911106dfb16696472af8c1b7b4c554a829354fa8jm return (1);
911106dfb16696472af8c1b7b4c554a829354fa8jm DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_exempt_filetype
911106dfb16696472af8c1b7b4c554a829354fa8jm * Each entry in vscan_svc_types includes a rule indicator (+,-)
911106dfb16696472af8c1b7b4c554a829354fa8jm * followed by the match string for file types to which the rule
911106dfb16696472af8c1b7b4c554a829354fa8jm * applies. Look for first match of file type in vscan_svc_types
911106dfb16696472af8c1b7b4c554a829354fa8jm * and return 1 (exempt) if the indicator is '-', and 0 (not exempt)
911106dfb16696472af8c1b7b4c554a829354fa8jm * if the indicator is '+'.
911106dfb16696472af8c1b7b4c554a829354fa8jm * If vscan_svc_match_ext fails, or no match is found, return 0
911106dfb16696472af8c1b7b4c554a829354fa8jm * (not exempt)
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns 1: exempt, 0: not exempt
911106dfb16696472af8c1b7b4c554a829354fa8jm for (i = 0; i < VS_TYPES_MAX; i ++) {
911106dfb16696472af8c1b7b4c554a829354fa8jm rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1);
911106dfb16696472af8c1b7b4c554a829354fa8jm if (rc > 0) {
911106dfb16696472af8c1b7b4c554a829354fa8jm * vscan_svc_match_ext
911106dfb16696472af8c1b7b4c554a829354fa8jm * Performs a case-insensitive match for two strings. The first string
911106dfb16696472af8c1b7b4c554a829354fa8jm * argument can contain the wildcard characters '?' and '*'
911106dfb16696472af8c1b7b4c554a829354fa8jm * Returns: 0 no match
911106dfb16696472af8c1b7b4c554a829354fa8jm * -1 recursion error
911106dfb16696472af8c1b7b4c554a829354fa8jm return (-1);
911106dfb16696472af8c1b7b4c554a829354fa8jm for (;;) {
911106dfb16696472af8c1b7b4c554a829354fa8jm switch (*patn) {
911106dfb16696472af8c1b7b4c554a829354fa8jm return (*str == 0);
911106dfb16696472af8c1b7b4c554a829354fa8jm if (*str != 0) {
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm if (*patn == 0)
911106dfb16696472af8c1b7b4c554a829354fa8jm return (1);
911106dfb16696472af8c1b7b4c554a829354fa8jm while (*str) {
911106dfb16696472af8c1b7b4c554a829354fa8jm return (1);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm return (0);
911106dfb16696472af8c1b7b4c554a829354fa8jm /* NOT REACHED */