]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - libexec/rpc.rquotad/rquotad.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / libexec / rpc.rquotad / rquotad.c
1 /*
2  * by Manuel Bouyer (bouyer@ensta.fr)
3  *
4  * There is no copyright, you can use it as you want.
5  */
6
7 #include <sys/cdefs.h>
8 __FBSDID("$FreeBSD$");
9
10 #include <sys/param.h>
11 #include <sys/mount.h>
12 #include <sys/file.h>
13 #include <sys/stat.h>
14 #include <sys/socket.h>
15
16 #include <ufs/ufs/quota.h>
17 #include <rpc/rpc.h>
18 #include <rpcsvc/rquota.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fstab.h>
25 #include <grp.h>
26 #include <libutil.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <unistd.h>
34
35 static void rquota_service(struct svc_req *request, SVCXPRT *transp);
36 static void sendquota(struct svc_req *request, SVCXPRT *transp);
37 static void initfs(void);
38 static int getfsquota(long id, char *path, struct dqblk *dqblk);
39
40 static struct quotafile **qfa;  /* array of qfs */
41 static int nqf, szqf;           /* number of qfs and size of array */
42 static int from_inetd = 1;
43
44 static void
45 cleanup(int sig)
46 {
47
48         (void)sig;
49         (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
50         exit(0);
51 }
52
53 int
54 main(void)
55 {
56         SVCXPRT *transp;
57         int ok;
58         struct sockaddr_storage from;
59         socklen_t fromlen;
60
61         fromlen = sizeof(from);
62         if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
63                 from_inetd = 0;
64
65         if (!from_inetd) {
66                 daemon(0, 0);
67                 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
68                 (void)signal(SIGINT, cleanup);
69                 (void)signal(SIGTERM, cleanup);
70                 (void)signal(SIGHUP, cleanup);
71         }
72
73         openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
74
75         /* create and register the service */
76         if (from_inetd) {
77                 transp = svc_tli_create(0, NULL, NULL, 0, 0);
78                 if (transp == NULL) {
79                         syslog(LOG_ERR, "couldn't create udp service.");
80                         exit(1);
81                 }
82                 ok = svc_reg(transp, RQUOTAPROG, RQUOTAVERS,
83                     rquota_service, NULL);
84         } else {
85                 ok = svc_create(rquota_service,
86                     RQUOTAPROG, RQUOTAVERS, "udp");
87         }
88         if (!ok) {
89                 syslog(LOG_ERR,
90                     "unable to register (RQUOTAPROG, RQUOTAVERS, %s)",
91                     from_inetd ? "(inetd)" : "udp");
92                 exit(1);
93         }
94
95         initfs();
96         svc_run();
97         syslog(LOG_ERR, "svc_run returned");
98         exit(1);
99 }
100
101 static void
102 rquota_service(struct svc_req *request, SVCXPRT *transp)
103 {
104
105         switch (request->rq_proc) {
106         case NULLPROC:
107                 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
108                 break;
109         case RQUOTAPROC_GETQUOTA:
110         case RQUOTAPROC_GETACTIVEQUOTA:
111                 sendquota(request, transp);
112                 break;
113         default:
114                 svcerr_noproc(transp);
115                 break;
116         }
117         if (from_inetd)
118                 exit(0);
119 }
120
121 /* read quota for the specified id, and send it */
122 static void
123 sendquota(struct svc_req *request, SVCXPRT *transp)
124 {
125         struct getquota_args getq_args;
126         struct getquota_rslt getq_rslt;
127         struct dqblk dqblk;
128         struct timeval timev;
129         int scale;
130
131         bzero(&getq_args, sizeof(getq_args));
132         if (!svc_getargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
133                 svcerr_decode(transp);
134                 return;
135         }
136         if (request->rq_cred.oa_flavor != AUTH_UNIX) {
137                 /* bad auth */
138                 getq_rslt.status = Q_EPERM;
139         } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
140                 /* failed, return noquota */
141                 getq_rslt.status = Q_NOQUOTA;
142         } else {
143                 gettimeofday(&timev, NULL);
144                 getq_rslt.status = Q_OK;
145                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
146                 scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
147                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
148                     DEV_BSIZE * scale;
149                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
150                     dqblk.dqb_bhardlimit / scale;
151                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
152                     dqblk.dqb_bsoftlimit / scale;
153                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
154                     dqblk.dqb_curblocks / scale;
155                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
156                     dqblk.dqb_ihardlimit;
157                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
158                     dqblk.dqb_isoftlimit;
159                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
160                     dqblk.dqb_curinodes;
161                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
162                     dqblk.dqb_btime - timev.tv_sec;
163                 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
164                     dqblk.dqb_itime - timev.tv_sec;
165         }
166         if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
167                 svcerr_systemerr(transp);
168         if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
169                 syslog(LOG_ERR, "unable to free arguments");
170                 exit(1);
171         }
172 }
173
174 static void
175 initfs(void)
176 {
177         struct fstab *fs;
178
179         setfsent();
180         szqf = 8;
181         if ((qfa = malloc(szqf * sizeof *qfa)) == NULL)
182                 goto enomem;
183         while ((fs = getfsent())) {
184                 if (strcmp(fs->fs_vfstype, "ufs"))
185                         continue;
186                 if (nqf >= szqf) {
187                         szqf *= 2;
188                         if ((qfa = reallocf(qfa, szqf * sizeof *qfa)) == NULL)
189                                 goto enomem;
190                 }
191                 if ((qfa[nqf] = quota_open(fs, USRQUOTA, O_RDONLY)) == NULL) {
192                         if (errno != EOPNOTSUPP)
193                                 goto fserr;
194                         continue;
195                 }
196                 ++nqf;
197                 /* XXX */
198         }
199         endfsent();
200         return;
201 enomem:
202         syslog(LOG_ERR, "out of memory");
203         exit(1);
204 fserr:
205         syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno));
206         exit(1);
207 }
208
209 /*
210  * gets the quotas for id, filesystem path.
211  * Return 0 if fail, 1 otherwise
212  */
213 static int
214 getfsquota(long id, char *path, struct dqblk *dqblk)
215 {
216         int i;
217
218         for (i = 0; i < nqf; ++i)
219                 if (quota_check_path(qfa[i], path) == 1)
220                         return (quota_read(qfa[i], dqblk, id) == 0);
221         return (0);
222 }