8aa01927da6ee792cde814d2be403d999b6f7028
[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                 if (strncmp(argv[0], "/dev/", 5) == 0) {
153                   disk_name = argv[0] + 5;
154                 } else {
155                         disk_name = argv[0];
156                 }
157         } else if (argc > 1) {
158                 usage();
159                 /* NOT REACHED */
160         }
161
162         /*
163          * Check arguments:
164          * - need to use at least one mode
165          */
166         if (!(lflag || pflag || sflag)) {
167                 usage();
168                 /* NOT REACHED */
169         }
170
171         dev_fd = open("/dev/dsched", O_RDWR);
172         if (dev_fd == -1)
173                 err(1, "open(/dev/dsched)");
174
175         if (lflag) {
176                 if (dflag) {
177                         strncpy(dioc.dev_name, disk_name, DSCHED_NAME_LENGTH);
178                         error = dsched_ioctl(DSCHED_LIST_DISK, &dioc);
179                         if (!error) {
180                                 printf("%s\t=>\t%s\n",
181                                     disk_name, dioc.pol_name);
182                         }
183                 } else {
184                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
185                                 printf("%s\t=>\t%s\n",
186                                     dioc.dev_name, dioc.pol_name);
187                         }
188                 }
189         }
190
191         if (pflag) {
192                 DSCHED_FOREACH_POLICY(dev_fd, &dioc) {
193                         printf("%s\n", dioc.pol_name);
194                 }
195         }
196
197         if (sflag) {
198                 if (dflag) {
199                         error = dsched_set_disk_policy(disk_name, policy);
200                 } else {
201                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
202                                 error = dsched_set_disk_policy(dioc.dev_name,
203                                     policy);
204                         }
205                 }
206         }
207
208         close(dev_fd);
209
210         return (error);
211 }