]> git.ozlabs.org Git - petitboot/blob - utils/pb-event.c
discover/boot: Fix stale boot cancellation code
[petitboot] / utils / pb-event.c
1 /*
2  *  Copyright (C) 2009 Sony Computer Entertainment Inc.
3  *  Copyright 2009 Sony Corp.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #if defined(HAVE_CONFIG_H)
20 #include "config.h"
21 #endif
22
23 #include <assert.h>
24 #include <err.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/socket.h>
31 #include <sys/types.h>
32 #include <sys/un.h>
33
34 #include "discover/user-event.h"
35
36 #if defined(DEBUG)
37 #define DBG(_args...) do {fprintf(stderr, _args); fflush(stderr); } while (0)
38 #else
39 static inline int __attribute__ ((format (printf, 1, 2))) DBG(
40         __attribute__((unused)) const char *fmt, ...) {return 0; }
41 #endif
42
43 static void print_version(void)
44 {
45         printf("pb-event (" PACKAGE_NAME ") " PACKAGE_VERSION "\n");
46 }
47
48 static void print_usage(void)
49 {
50         print_version();
51         printf(
52 "Usage: pb-event [-h] [event...]\n"
53 "\n"
54 "       Send a single petitboot user event to the petitboot discover server.\n"
55 "       Events can be read from stdin, or provided on the command line.\n"
56 "       User events must have the following format:\n"
57 "\n"
58 "         (add|remove|boot|sync)@device-id [name=value] [image=value] [args=value]\n"
59 "\n"
60 "       When read from stdin, components are separated by NUL chars\n"
61 "\n"
62 "Examples:\n"
63 "\n"
64 "    args:\n"
65 "       pb-event add@/net/eth0 name=netboot image=tftp://192.168.1.10/vmlinux\n"
66 "       pb-event remove@/net/eth0\n"
67 "\n"
68 "    stdin:\n"
69 "       printf 'add@/net/eth0\\0name=netboot\\0image=tftp://10.0.0.2/vmlinux\\0' \\\n"
70 "           | pb-event\n"
71 "       printf 'remove@/net/eth0\\0' | pb-event\n"
72 "\n");
73 }
74
75 static const char *err_max_size = "pb-event: message too large "
76                                         "(%zu byte max)\n";
77
78 static ssize_t parse_event_args(int n, char * const * args,
79                 char *buf, size_t max_len)
80 {
81         ssize_t arg_len, total_len;
82         const char *arg;
83         int i;
84
85         total_len = 0;
86
87         for (i = 0; i < n; i++) {
88                 arg = args[i];
89                 arg_len = strlen(arg);
90
91                 if (total_len + (size_t)i + 1 > max_len) {
92                         fprintf(stderr, err_max_size, max_len);
93                         return -1;
94                 }
95
96                 memcpy(buf + total_len, arg, arg_len);
97                 total_len += arg_len;
98
99                 buf[total_len] = '\0';
100                 total_len++;
101         }
102
103         return total_len;
104
105 }
106
107 static ssize_t parse_event_file(FILE *filp, char *buf, size_t max_len)
108 {
109         int len;
110
111         len = fread(buf, 1, max_len, filp);
112
113         if (!feof(filp)) {
114                 fprintf(stderr, err_max_size, max_len);
115                 return -1;
116         }
117
118         if (!len)
119                 return -1;
120
121         return len;
122 }
123
124 static int send_event(char *buf, ssize_t len)
125 {
126         struct sockaddr_un addr;
127         int sd, i;
128
129         sd = socket(PF_UNIX, SOCK_DGRAM, 0);
130         if (sd < 0)
131                 err(EXIT_FAILURE, "socket");
132
133         memset(&addr, 0, sizeof(addr));
134         addr.sun_family = AF_UNIX;
135         strcpy(addr.sun_path, PBOOT_USER_EVENT_SOCKET);
136
137         for (i = 10; i; i--) {
138                 ssize_t sent = sendto(sd, buf, len, 0,
139                                 (struct sockaddr *)&addr, SUN_LEN(&addr));
140
141                 if (sent == len)
142                         break;
143
144                 DBG("pb-event: waiting for server %d\n", i);
145                 sleep(1);
146         }
147
148         close(sd);
149
150         if (!i)
151                 err(EXIT_FAILURE, "send");
152
153         DBG("pb-event: wrote %zu bytes\n", len);
154
155         return 0;
156 }
157
158 int main(int argc, char *argv[])
159 {
160         char buf[PBOOT_USER_EVENT_SIZE];
161         ssize_t len;
162
163         if (argc >= 2 && !strcmp(argv[1], "-h")) {
164                 print_usage();
165                 return EXIT_SUCCESS;
166         }
167
168         if (argc > 1) {
169                 len = parse_event_args(argc - 1, argv + 1,
170                                         buf, sizeof(buf));
171         } else {
172                 len = parse_event_file(stdin, buf, sizeof(buf));
173         }
174
175         if (len < 0)
176                 return EXIT_FAILURE;
177
178         send_event(buf, len);
179
180         return EXIT_SUCCESS;
181 }