Print this page
NEX-14051 Be careful with RPC groups
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
8085 Handle RPC groups better
Reviewed by: "Joshua M. Clulow" <josh@sysmgr.org>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/nfs/rquotad/rpc.rquotad.c
+++ new/usr/src/cmd/fs.d/nfs/rquotad/rpc.rquotad.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2017 Joyent Inc
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 28
29 29 #include <stdio.h>
30 30 #include <stdlib.h>
31 31 #include <signal.h>
32 32 #include <syslog.h>
33 33 #include <string.h>
34 34 #include <stropts.h>
35 35 #include <errno.h>
36 36 #include <sys/netconfig.h>
37 37 #include <sys/mntent.h>
38 38 #include <sys/mnttab.h>
39 39 #include <sys/param.h>
40 40 #include <sys/time.h>
41 41 #include <sys/debug.h>
42 42 #ifdef notdef
43 43 #include <netconfig.h>
44 44 #endif
45 45 #include <sys/stat.h>
46 46 #include <sys/file.h>
47 47 #include <sys/fs/ufs_quota.h>
48 48 #include <netdir.h>
49 49 #include <rpc/rpc.h>
50 50 #include <rpcsvc/rquota.h>
51 51 #include <tiuser.h>
52 52 #include <unistd.h>
53 53 #include <dlfcn.h>
54 54 #include <libzfs.h>
55 55
56 56 #define QFNAME "quotas" /* name of quota file */
57 57 #define RPCSVC_CLOSEDOWN 120 /* 2 minutes */
58 58
59 59 struct fsquot {
60 60 char *fsq_fstype;
61 61 struct fsquot *fsq_next;
62 62 char *fsq_dir;
63 63 char *fsq_devname;
64 64 dev_t fsq_dev;
65 65 };
66 66
67 67 struct fsquot *fsqlist = NULL;
68 68
69 69 typedef struct authunix_parms *authp;
70 70
71 71 static int request_pending; /* Request in progress ? */
72 72
73 73 void closedown();
74 74 void dispatch();
75 75 struct fsquot *findfsq();
76 76 void freefs();
77 77 int getdiskquota();
78 78 void getquota();
79 79 int hasquota();
80 80 void log_cant_reply();
81 81 void setupfs();
82 82 static void zexit(int) __NORETURN;
83 83
84 84 static libzfs_handle_t *(*_libzfs_init)(void);
85 85 static void (*_libzfs_fini)(libzfs_handle_t *);
86 86 static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
87 87 static void (*_zfs_close)(zfs_handle_t *);
88 88 static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
89 89 uint64_t *);
90 90 static libzfs_handle_t *g_zfs = NULL;
91 91
92 92 /*
93 93 * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
94 94 * packages. 'rquotad' supports zfs as an option.
95 95 */
96 96 static void
97 97 load_libzfs(void)
98 98 {
99 99 void *hdl;
100 100
101 101 if (g_zfs != NULL)
102 102 return;
103 103
104 104 if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
105 105 _libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
106 106 "libzfs_init");
107 107 _libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
108 108 _zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
109 109 _zfs_close = (void (*)())dlsym(hdl, "zfs_close");
110 110 _zfs_prop_get_userquota_int = (int (*)())
111 111 dlsym(hdl, "zfs_prop_get_userquota_int");
112 112
113 113 if (_libzfs_init && _libzfs_fini && _zfs_open &&
114 114 _zfs_close && _zfs_prop_get_userquota_int)
115 115 g_zfs = _libzfs_init();
116 116 }
117 117 }
118 118
119 119 /*ARGSUSED*/
120 120 int
121 121 main(int argc, char *argv[])
122 122 {
123 123 register SVCXPRT *transp;
124 124
125 125 load_libzfs();
126 126
127 127 /*
128 128 * If stdin looks like a TLI endpoint, we assume
129 129 * that we were started by a port monitor. If
130 130 * t_getstate fails with TBADF, this is not a
131 131 * TLI endpoint.
132 132 */
133 133 if (t_getstate(0) != -1 || t_errno != TBADF) {
134 134 char *netid;
135 135 struct netconfig *nconf = NULL;
136 136
137 137 openlog("rquotad", LOG_PID, LOG_DAEMON);
138 138
139 139 if ((netid = getenv("NLSPROVIDER")) == NULL) {
140 140 struct t_info tinfo;
141 141
142 142 if (t_sync(0) == -1) {
143 143 syslog(LOG_ERR, "could not do t_sync");
144 144 zexit(1);
145 145 }
146 146 if (t_getinfo(0, &tinfo) == -1) {
147 147 syslog(LOG_ERR, "t_getinfo failed");
148 148 zexit(1);
149 149 }
150 150 if (tinfo.servtype == T_CLTS) {
151 151 if (tinfo.addr == INET_ADDRSTRLEN)
152 152 netid = "udp";
153 153 else
154 154 netid = "udp6";
155 155 } else {
156 156 syslog(LOG_ERR, "wrong transport");
157 157 zexit(1);
158 158 }
159 159 }
160 160 if ((nconf = getnetconfigent(netid)) == NULL) {
161 161 syslog(LOG_ERR, "cannot get transport info");
162 162 }
163 163
164 164 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
165 165 syslog(LOG_ERR, "cannot create server handle");
166 166 zexit(1);
167 167 }
168 168 if (nconf)
169 169 freenetconfigent(nconf);
170 170
171 171 if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, dispatch, 0)) {
172 172 syslog(LOG_ERR,
173 173 "unable to register (RQUOTAPROG, RQUOTAVERS).");
174 174 zexit(1);
175 175 }
176 176
177 177 (void) sigset(SIGALRM, (void(*)(int)) closedown);
178 178 (void) alarm(RPCSVC_CLOSEDOWN);
179 179
180 180 svc_run();
181 181 zexit(1);
182 182 /* NOTREACHED */
183 183 }
184 184
185 185 /*
186 186 * Started from a shell - fork the daemon.
187 187 */
188 188
189 189 switch (fork()) {
190 190 case 0: /* child */
191 191 break;
192 192 case -1:
193 193 perror("rquotad: can't fork");
194 194 zexit(1);
195 195 default: /* parent */
196 196 zexit(0);
197 197 }
198 198
199 199 /*
200 200 * Close existing file descriptors, open "/dev/null" as
201 201 * standard input, output, and error, and detach from
202 202 * controlling terminal.
203 203 */
204 204 closefrom(0);
205 205 (void) open("/dev/null", O_RDONLY);
206 206 (void) open("/dev/null", O_WRONLY);
207 207 (void) dup(1);
208 208 (void) setsid();
209 209
210 210 openlog("rquotad", LOG_PID, LOG_DAEMON);
211 211
212 212 /*
213 213 * Create datagram service
214 214 */
215 215 if (svc_create(dispatch, RQUOTAPROG, RQUOTAVERS, "datagram_v") == 0) {
216 216 syslog(LOG_ERR, "couldn't register datagram_v service");
217 217 zexit(1);
218 218 }
219 219
220 220 /*
221 221 * Start serving
222 222 */
223 223 svc_run();
224 224 syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
225 225 return (1);
226 226 }
227 227
228 228 void
229 229 dispatch(rqstp, transp)
230 230 register struct svc_req *rqstp;
231 231 register SVCXPRT *transp;
232 232 {
233 233
234 234 request_pending = 1;
235 235
236 236 switch (rqstp->rq_proc) {
237 237 case NULLPROC:
238 238 errno = 0;
239 239 if (!svc_sendreply(transp, xdr_void, 0))
240 240 log_cant_reply(transp);
241 241 break;
242 242
243 243 case RQUOTAPROC_GETQUOTA:
244 244 case RQUOTAPROC_GETACTIVEQUOTA:
245 245 getquota(rqstp, transp);
246 246 break;
247 247
248 248 default:
249 249 svcerr_noproc(transp);
250 250 break;
251 251 }
252 252
253 253 request_pending = 0;
254 254 }
255 255
256 256 void
257 257 closedown()
258 258 {
259 259 if (!request_pending) {
260 260 int i, openfd;
261 261 struct t_info tinfo;
262 262
263 263 if (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))
264 264 zexit(0);
265 265
266 266 for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++) {
267 267 if (svc_pollfd[i].fd >= 0)
268 268 openfd++;
269 269 }
270 270
271 271 if (openfd <= 1)
272 272 zexit(0);
273 273 }
274 274 (void) alarm(RPCSVC_CLOSEDOWN);
275 275 }
276 276
277 277 static int
278 278 getzfsquota(uid_t user, char *dataset, struct dqblk *zq)
279 279 {
280 280 zfs_handle_t *zhp = NULL;
281 281 char propname[ZFS_MAXPROPLEN];
282 282 uint64_t userquota, userused;
283 283
284 284 if (g_zfs == NULL)
285 285 return (1);
286 286
287 287 if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL) {
288 288 syslog(LOG_ERR, "can not open zfs dataset %s", dataset);
289 289 return (1);
290 290 }
291 291
292 292 (void) snprintf(propname, sizeof (propname), "userquota@%u", user);
293 293 if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
294 294 _zfs_close(zhp);
295 295 return (1);
296 296 }
297 297
298 298 (void) snprintf(propname, sizeof (propname), "userused@%u", user);
299 299 if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
300 300 _zfs_close(zhp);
301 301 return (1);
302 302 }
303 303
304 304 zq->dqb_bhardlimit = userquota / DEV_BSIZE;
305 305 zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
306 306 zq->dqb_curblocks = userused / DEV_BSIZE;
307 307 _zfs_close(zhp);
308 308 return (0);
309 309 }
310 310
311 311 void
312 312 getquota(rqstp, transp)
|
↓ open down ↓ |
312 lines elided |
↑ open up ↑ |
313 313 register struct svc_req *rqstp;
314 314 register SVCXPRT *transp;
315 315 {
316 316 struct getquota_args gqa;
317 317 struct getquota_rslt gqr;
318 318 struct dqblk dqblk;
319 319 struct fsquot *fsqp;
320 320 struct timeval tv;
321 321 bool_t qactive;
322 322
323 + CTASSERT(sizeof (authp) <= RQCRED_SIZE);
324 +
323 325 gqa.gqa_pathp = NULL; /* let xdr allocate the storage */
324 326 if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&gqa)) {
325 327 svcerr_decode(transp);
326 328 return;
327 329 }
328 330 /*
329 331 * This authentication is really bogus with the current rpc
330 332 * authentication scheme. One day we will have something for real.
331 333 */
332 334 CTASSERT(sizeof (authp) <= RQCRED_SIZE);
333 335 if (rqstp->rq_cred.oa_flavor != AUTH_UNIX ||
334 336 (((authp) rqstp->rq_clntcred)->aup_uid != 0 &&
335 337 ((authp) rqstp->rq_clntcred)->aup_uid != (uid_t)gqa.gqa_uid)) {
336 338 gqr.status = Q_EPERM;
337 339 goto sendreply;
338 340 }
339 341 fsqp = findfsq(gqa.gqa_pathp);
340 342 if (fsqp == NULL) {
341 343 gqr.status = Q_NOQUOTA;
342 344 goto sendreply;
343 345 }
344 346
345 347 bzero(&dqblk, sizeof (dqblk));
346 348 if (strcmp(fsqp->fsq_fstype, MNTTYPE_ZFS) == 0) {
347 349 if (getzfsquota(gqa.gqa_uid, fsqp->fsq_devname, &dqblk)) {
348 350 gqr.status = Q_NOQUOTA;
349 351 goto sendreply;
350 352 }
351 353 qactive = TRUE;
352 354 } else {
353 355 if (quotactl(Q_GETQUOTA, fsqp->fsq_dir,
354 356 (uid_t)gqa.gqa_uid, &dqblk) != 0) {
355 357 qactive = FALSE;
356 358 if ((errno == ENOENT) ||
357 359 (rqstp->rq_proc != RQUOTAPROC_GETQUOTA)) {
358 360 gqr.status = Q_NOQUOTA;
359 361 goto sendreply;
360 362 }
361 363
362 364 /*
363 365 * If there is no quotas file, don't bother to sync it.
364 366 */
365 367 if (errno != ENOENT) {
366 368 if (quotactl(Q_ALLSYNC, fsqp->fsq_dir,
367 369 (uid_t)gqa.gqa_uid, &dqblk) < 0 &&
368 370 errno == EINVAL)
369 371 syslog(LOG_WARNING,
370 372 "Quotas are not compiled "
371 373 "into this kernel");
372 374 if (getdiskquota(fsqp, (uid_t)gqa.gqa_uid,
373 375 &dqblk) == 0) {
374 376 gqr.status = Q_NOQUOTA;
375 377 goto sendreply;
376 378 }
377 379 }
378 380 } else {
379 381 qactive = TRUE;
380 382 }
381 383 /*
382 384 * We send the remaining time instead of the absolute time
383 385 * because clock skew between machines should be much greater
384 386 * than rpc delay.
385 387 */
386 388 #define gqrslt getquota_rslt_u.gqr_rquota
387 389
388 390 gettimeofday(&tv, NULL);
389 391 gqr.gqrslt.rq_btimeleft = dqblk.dqb_btimelimit - tv.tv_sec;
390 392 gqr.gqrslt.rq_ftimeleft = dqblk.dqb_ftimelimit - tv.tv_sec;
391 393 }
392 394
393 395 gqr.status = Q_OK;
394 396 gqr.gqrslt.rq_active = qactive;
395 397 gqr.gqrslt.rq_bsize = DEV_BSIZE;
396 398 gqr.gqrslt.rq_bhardlimit = dqblk.dqb_bhardlimit;
397 399 gqr.gqrslt.rq_bsoftlimit = dqblk.dqb_bsoftlimit;
398 400 gqr.gqrslt.rq_curblocks = dqblk.dqb_curblocks;
399 401 gqr.gqrslt.rq_fhardlimit = dqblk.dqb_fhardlimit;
400 402 gqr.gqrslt.rq_fsoftlimit = dqblk.dqb_fsoftlimit;
401 403 gqr.gqrslt.rq_curfiles = dqblk.dqb_curfiles;
402 404 sendreply:
403 405 errno = 0;
404 406 if (!svc_sendreply(transp, xdr_getquota_rslt, (caddr_t)&gqr))
405 407 log_cant_reply(transp);
406 408 }
407 409
408 410 int
409 411 quotactl(cmd, mountp, uid, dqp)
410 412 int cmd;
411 413 char *mountp;
412 414 uid_t uid;
413 415 struct dqblk *dqp;
414 416 {
415 417 int fd;
416 418 int status;
417 419 struct quotctl quota;
418 420 char mountpoint[256];
419 421 FILE *fstab;
420 422 struct mnttab mntp;
421 423
422 424 if ((mountp == NULL) && (cmd == Q_ALLSYNC)) {
423 425 /*
424 426 * Find the mount point of any ufs file system. this is
425 427 * because the ioctl that implements the quotactl call has
426 428 * to go to a real file, and not to the block device.
427 429 */
428 430 if ((fstab = fopen(MNTTAB, "r")) == NULL) {
429 431 syslog(LOG_ERR, "can not open %s: %m ", MNTTAB);
430 432 return (-1);
431 433 }
432 434 fd = -1;
433 435 while ((status = getmntent(fstab, &mntp)) == NULL) {
434 436 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
435 437 !(hasmntopt(&mntp, MNTOPT_RQ) ||
436 438 hasmntopt(&mntp, MNTOPT_QUOTA)))
437 439 continue;
438 440 (void) strlcpy(mountpoint, mntp.mnt_mountp,
439 441 sizeof (mountpoint));
440 442 strcat(mountpoint, "/quotas");
441 443 if ((fd = open64(mountpoint, O_RDWR)) >= 0)
442 444 break;
443 445 }
444 446 fclose(fstab);
445 447 if (fd == -1) {
446 448 errno = ENOENT;
447 449 return (-1);
448 450 }
449 451 } else {
450 452 if (mountp == NULL || mountp[0] == '\0') {
451 453 errno = ENOENT;
452 454 return (-1);
453 455 }
454 456 (void) strlcpy(mountpoint, mountp, sizeof (mountpoint));
455 457 strcat(mountpoint, "/quotas");
456 458
457 459 if ((fd = open64(mountpoint, O_RDONLY)) < 0) {
458 460 errno = ENOENT;
459 461 syslog(LOG_ERR, "can not open %s: %m ", mountpoint);
460 462 return (-1);
461 463 }
462 464 }
463 465 quota.op = cmd;
464 466 quota.uid = uid;
465 467 quota.addr = (caddr_t)dqp;
466 468
467 469 status = ioctl(fd, Q_QUOTACTL, "a);
468 470
469 471 close(fd);
470 472 return (status);
471 473 }
472 474
473 475 /*
474 476 * Return the quota information for the given path. Returns NULL if none
475 477 * was found.
476 478 */
477 479
478 480 struct fsquot *
479 481 findfsq(char *dir)
480 482 {
481 483 struct stat sb;
482 484 struct fsquot *fsqp;
483 485 static time_t lastmtime = 0; /* mount table's previous mtime */
484 486
485 487 /*
486 488 * If we've never looked at the mount table, or it has changed
487 489 * since the last time, rebuild the list of quota'd file systems
488 490 * and remember the current mod time for the mount table.
489 491 */
490 492
491 493 if (stat(MNTTAB, &sb) < 0) {
492 494 syslog(LOG_ERR, "can't stat %s: %m", MNTTAB);
493 495 return (NULL);
494 496 }
495 497 if (lastmtime == 0 || sb.st_mtime != lastmtime) {
496 498 freefs();
497 499 setupfs();
498 500 lastmtime = sb.st_mtime;
499 501 }
500 502
501 503 /*
502 504 * Try to find the given path in the list of file systems with
503 505 * quotas.
504 506 */
505 507
506 508 if (fsqlist == NULL)
507 509 return (NULL);
508 510 if (stat(dir, &sb) < 0)
509 511 return (NULL);
510 512
511 513 for (fsqp = fsqlist; fsqp != NULL; fsqp = fsqp->fsq_next) {
512 514 if (sb.st_dev == fsqp->fsq_dev)
513 515 return (fsqp);
514 516 }
515 517
516 518 return (NULL);
517 519 }
518 520
519 521 static void
520 522 setup_zfs(struct mnttab *mp)
521 523 {
522 524 struct fsquot *fsqp;
523 525 struct stat sb;
524 526
525 527 if (stat(mp->mnt_mountp, &sb) < 0)
526 528 return;
527 529
528 530 fsqp = malloc(sizeof (struct fsquot));
529 531 if (fsqp == NULL) {
530 532 syslog(LOG_ERR, "out of memory");
531 533 zexit(1);
532 534 }
533 535 fsqp->fsq_dir = strdup(mp->mnt_mountp);
534 536 fsqp->fsq_devname = strdup(mp->mnt_special);
535 537 if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
536 538 syslog(LOG_ERR, "out of memory");
537 539 zexit(1);
538 540 }
539 541
540 542 fsqp->fsq_fstype = MNTTYPE_ZFS;
541 543 fsqp->fsq_dev = sb.st_dev;
542 544 fsqp->fsq_next = fsqlist;
543 545 fsqlist = fsqp;
544 546 }
545 547
546 548 void
547 549 setupfs()
548 550 {
549 551 struct fsquot *fsqp;
550 552 FILE *mt;
551 553 struct mnttab m;
552 554 struct stat sb;
553 555 char qfilename[MAXPATHLEN];
554 556
555 557 mt = fopen(MNTTAB, "r");
556 558 if (mt == NULL) {
557 559 syslog(LOG_ERR, "can't read %s: %m", MNTTAB);
558 560 return;
559 561 }
560 562
561 563 while (getmntent(mt, &m) == 0) {
562 564 if (strcmp(m.mnt_fstype, MNTTYPE_ZFS) == 0) {
563 565 setup_zfs(&m);
564 566 continue;
565 567 }
566 568
567 569 if (strcmp(m.mnt_fstype, MNTTYPE_UFS) != 0)
568 570 continue;
569 571 if (!hasquota(m.mnt_mntopts)) {
570 572 snprintf(qfilename, sizeof (qfilename), "%s/%s",
571 573 m.mnt_mountp, QFNAME);
572 574 if (access(qfilename, F_OK) < 0)
573 575 continue;
574 576 }
575 577 if (stat(m.mnt_special, &sb) < 0 ||
576 578 (sb.st_mode & S_IFMT) != S_IFBLK)
577 579 continue;
578 580 fsqp = malloc(sizeof (struct fsquot));
579 581 if (fsqp == NULL) {
580 582 syslog(LOG_ERR, "out of memory");
581 583 zexit(1);
582 584 }
583 585 fsqp->fsq_dir = strdup(m.mnt_mountp);
584 586 fsqp->fsq_devname = strdup(m.mnt_special);
585 587 if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
586 588 syslog(LOG_ERR, "out of memory");
587 589 zexit(1);
588 590 }
589 591 fsqp->fsq_fstype = MNTTYPE_UFS;
590 592 fsqp->fsq_dev = sb.st_rdev;
591 593 fsqp->fsq_next = fsqlist;
592 594 fsqlist = fsqp;
593 595 }
594 596 (void) fclose(mt);
595 597 }
596 598
597 599 /*
598 600 * Free the memory used by the current list of quota'd file systems. Nulls
599 601 * out the list.
600 602 */
601 603
602 604 void
603 605 freefs()
604 606 {
605 607 register struct fsquot *fsqp;
606 608
607 609 while ((fsqp = fsqlist) != NULL) {
608 610 fsqlist = fsqp->fsq_next;
609 611 free(fsqp->fsq_dir);
610 612 free(fsqp->fsq_devname);
611 613 free(fsqp);
612 614 }
613 615 }
614 616
615 617 int
616 618 getdiskquota(fsqp, uid, dqp)
617 619 struct fsquot *fsqp;
618 620 uid_t uid;
619 621 struct dqblk *dqp;
620 622 {
621 623 int fd;
622 624 char qfilename[MAXPATHLEN];
623 625
624 626 snprintf(qfilename, sizeof (qfilename), "%s/%s", fsqp->fsq_dir, QFNAME);
625 627 if ((fd = open64(qfilename, O_RDONLY)) < 0)
626 628 return (0);
627 629 (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
628 630 if (read(fd, dqp, sizeof (struct dqblk)) != sizeof (struct dqblk)) {
629 631 close(fd);
630 632 return (0);
631 633 }
632 634 close(fd);
633 635 if (dqp->dqb_bhardlimit == 0 && dqp->dqb_bsoftlimit == 0 &&
634 636 dqp->dqb_fhardlimit == 0 && dqp->dqb_fsoftlimit == 0) {
635 637 return (0);
636 638 }
637 639 return (1);
638 640 }
639 641
640 642 /*
641 643 * Get the client's hostname from the transport handle
642 644 * If the name is not available then return "(anon)".
643 645 */
644 646 struct nd_hostservlist *
645 647 getclientsnames(transp)
646 648 SVCXPRT *transp;
647 649 {
648 650 struct netbuf *nbuf;
649 651 struct netconfig *nconf;
650 652 static struct nd_hostservlist *serv;
651 653 static struct nd_hostservlist anon_hsl;
652 654 static struct nd_hostserv anon_hs;
653 655 static char anon_hname[] = "(anon)";
654 656 static char anon_sname[] = "";
655 657
656 658 /* Set up anonymous client */
657 659 anon_hs.h_host = anon_hname;
658 660 anon_hs.h_serv = anon_sname;
659 661 anon_hsl.h_cnt = 1;
660 662 anon_hsl.h_hostservs = &anon_hs;
661 663
662 664 if (serv) {
663 665 netdir_free((char *)serv, ND_HOSTSERVLIST);
664 666 serv = NULL;
665 667 }
666 668 nconf = getnetconfigent(transp->xp_netid);
667 669 if (nconf == NULL) {
668 670 syslog(LOG_ERR, "%s: getnetconfigent failed",
669 671 transp->xp_netid);
670 672 return (&anon_hsl);
671 673 }
672 674
673 675 nbuf = svc_getrpccaller(transp);
674 676 if (nbuf == NULL) {
675 677 freenetconfigent(nconf);
676 678 return (&anon_hsl);
677 679 }
678 680 if (netdir_getbyaddr(nconf, &serv, nbuf)) {
679 681 freenetconfigent(nconf);
680 682 return (&anon_hsl);
681 683 }
682 684 freenetconfigent(nconf);
683 685 return (serv);
684 686 }
685 687
686 688 void
687 689 log_cant_reply(transp)
688 690 SVCXPRT *transp;
689 691 {
690 692 int saverrno;
691 693 struct nd_hostservlist *clnames;
692 694 register char *name;
693 695
694 696 saverrno = errno; /* save error code */
695 697 clnames = getclientsnames(transp);
696 698 if (clnames == NULL)
697 699 return;
698 700 name = clnames->h_hostservs->h_host;
699 701
700 702 errno = saverrno;
701 703 if (errno == 0)
702 704 syslog(LOG_ERR, "couldn't send reply to %s", name);
703 705 else
704 706 syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
705 707 }
706 708
707 709 char *mntopts[] = { MNTOPT_QUOTA, NULL };
708 710 #define QUOTA 0
709 711
710 712 /*
711 713 * Return 1 if "quota" appears in the options string
712 714 */
713 715 int
714 716 hasquota(opts)
715 717 char *opts;
716 718 {
717 719 char *value;
718 720
719 721 if (opts == NULL)
720 722 return (0);
721 723 while (*opts != '\0') {
722 724 if (getsubopt(&opts, mntopts, &value) == QUOTA)
723 725 return (1);
724 726 }
725 727
726 728 return (0);
727 729 }
728 730
729 731 static void
730 732 zexit(int n)
731 733 {
732 734 if (g_zfs != NULL)
733 735 _libzfs_fini(g_zfs);
734 736 exit(n);
735 737 }
|
↓ open down ↓ |
403 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX