1  | 
     | 
     | 
    /*	$OpenBSD: rquotad.c,v 1.22 2015/01/16 06:39:50 deraadt Exp $	*/  | 
    
    
    2  | 
     | 
     | 
     | 
    
    
    3  | 
     | 
     | 
    /*  | 
    
    
    4  | 
     | 
     | 
     * by Manuel Bouyer (bouyer@ensta.fr). Public domain.  | 
    
    
    5  | 
     | 
     | 
     */  | 
    
    
    6  | 
     | 
     | 
     | 
    
    
    7  | 
     | 
     | 
    #include <sys/param.h>	/* DEV_BSIZE */  | 
    
    
    8  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    9  | 
     | 
     | 
    #include <sys/mount.h>  | 
    
    
    10  | 
     | 
     | 
    #include <sys/socket.h>  | 
    
    
    11  | 
     | 
     | 
    #include <sys/stat.h>  | 
    
    
    12  | 
     | 
     | 
    #include <signal.h>  | 
    
    
    13  | 
     | 
     | 
     | 
    
    
    14  | 
     | 
     | 
    #include <ctype.h>  | 
    
    
    15  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    16  | 
     | 
     | 
    #include <fcntl.h>  | 
    
    
    17  | 
     | 
     | 
    #include <fstab.h>  | 
    
    
    18  | 
     | 
     | 
    #include <grp.h>  | 
    
    
    19  | 
     | 
     | 
    #include <pwd.h>  | 
    
    
    20  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    21  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    22  | 
     | 
     | 
    #include <string.h>  | 
    
    
    23  | 
     | 
     | 
    #include <syslog.h>  | 
    
    
    24  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    25  | 
     | 
     | 
     | 
    
    
    26  | 
     | 
     | 
    #include <ufs/ufs/quota.h>  | 
    
    
    27  | 
     | 
     | 
    #include <rpc/rpc.h>  | 
    
    
    28  | 
     | 
     | 
    #include <rpcsvc/rquota.h>  | 
    
    
    29  | 
     | 
     | 
    #include <arpa/inet.h>  | 
    
    
    30  | 
     | 
     | 
     | 
    
    
    31  | 
     | 
     | 
    void rquota_service(struct svc_req *request, SVCXPRT *transp);  | 
    
    
    32  | 
     | 
     | 
    void sendquota(struct svc_req *request, SVCXPRT *transp);  | 
    
    
    33  | 
     | 
     | 
    void printerr_reply(SVCXPRT *transp);  | 
    
    
    34  | 
     | 
     | 
    void initfs(void);  | 
    
    
    35  | 
     | 
     | 
    int getfsquota(long id, char *path, struct dqblk *dqblk);  | 
    
    
    36  | 
     | 
     | 
    int hasquota(struct fstab *fs, char **qfnamep);  | 
    
    
    37  | 
     | 
     | 
     | 
    
    
    38  | 
     | 
     | 
    /*  | 
    
    
    39  | 
     | 
     | 
     * structure containing informations about ufs filesystems  | 
    
    
    40  | 
     | 
     | 
     * initialised by initfs()  | 
    
    
    41  | 
     | 
     | 
     */  | 
    
    
    42  | 
     | 
     | 
    struct fs_stat { | 
    
    
    43  | 
     | 
     | 
    	struct fs_stat *fs_next;	/* next element */  | 
    
    
    44  | 
     | 
     | 
    	char   *fs_file;		/* mount point of the filesystem */  | 
    
    
    45  | 
     | 
     | 
    	char   *qfpathname;		/* pathname of the quota file */  | 
    
    
    46  | 
     | 
     | 
    	dev_t   st_dev;			/* device of the filesystem */  | 
    
    
    47  | 
     | 
     | 
    };  | 
    
    
    48  | 
     | 
     | 
    struct fs_stat *fs_begin = NULL;  | 
    
    
    49  | 
     | 
     | 
     | 
    
    
    50  | 
     | 
     | 
    int from_inetd = 1;  | 
    
    
    51  | 
     | 
     | 
     | 
    
    
    52  | 
     | 
     | 
    /* ARGSUSED */  | 
    
    
    53  | 
     | 
     | 
    static void  | 
    
    
    54  | 
     | 
     | 
    cleanup(int signo)  | 
    
    
    55  | 
     | 
     | 
    { | 
    
    
    56  | 
     | 
     | 
    	(void) pmap_unset(RQUOTAPROG, RQUOTAVERS);	/* XXX signal races */  | 
    
    
    57  | 
     | 
     | 
    	_exit(0);  | 
    
    
    58  | 
     | 
     | 
    }  | 
    
    
    59  | 
     | 
     | 
     | 
    
    
    60  | 
     | 
     | 
    int  | 
    
    
    61  | 
     | 
     | 
    main(int argc, char *argv[])  | 
    
    
    62  | 
     | 
     | 
    { | 
    
    
    63  | 
     | 
     | 
    	SVCXPRT *transp;  | 
    
    
    64  | 
     | 
     | 
    	int sock = 0;  | 
    
    
    65  | 
     | 
     | 
    	int proto = 0;  | 
    
    
    66  | 
     | 
     | 
    	struct sockaddr_storage from;  | 
    
    
    67  | 
     | 
     | 
    	socklen_t fromlen;  | 
    
    
    68  | 
     | 
     | 
     | 
    
    
    69  | 
     | 
     | 
    	fromlen = sizeof(from);  | 
    
    
    70  | 
     | 
     | 
    	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { | 
    
    
    71  | 
     | 
     | 
    		from_inetd = 0;  | 
    
    
    72  | 
     | 
     | 
    		sock = RPC_ANYSOCK;  | 
    
    
    73  | 
     | 
     | 
    		proto = IPPROTO_UDP;  | 
    
    
    74  | 
     | 
     | 
    	}  | 
    
    
    75  | 
     | 
     | 
     | 
    
    
    76  | 
     | 
     | 
    	if (!from_inetd) { | 
    
    
    77  | 
     | 
     | 
    		daemon(0, 0);  | 
    
    
    78  | 
     | 
     | 
     | 
    
    
    79  | 
     | 
     | 
    		(void) pmap_unset(RQUOTAPROG, RQUOTAVERS);  | 
    
    
    80  | 
     | 
     | 
     | 
    
    
    81  | 
     | 
     | 
    		(void) signal(SIGINT, cleanup);  | 
    
    
    82  | 
     | 
     | 
    		(void) signal(SIGTERM, cleanup);  | 
    
    
    83  | 
     | 
     | 
    		(void) signal(SIGHUP, cleanup);  | 
    
    
    84  | 
     | 
     | 
    	}  | 
    
    
    85  | 
     | 
     | 
     | 
    
    
    86  | 
     | 
     | 
    	openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON); | 
    
    
    87  | 
     | 
     | 
     | 
    
    
    88  | 
     | 
     | 
    	/* create and register the service */  | 
    
    
    89  | 
     | 
     | 
    	transp = svcudp_create(sock);  | 
    
    
    90  | 
     | 
     | 
    	if (transp == NULL) { | 
    
    
    91  | 
     | 
     | 
    		syslog(LOG_ERR, "couldn't create udp service.");  | 
    
    
    92  | 
     | 
     | 
    		exit(1);  | 
    
    
    93  | 
     | 
     | 
    	}  | 
    
    
    94  | 
     | 
     | 
    	if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquota_service, proto)) { | 
    
    
    95  | 
     | 
     | 
    		syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS, %s).",  | 
    
    
    96  | 
     | 
     | 
    		    proto ? "udp" : "(inetd)");  | 
    
    
    97  | 
     | 
     | 
    		exit(1);  | 
    
    
    98  | 
     | 
     | 
    	}  | 
    
    
    99  | 
     | 
     | 
     | 
    
    
    100  | 
     | 
     | 
    	initfs();		/* init the fs_stat list */  | 
    
    
    101  | 
     | 
     | 
    	svc_run();  | 
    
    
    102  | 
     | 
     | 
    	syslog(LOG_ERR, "svc_run returned");  | 
    
    
    103  | 
     | 
     | 
    	exit(1);  | 
    
    
    104  | 
     | 
     | 
    }  | 
    
    
    105  | 
     | 
     | 
     | 
    
    
    106  | 
     | 
     | 
    void  | 
    
    
    107  | 
     | 
     | 
    rquota_service(struct svc_req *request, SVCXPRT *transp)  | 
    
    
    108  | 
     | 
     | 
    { | 
    
    
    109  | 
     | 
     | 
    	switch (request->rq_proc) { | 
    
    
    110  | 
     | 
     | 
    	case NULLPROC:  | 
    
    
    111  | 
     | 
     | 
    		(void)svc_sendreply(transp, xdr_void, (char *)NULL);  | 
    
    
    112  | 
     | 
     | 
    		break;  | 
    
    
    113  | 
     | 
     | 
     | 
    
    
    114  | 
     | 
     | 
    	case RQUOTAPROC_GETQUOTA:  | 
    
    
    115  | 
     | 
     | 
    	case RQUOTAPROC_GETACTIVEQUOTA:  | 
    
    
    116  | 
     | 
     | 
    		sendquota(request, transp);  | 
    
    
    117  | 
     | 
     | 
    		break;  | 
    
    
    118  | 
     | 
     | 
     | 
    
    
    119  | 
     | 
     | 
    	default:  | 
    
    
    120  | 
     | 
     | 
    		svcerr_noproc(transp);  | 
    
    
    121  | 
     | 
     | 
    		break;  | 
    
    
    122  | 
     | 
     | 
    	}  | 
    
    
    123  | 
     | 
     | 
    	if (from_inetd)  | 
    
    
    124  | 
     | 
     | 
    		exit(0);  | 
    
    
    125  | 
     | 
     | 
    }  | 
    
    
    126  | 
     | 
     | 
     | 
    
    
    127  | 
     | 
     | 
    /* read quota for the specified id, and send it */  | 
    
    
    128  | 
     | 
     | 
    void  | 
    
    
    129  | 
     | 
     | 
    sendquota(struct svc_req *request, SVCXPRT *transp)  | 
    
    
    130  | 
     | 
     | 
    { | 
    
    
    131  | 
     | 
     | 
    	struct getquota_args getq_args;  | 
    
    
    132  | 
     | 
     | 
    	struct getquota_rslt getq_rslt;  | 
    
    
    133  | 
     | 
     | 
    	struct dqblk dqblk;  | 
    
    
    134  | 
     | 
     | 
    	struct timeval timev;  | 
    
    
    135  | 
     | 
     | 
     | 
    
    
    136  | 
     | 
     | 
    	bzero((char *)&getq_args, sizeof(getq_args));  | 
    
    
    137  | 
     | 
     | 
    	if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) { | 
    
    
    138  | 
     | 
     | 
    		svcerr_decode(transp);  | 
    
    
    139  | 
     | 
     | 
    		return;  | 
    
    
    140  | 
     | 
     | 
    	}  | 
    
    
    141  | 
     | 
     | 
    	if (request->rq_cred.oa_flavor != AUTH_UNIX) { | 
    
    
    142  | 
     | 
     | 
    		/* bad auth */  | 
    
    
    143  | 
     | 
     | 
    		getq_rslt.status = Q_EPERM;  | 
    
    
    144  | 
     | 
     | 
    	} else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) { | 
    
    
    145  | 
     | 
     | 
    		/* failed, return noquota */  | 
    
    
    146  | 
     | 
     | 
    		getq_rslt.status = Q_NOQUOTA;  | 
    
    
    147  | 
     | 
     | 
    	} else { | 
    
    
    148  | 
     | 
     | 
    		gettimeofday(&timev, NULL);  | 
    
    
    149  | 
     | 
     | 
    		getq_rslt.status = Q_OK;  | 
    
    
    150  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;  | 
    
    
    151  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;  | 
    
    
    152  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =  | 
    
    
    153  | 
     | 
     | 
    		    dqblk.dqb_bhardlimit;  | 
    
    
    154  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =  | 
    
    
    155  | 
     | 
     | 
    		    dqblk.dqb_bsoftlimit;  | 
    
    
    156  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =  | 
    
    
    157  | 
     | 
     | 
    		    dqblk.dqb_curblocks;  | 
    
    
    158  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =  | 
    
    
    159  | 
     | 
     | 
    		    dqblk.dqb_ihardlimit;  | 
    
    
    160  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =  | 
    
    
    161  | 
     | 
     | 
    		    dqblk.dqb_isoftlimit;  | 
    
    
    162  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =  | 
    
    
    163  | 
     | 
     | 
    		    dqblk.dqb_curinodes;  | 
    
    
    164  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =  | 
    
    
    165  | 
     | 
     | 
    		    dqblk.dqb_btime - timev.tv_sec;  | 
    
    
    166  | 
     | 
     | 
    		getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =  | 
    
    
    167  | 
     | 
     | 
    		    dqblk.dqb_itime - timev.tv_sec;  | 
    
    
    168  | 
     | 
     | 
    	}  | 
    
    
    169  | 
     | 
     | 
    	if (!svc_sendreply(transp, xdr_getquota_rslt, (char *)&getq_rslt)) { | 
    
    
    170  | 
     | 
     | 
    		svcerr_systemerr(transp);  | 
    
    
    171  | 
     | 
     | 
    	}  | 
    
    
    172  | 
     | 
     | 
    	if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) { | 
    
    
    173  | 
     | 
     | 
    		syslog(LOG_ERR, "unable to free arguments");  | 
    
    
    174  | 
     | 
     | 
    		exit(1);  | 
    
    
    175  | 
     | 
     | 
    	}  | 
    
    
    176  | 
     | 
     | 
    }  | 
    
    
    177  | 
     | 
     | 
     | 
    
    
    178  | 
     | 
     | 
    /* initialise the fs_tab list from entries in /etc/fstab */  | 
    
    
    179  | 
     | 
     | 
    void  | 
    
    
    180  | 
     | 
     | 
    initfs(void)  | 
    
    
    181  | 
     | 
     | 
    { | 
    
    
    182  | 
     | 
     | 
    	struct fs_stat *fs_current = NULL;  | 
    
    
    183  | 
     | 
     | 
    	struct fs_stat *fs_next = NULL;  | 
    
    
    184  | 
     | 
     | 
    	char *qfpathname;  | 
    
    
    185  | 
     | 
     | 
    	struct fstab *fs;  | 
    
    
    186  | 
     | 
     | 
    	struct stat st;  | 
    
    
    187  | 
     | 
     | 
     | 
    
    
    188  | 
     | 
     | 
    	setfsent();  | 
    
    
    189  | 
     | 
     | 
    	while ((fs = getfsent())) { | 
    
    
    190  | 
     | 
     | 
    		if (strcmp(fs->fs_vfstype, "ffs"))  | 
    
    
    191  | 
     | 
     | 
    			continue;  | 
    
    
    192  | 
     | 
     | 
    		if (!hasquota(fs, &qfpathname))  | 
    
    
    193  | 
     | 
     | 
    			continue;  | 
    
    
    194  | 
     | 
     | 
     | 
    
    
    195  | 
     | 
     | 
    		fs_current = malloc(sizeof(struct fs_stat));  | 
    
    
    196  | 
     | 
     | 
    		if (fs_current == NULL) { | 
    
    
    197  | 
     | 
     | 
    			syslog(LOG_ERR, "can't malloc: %m");  | 
    
    
    198  | 
     | 
     | 
    			exit(1);  | 
    
    
    199  | 
     | 
     | 
    		}  | 
    
    
    200  | 
     | 
     | 
    		fs_current->fs_next = fs_next;	/* next element */  | 
    
    
    201  | 
     | 
     | 
     | 
    
    
    202  | 
     | 
     | 
    		fs_current->fs_file = strdup(fs->fs_file);  | 
    
    
    203  | 
     | 
     | 
    		if (fs_current->fs_file == NULL) { | 
    
    
    204  | 
     | 
     | 
    			syslog(LOG_ERR, "can't strdup: %m");  | 
    
    
    205  | 
     | 
     | 
    			exit(1);  | 
    
    
    206  | 
     | 
     | 
    		}  | 
    
    
    207  | 
     | 
     | 
     | 
    
    
    208  | 
     | 
     | 
    		fs_current->qfpathname = strdup(qfpathname);  | 
    
    
    209  | 
     | 
     | 
    		if (fs_current->qfpathname == NULL) { | 
    
    
    210  | 
     | 
     | 
    			syslog(LOG_ERR, "can't strdup: %m");  | 
    
    
    211  | 
     | 
     | 
    			exit(1);  | 
    
    
    212  | 
     | 
     | 
    		}  | 
    
    
    213  | 
     | 
     | 
     | 
    
    
    214  | 
     | 
     | 
    		stat(fs_current->fs_file, &st);  | 
    
    
    215  | 
     | 
     | 
    		fs_current->st_dev = st.st_dev;  | 
    
    
    216  | 
     | 
     | 
     | 
    
    
    217  | 
     | 
     | 
    		fs_next = fs_current;  | 
    
    
    218  | 
     | 
     | 
    	}  | 
    
    
    219  | 
     | 
     | 
    	endfsent();  | 
    
    
    220  | 
     | 
     | 
    	fs_begin = fs_current;  | 
    
    
    221  | 
     | 
     | 
    }  | 
    
    
    222  | 
     | 
     | 
     | 
    
    
    223  | 
     | 
     | 
    /*  | 
    
    
    224  | 
     | 
     | 
     * gets the quotas for id, filesystem path.  | 
    
    
    225  | 
     | 
     | 
     * Return 0 if fail, 1 otherwise  | 
    
    
    226  | 
     | 
     | 
     */  | 
    
    
    227  | 
     | 
     | 
    int  | 
    
    
    228  | 
     | 
     | 
    getfsquota(long id, char *path, struct dqblk *dqblk)  | 
    
    
    229  | 
     | 
     | 
    { | 
    
    
    230  | 
     | 
     | 
    	struct stat st_path;  | 
    
    
    231  | 
     | 
     | 
    	struct fs_stat *fs;  | 
    
    
    232  | 
     | 
     | 
    	int	qcmd, fd, ret = 0;  | 
    
    
    233  | 
     | 
     | 
     | 
    
    
    234  | 
     | 
     | 
    	if (stat(path, &st_path) < 0)  | 
    
    
    235  | 
     | 
     | 
    		return (0);  | 
    
    
    236  | 
     | 
     | 
     | 
    
    
    237  | 
     | 
     | 
    	qcmd = QCMD(Q_GETQUOTA, USRQUOTA);  | 
    
    
    238  | 
     | 
     | 
     | 
    
    
    239  | 
     | 
     | 
    	for (fs = fs_begin; fs != NULL; fs = fs->fs_next) { | 
    
    
    240  | 
     | 
     | 
    		/* where the device is the same as path */  | 
    
    
    241  | 
     | 
     | 
    		if (fs->st_dev != st_path.st_dev)  | 
    
    
    242  | 
     | 
     | 
    			continue;  | 
    
    
    243  | 
     | 
     | 
     | 
    
    
    244  | 
     | 
     | 
    		/* find the specified filesystem. get and return quota */  | 
    
    
    245  | 
     | 
     | 
    		if (quotactl(fs->fs_file, qcmd, id, (char *)dqblk) == 0)  | 
    
    
    246  | 
     | 
     | 
    			return (1);  | 
    
    
    247  | 
     | 
     | 
     | 
    
    
    248  | 
     | 
     | 
    		if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) { | 
    
    
    249  | 
     | 
     | 
    			syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);  | 
    
    
    250  | 
     | 
     | 
    			return (0);  | 
    
    
    251  | 
     | 
     | 
    		}  | 
    
    
    252  | 
     | 
     | 
    		if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), SEEK_SET) ==  | 
    
    
    253  | 
     | 
     | 
    		    (off_t)-1) { | 
    
    
    254  | 
     | 
     | 
    			close(fd);  | 
    
    
    255  | 
     | 
     | 
    			return (1);  | 
    
    
    256  | 
     | 
     | 
    		}  | 
    
    
    257  | 
     | 
     | 
    		switch (read(fd, dqblk, sizeof(struct dqblk))) { | 
    
    
    258  | 
     | 
     | 
    		case 0:  | 
    
    
    259  | 
     | 
     | 
    			/*  | 
    
    
    260  | 
     | 
     | 
    			 * Convert implicit 0 quota (EOF)  | 
    
    
    261  | 
     | 
     | 
    			 * into an explicit one (zero'ed dqblk)  | 
    
    
    262  | 
     | 
     | 
    			 */  | 
    
    
    263  | 
     | 
     | 
    			bzero((caddr_t) dqblk, sizeof(struct dqblk));  | 
    
    
    264  | 
     | 
     | 
    			ret = 1;  | 
    
    
    265  | 
     | 
     | 
    			break;  | 
    
    
    266  | 
     | 
     | 
    		case sizeof(struct dqblk):	/* OK */  | 
    
    
    267  | 
     | 
     | 
    			ret = 1;  | 
    
    
    268  | 
     | 
     | 
    			break;  | 
    
    
    269  | 
     | 
     | 
    		default:	/* ERROR */  | 
    
    
    270  | 
     | 
     | 
    			syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);  | 
    
    
    271  | 
     | 
     | 
    			close(fd);  | 
    
    
    272  | 
     | 
     | 
    			return (0);  | 
    
    
    273  | 
     | 
     | 
    		}  | 
    
    
    274  | 
     | 
     | 
    		close(fd);  | 
    
    
    275  | 
     | 
     | 
    	}  | 
    
    
    276  | 
     | 
     | 
    	return (ret);  | 
    
    
    277  | 
     | 
     | 
    }  | 
    
    
    278  | 
     | 
     | 
     | 
    
    
    279  | 
     | 
     | 
    /*  | 
    
    
    280  | 
     | 
     | 
     * Check to see if a particular quota is to be enabled.  | 
    
    
    281  | 
     | 
     | 
     * Comes from quota.c, NetBSD 0.9  | 
    
    
    282  | 
     | 
     | 
     */  | 
    
    
    283  | 
     | 
     | 
    int  | 
    
    
    284  | 
     | 
     | 
    hasquota(struct fstab *fs, char **qfnamep)  | 
    
    
    285  | 
     | 
     | 
    { | 
    
    
    286  | 
     | 
     | 
    	static char initname, usrname[100];  | 
    
    
    287  | 
     | 
     | 
    	static char buf[BUFSIZ];  | 
    
    
    288  | 
     | 
     | 
    	char	*opt, *cp;  | 
    
    
    289  | 
     | 
     | 
    	char	*qfextension[] = INITQFNAMES;  | 
    
    
    290  | 
     | 
     | 
     | 
    
    
    291  | 
     | 
     | 
    	cp = NULL;  | 
    
    
    292  | 
     | 
     | 
    	if (!initname) { | 
    
    
    293  | 
     | 
     | 
    		(void)snprintf(usrname, sizeof usrname, "%s%s",  | 
    
    
    294  | 
     | 
     | 
    		    qfextension[USRQUOTA], QUOTAFILENAME);  | 
    
    
    295  | 
     | 
     | 
    		initname = 1;  | 
    
    
    296  | 
     | 
     | 
    	}  | 
    
    
    297  | 
     | 
     | 
    	strlcpy(buf, fs->fs_mntops, sizeof buf);  | 
    
    
    298  | 
     | 
     | 
    	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { | 
    
    
    299  | 
     | 
     | 
    		if ((cp = strchr(opt, '=')))  | 
    
    
    300  | 
     | 
     | 
    			*cp++ = '\0';  | 
    
    
    301  | 
     | 
     | 
    		if (strcmp(opt, usrname) == 0)  | 
    
    
    302  | 
     | 
     | 
    			break;  | 
    
    
    303  | 
     | 
     | 
    	}  | 
    
    
    304  | 
     | 
     | 
    	if (!opt)  | 
    
    
    305  | 
     | 
     | 
    		return (0);  | 
    
    
    306  | 
     | 
     | 
    	if (cp) { | 
    
    
    307  | 
     | 
     | 
    		*qfnamep = cp;  | 
    
    
    308  | 
     | 
     | 
    		return (1);  | 
    
    
    309  | 
     | 
     | 
    	}  | 
    
    
    310  | 
     | 
     | 
    	(void)snprintf(buf, sizeof buf, "%s/%s.%s", fs->fs_file,  | 
    
    
    311  | 
     | 
     | 
    	    QUOTAFILENAME, qfextension[USRQUOTA]);  | 
    
    
    312  | 
     | 
     | 
    	*qfnamep = buf;  | 
    
    
    313  | 
     | 
     | 
    	return (1);  | 
    
    
    314  | 
     | 
     | 
    }  |