918a4731f159f1d73605a0cdbc91e2ae0caaf691
[dragonfly.git] / usr.sbin / dschedctl / dschedctl.c
1 /*
2  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/types.h>
36 #include <sys/cdefs.h>
37 #include <sys/syslimits.h>
38 #include <sys/ioctl.h>
39 #include <sys/device.h>
40 #include <sys/queue.h>
41 #include <sys/stat.h>
42 #include <sys/dsched.h>
43
44 #include <ctype.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <grp.h>
49 #include <libgen.h>
50 #include <pwd.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #define DSCHED_FOREACH_DISK(dev_fd, diocp)              \
58         for ((diocp)->num_elem = 0;                     \
59              (ioctl((dev_fd),                           \
60                  DSCHED_LIST_DISKS, (diocp)) != -1);    \
61              ++(diocp)->num_elem)
62
63 #define DSCHED_FOREACH_POLICY(dev_fd, diocp)            \
64         for ((diocp)->num_elem = 0;                     \
65              (ioctl((dev_fd),                           \
66                  DSCHED_LIST_POLICIES, (diocp)) != -1); \
67              ++(diocp)->num_elem)
68
69 static int dev_fd;
70 static int verbose = 0;
71
72 static void
73 usage(void)
74 {
75         fprintf(stderr,
76             "Usage: dschedctl <commands>\n"
77             "Valid commands are:\n"
78             " -l [disk]\n"
79             "\t Lists all disks and their policies, or just for [disk]\n"
80             " -p\n"
81             "\t Lists all available I/O scheduling policies\n"
82             " -s <policy> [disk]\n"
83             "\t Switches the policy of [disk] or otherwise all disks to "
84             "<policy>\n");
85
86         exit(1);
87 }
88
89 static int
90 dsched_ioctl(unsigned long cmd, struct dsched_ioctl *pdioc)
91 {
92         if (ioctl(dev_fd, cmd, pdioc) == -1)
93                 err(1, "ioctl");
94
95         return 0;
96 }
97
98 static int dsched_set_disk_policy(char *disk_name, char *policy)
99 {
100         struct dsched_ioctl     dioc;
101         int error;
102
103         bzero(&dioc, sizeof(dioc));
104         strncpy(dioc.dev_name, disk_name, DSCHED_NAME_LENGTH);
105         strncpy(dioc.pol_name, policy, DSCHED_NAME_LENGTH);
106         error = dsched_ioctl(DSCHED_SET_DEVICE_POLICY, &dioc);
107
108         if ((!error) && verbose) {
109                 printf("Switched scheduler policy of %s successfully to %s\n",
110                     disk_name, policy);
111         }
112
113         return error;
114 }
115
116 int main(int argc, char *argv[])
117 {
118         struct dsched_ioctl     dioc;
119         char    *disk_name = NULL;
120         char    *policy = NULL;
121         int     dflag = 0, lflag = 0, pflag = 0, sflag = 0;
122         int     ch, error = 0;
123
124         while ((ch = getopt(argc, argv, "hlps:v")) != -1) {
125                 switch (ch) {
126                 case 'l':
127                         lflag = 1;
128                         break;
129                 case 'p':
130                         pflag = 1;
131                         break;
132                 case 's':
133                         sflag = 1;
134                         policy = optarg;
135                         break;
136                 case 'v':
137                         verbose = 1;
138                         break;
139                 case 'h':
140                 case '?':
141                 default:
142                         usage();
143                         /* NOT REACHED */
144                 }
145         }
146
147         argc -= optind;
148         argv += optind;
149
150         if (argc == 1) {
151                 dflag = 1;
152                 disk_name = argv[0];
153         } else if (argc > 1) {
154                 usage();
155                 /* NOT REACHED */
156         }
157
158         /*
159          * Check arguments:
160          * - need to use at least one mode
161          */
162         if (!(lflag || pflag || sflag)) {
163                 usage();
164                 /* NOT REACHED */
165         }
166
167         dev_fd = open("/dev/dsched", O_RDWR);
168         if (dev_fd == -1)
169                 err(1, "open(/dev/dsched)");
170
171         if (lflag) {
172                 if (dflag) {
173                         strncpy(dioc.dev_name, disk_name, DSCHED_NAME_LENGTH);
174                         error = dsched_ioctl(DSCHED_LIST_DISK, &dioc);
175                         if (!error) {
176                                 printf("%s\t=>\t%s\n",
177                                     disk_name, dioc.pol_name);
178                         }
179                 } else {
180                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
181                                 printf("%s\t=>\t%s\n",
182                                     dioc.dev_name, dioc.pol_name);
183                         }
184                 }
185         }
186
187         if (pflag) {
188                 DSCHED_FOREACH_POLICY(dev_fd, &dioc) {
189                         printf("%s\n", dioc.pol_name);
190                 }
191         }
192
193         if (sflag) {
194                 if (dflag) {
195                         error = dsched_set_disk_policy(disk_name, policy);
196                 } else {
197                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
198                                 error = dsched_set_disk_policy(dioc.dev_name,
199                                     policy);
200                         }
201                 }
202         }
203
204         close(dev_fd);
205
206         return (error);
207 }