gstreamer: Fix memory leaks when context parse fails
[platform/upstream/gstreamer.git] / libs / gst / helpers / gst-ptp-helper.c
1 /* GStreamer
2  * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
3  *
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /* Helper process that runs setuid root or with appropriate privileges to
22  * listen on ports < 1024, do multicast operations and get MAC addresses of
23  * interfaces. Privileges are dropped after these operations are done.
24  *
25  * It listens on the PTP multicast group on port 319 and 320 and forwards
26  * everything received there to stdout, while forwarding everything received
27  * on stdout to those sockets.
28  * Additionally it provides the MAC address of a network interface via stdout
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <errno.h>
39 #include <sys/ioctl.h>
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <string.h>
43
44 #ifdef HAVE_GETIFADDRS_AF_LINK
45 #include <ifaddrs.h>
46 #include <net/if_dl.h>
47 #endif
48
49 #ifdef HAVE_PTP_HELPER_SETUID
50 #include <grp.h>
51 #include <pwd.h>
52 #endif
53
54 #ifdef HAVE_PTP_HELPER_CAPABILITIES
55 #include <sys/capability.h>
56 #endif
57
58 #include <glib.h>
59 #include <gio/gio.h>
60
61 #include <gst/gst.h>
62 #include <gst/net/gstptp_private.h>
63
64 #define PTP_MULTICAST_GROUP "224.0.1.129"
65 #define PTP_EVENT_PORT   319
66 #define PTP_GENERAL_PORT 320
67
68 static gchar **ifaces = NULL;
69 static gboolean verbose = FALSE;
70 static guint64 clock_id = (guint64) - 1;
71 static guint8 clock_id_array[8];
72
73 static GOptionEntry opt_entries[] = {
74   {"interface", 'i', 0, G_OPTION_ARG_STRING_ARRAY, &ifaces,
75       "Interface to listen on", NULL},
76   {"clock-id", 'c', 0, G_OPTION_ARG_INT64, &clock_id,
77       "PTP clock id", NULL},
78   {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
79       "Be verbose", NULL},
80   {NULL}
81 };
82
83 static GSocketAddress *event_saddr, *general_saddr;
84 static GSocket *socket_event, *socket_general;
85 static GIOChannel *stdin_channel, *stdout_channel;
86
87 static gboolean
88 have_socket_data_cb (GSocket * socket, GIOCondition condition,
89     gpointer user_data)
90 {
91   gchar buffer[8192];
92   gssize read;
93   gsize written;
94   GError *err = NULL;
95   GIOStatus status;
96   StdIOHeader header = { 0, };
97
98   read = g_socket_receive (socket, buffer, sizeof (buffer), NULL, &err);
99   if (read == -1)
100     g_error ("Failed to read from socket: %s", err->message);
101   g_clear_error (&err);
102
103   if (verbose)
104     g_message ("Received %" G_GSSIZE_FORMAT " bytes from %s socket", read,
105         (socket == socket_event ? "event" : "general"));
106
107   header.size = read;
108   header.type = (socket == socket_event) ? TYPE_EVENT : TYPE_GENERAL;
109
110   status =
111       g_io_channel_write_chars (stdout_channel, (gchar *) & header,
112       sizeof (header), &written, &err);
113   if (status == G_IO_STATUS_ERROR) {
114     g_error ("Failed to write to stdout: %s", err->message);
115     g_clear_error (&err);
116   } else if (status == G_IO_STATUS_EOF) {
117     g_message ("EOF on stdout");
118     exit (0);
119   } else if (status != G_IO_STATUS_NORMAL) {
120     g_error ("Unexpected stdout write status: %d", status);
121   } else if (written != sizeof (header)) {
122     g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
123   }
124
125   status =
126       g_io_channel_write_chars (stdout_channel, buffer, read, &written, &err);
127   if (status == G_IO_STATUS_ERROR) {
128     g_error ("Failed to write to stdout: %s", err->message);
129     g_clear_error (&err);
130   } else if (status == G_IO_STATUS_EOF) {
131     g_message ("EOF on stdout");
132     exit (0);
133   } else if (status != G_IO_STATUS_NORMAL) {
134     g_error ("Unexpected stdout write status: %d", status);
135   } else if (written != read) {
136     g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
137   }
138
139   return G_SOURCE_CONTINUE;
140 }
141
142 static gboolean
143 have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
144     gpointer user_data)
145 {
146   GIOStatus status;
147   StdIOHeader header = { 0, };
148   gchar buffer[8192];
149   GError *err = NULL;
150   gsize read;
151   gssize written;
152
153   if ((condition & G_IO_STATUS_EOF)) {
154     g_message ("EOF on stdin");
155     exit (0);
156   }
157
158   status =
159       g_io_channel_read_chars (channel, (gchar *) & header, sizeof (header),
160       &read, &err);
161   if (status == G_IO_STATUS_ERROR) {
162     g_error ("Failed to read from stdin: %s", err->message);
163     g_clear_error (&err);
164   } else if (status == G_IO_STATUS_EOF) {
165     g_message ("EOF on stdin");
166     exit (0);
167   } else if (status != G_IO_STATUS_NORMAL) {
168     g_error ("Unexpected stdin read status: %d", status);
169   } else if (read != sizeof (header)) {
170     g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
171   } else if (header.size > 8192) {
172     g_error ("Unexpected size: %u", header.size);
173   }
174
175   status = g_io_channel_read_chars (channel, buffer, header.size, &read, &err);
176   if (status == G_IO_STATUS_ERROR) {
177     g_error ("Failed to read from stdin: %s", err->message);
178     g_clear_error (&err);
179   } else if (status == G_IO_STATUS_EOF) {
180     g_message ("EOF on stdin");
181     exit (0);
182   } else if (status != G_IO_STATUS_NORMAL) {
183     g_error ("Unexpected stdin read status: %d", status);
184   } else if (read != header.size) {
185     g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
186   }
187
188   switch (header.type) {
189     case TYPE_EVENT:
190     case TYPE_GENERAL:
191       written =
192           g_socket_send_to (header.type ==
193           TYPE_EVENT ? socket_event : socket_general,
194           (header.type == TYPE_EVENT ? event_saddr : general_saddr), buffer,
195           header.size, NULL, &err);
196       if (written == -1)
197         g_error ("Failed to write to socket: %s", err->message);
198       else if (written != header.size)
199         g_error ("Unexpected write size: %" G_GSSIZE_FORMAT, written);
200       g_clear_error (&err);
201       if (verbose)
202         g_message ("Sent %" G_GSSIZE_FORMAT " bytes to %s socket", read,
203             (header.type == TYPE_EVENT ? "event" : "general"));
204       break;
205     default:
206       break;
207   }
208
209   return G_SOURCE_CONTINUE;
210 }
211
212 static void
213 setup_sockets (void)
214 {
215   GInetAddress *bind_addr, *mcast_addr;
216   GSocketAddress *bind_saddr;
217   GSource *socket_event_source, *socket_general_source;
218   gchar **probed_ifaces = NULL;
219   GError *err = NULL;
220
221   /* Create sockets */
222   socket_event =
223       g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
224       G_SOCKET_PROTOCOL_UDP, &err);
225   if (!socket_event)
226     g_error ("Couldn't create event socket: %s", err->message);
227   g_clear_error (&err);
228
229   socket_general =
230       g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
231       G_SOCKET_PROTOCOL_UDP, &err);
232   if (!socket_general)
233     g_error ("Couldn't create general socket: %s", err->message);
234   g_clear_error (&err);
235
236   /* Bind sockets */
237   bind_addr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
238   bind_saddr = g_inet_socket_address_new (bind_addr, PTP_EVENT_PORT);
239   if (!g_socket_bind (socket_event, bind_saddr, TRUE, &err))
240     g_error ("Couldn't bind event socket: %s", err->message);
241   g_object_unref (bind_saddr);
242   bind_saddr = g_inet_socket_address_new (bind_addr, PTP_GENERAL_PORT);
243   if (!g_socket_bind (socket_general, bind_saddr, TRUE, &err))
244     g_error ("Couldn't bind general socket: %s", err->message);
245   g_object_unref (bind_saddr);
246   g_object_unref (bind_addr);
247
248   /* Probe all non-loopback interfaces */
249   if (!ifaces) {
250 #if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
251     struct ifreq ifr;
252     struct ifconf ifc;
253     gchar buf[8192];
254
255     ifc.ifc_len = sizeof (buf);
256     ifc.ifc_buf = buf;
257     if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
258       guint i, idx = 0;
259
260       probed_ifaces = g_new0 (gchar *, ifc.ifc_len + 1);
261
262       for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
263         strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
264         if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
265           if ((ifr.ifr_flags & IFF_LOOPBACK))
266             continue;
267           probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
268           idx++;
269         } else {
270           g_warning ("can't get flags of interface '%s'",
271               ifc.ifc_req[i].ifr_name);
272           probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
273           idx++;
274         }
275         if (idx != 0)
276           ifaces = probed_ifaces;
277       }
278     }
279 #elif defined(HAVE_GETIFADDRS_AF_LINK)
280     struct ifaddrs *ifaddr, *ifa;
281
282     if (getifaddrs (&ifaddr) != -1) {
283       GPtrArray *arr;
284
285       arr = g_ptr_array_new ();
286
287       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
288         if ((ifa->ifa_flags & IFF_LOOPBACK))
289           continue;
290
291         if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
292           continue;
293
294         g_ptr_array_add (arr, g_strdup (ifa->ifa_name));
295       }
296       freeifaddrs (ifaddr);
297
298       g_ptr_array_add (arr, NULL);
299       ifaces = probed_ifaces = (gchar **) g_ptr_array_free (arr, FALSE);
300     }
301 #else
302 #warning "Implement something to list all network interfaces"
303 #endif
304   }
305
306   /* Get a clock id from the MAC address if none was given */
307   if (clock_id == (guint64) - 1) {
308     gboolean success = FALSE;
309
310 #if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
311     struct ifreq ifr;
312
313     if (ifaces) {
314       gchar **ptr = ifaces;
315
316       while (*ptr) {
317         strncpy (ifr.ifr_name, *ptr, IFNAMSIZ);
318         if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR, &ifr) == 0) {
319           clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
320           clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
321           clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
322           clock_id_array[3] = 0xff;
323           clock_id_array[4] = 0xfe;
324           clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
325           clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
326           clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
327           success = TRUE;
328           break;
329         }
330       }
331
332       ptr++;
333     } else {
334       struct ifconf ifc;
335       gchar buf[8192];
336
337       ifc.ifc_len = sizeof (buf);
338       ifc.ifc_buf = buf;
339       if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
340         guint i;
341
342         for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
343           strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
344           if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
345             if ((ifr.ifr_flags & IFF_LOOPBACK))
346               continue;
347
348             if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR,
349                     &ifr) == 0) {
350               clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
351               clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
352               clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
353               clock_id_array[3] = 0xff;
354               clock_id_array[4] = 0xfe;
355               clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
356               clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
357               clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
358               success = TRUE;
359               break;
360             }
361           } else {
362             g_warning ("can't get flags of interface '%s'",
363                 ifc.ifc_req[i].ifr_name);
364           }
365         }
366       }
367     }
368 #elif defined(HAVE_GETIFADDRS_AF_LINK)
369     struct ifaddrs *ifaddr, *ifa;
370
371     if (getifaddrs (&ifaddr) != -1) {
372       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
373         struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
374         guint8 mac_addr[6];
375
376         if ((ifa->ifa_flags & IFF_LOOPBACK))
377           continue;
378
379         if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
380           continue;
381
382         if (ifaces) {
383           gchar **p = ifaces;
384           gboolean found = FALSE;
385
386           while (*p) {
387             if (strcmp (*p, ifa->ifa_name) == 0) {
388               found = TRUE;
389               break;
390             }
391             p++;
392           }
393
394           if (!found)
395             continue;
396         }
397
398         if (sdl->sdl_alen != 6)
399           continue;
400
401         memcpy (mac_addr, LLADDR (sdl), sdl->sdl_alen);
402
403         clock_id_array[0] = mac_addr[0];
404         clock_id_array[1] = mac_addr[1];
405         clock_id_array[2] = mac_addr[2];
406         clock_id_array[3] = 0xff;
407         clock_id_array[4] = 0xfe;
408         clock_id_array[5] = mac_addr[3];
409         clock_id_array[6] = mac_addr[4];
410         clock_id_array[7] = mac_addr[5];
411         success = TRUE;
412         break;
413       }
414
415       freeifaddrs (ifaddr);
416     }
417 #else
418 #warning "Implement something to get MAC addresses of network interfaces"
419 #endif
420
421     if (!success) {
422       g_warning ("can't get any MAC address, using random clock id");
423       clock_id = (((guint64) g_random_int ()) << 32) | (g_random_int ());
424       GST_WRITE_UINT64_BE (clock_id_array, clock_id);
425       clock_id_array[3] = 0xff;
426       clock_id_array[4] = 0xfe;
427     }
428   } else {
429     GST_WRITE_UINT64_BE (clock_id_array, clock_id);
430   }
431
432   /* Join multicast groups */
433   mcast_addr = g_inet_address_new_from_string (PTP_MULTICAST_GROUP);
434   if (ifaces) {
435     gchar **ptr = ifaces;
436     gboolean success = FALSE;
437
438     while (*ptr) {
439       gint c = 0;
440       if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, *ptr,
441               &err)
442           && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
443         g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
444             err->message);
445       else
446         c++;
447       g_clear_error (&err);
448
449       if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
450               *ptr, &err)
451           && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
452         g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
453             err->message);
454       else
455         c++;
456       g_clear_error (&err);
457
458       if (c == 2)
459         success = TRUE;
460       ptr++;
461     }
462
463     if (!success) {
464       /* Join multicast group without any interface */
465       if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
466               &err))
467         g_error ("Couldn't join multicast group: %s", err->message);
468       g_clear_error (&err);
469       if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
470               NULL, &err))
471         g_error ("Couldn't join multicast group: %s", err->message);
472       g_clear_error (&err);
473     }
474   } else {
475     /* Join multicast group without any interface */
476     if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
477             &err))
478       g_error ("Couldn't join multicast group: %s", err->message);
479     g_clear_error (&err);
480     if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE, NULL,
481             &err))
482       g_error ("Couldn't join multicast group: %s", err->message);
483     g_clear_error (&err);
484   }
485
486   event_saddr = g_inet_socket_address_new (mcast_addr, PTP_EVENT_PORT);
487   general_saddr = g_inet_socket_address_new (mcast_addr, PTP_GENERAL_PORT);
488
489   /* Create socket sources */
490   socket_event_source =
491       g_socket_create_source (socket_event, G_IO_IN | G_IO_PRI, NULL);
492   g_source_set_priority (socket_event_source, G_PRIORITY_HIGH);
493   g_source_set_callback (socket_event_source, (GSourceFunc) have_socket_data_cb,
494       NULL, NULL);
495   g_source_attach (socket_event_source, NULL);
496   socket_general_source =
497       g_socket_create_source (socket_general, G_IO_IN | G_IO_PRI, NULL);
498   g_source_set_priority (socket_general_source, G_PRIORITY_DEFAULT);
499   g_source_set_callback (socket_general_source,
500       (GSourceFunc) have_socket_data_cb, NULL, NULL);
501   g_source_attach (socket_general_source, NULL);
502
503   g_strfreev (probed_ifaces);
504 }
505
506 static void
507 drop_privileges (void)
508 {
509 #ifdef HAVE_PTP_HELPER_SETUID
510   /* Switch to the given user/group */
511 #ifdef HAVE_PTP_HELPER_SETUID_GROUP
512   {
513     struct group *grp;
514
515     grp = getgrnam (HAVE_PTP_HELPER_SETUID_GROUP);
516     if (!grp)
517       g_error ("Failed to get group information '%s': %s",
518           HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
519
520     if (setgid (grp->gr_gid) != 0)
521       g_error ("Failed to change to group '%s': %s",
522           HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
523   }
524 #endif
525
526 #ifdef HAVE_PTP_HELPER_SETUID_USER
527   {
528     struct passwd *pwd;
529
530     pwd = getpwnam (HAVE_PTP_HELPER_SETUID_USER);
531     if (!pwd)
532       g_error ("Failed to get user information '%s': %s",
533           HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
534
535 #ifndef HAVE_PTP_HELPER_SETUID_GROUP
536     if (setgid (pwd->pw_gid) != 0)
537       g_error ("Failed to change to user group '%s': %s",
538           HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
539 #endif
540
541     if (setuid (pwd->pw_uid) != 0)
542       g_error ("Failed to change to user '%s': %s", HAVE_PTP_HELPER_SETUID_USER,
543           g_strerror (errno));
544   }
545 #endif
546 #endif
547 #ifdef HAVE_PTP_HELPER_CAPABILITIES
548   /* Drop all capabilities */
549   {
550     cap_t caps;
551
552     caps = cap_get_proc ();
553     if (caps == 0)
554       g_error ("Failed to get process caps: %s", g_strerror (errno));
555     if (cap_clear (caps) != 0)
556       g_error ("Failed to clear caps: %s", g_strerror (errno));
557     if (cap_set_proc (caps) != 0)
558       g_error ("Failed to set process caps: %s", g_strerror (errno));
559   }
560 #endif
561 }
562
563 static void
564 setup_stdio_channels (void)
565 {
566   GSource *stdin_source;
567
568   /* Create stdin source */
569   stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
570   if (g_io_channel_set_encoding (stdin_channel, NULL,
571           NULL) == G_IO_STATUS_ERROR)
572     g_error ("Failed to set stdin to binary encoding");
573   g_io_channel_set_buffered (stdin_channel, FALSE);
574   stdin_source =
575       g_io_create_watch (stdin_channel, G_IO_IN | G_IO_PRI | G_IO_HUP);
576   g_source_set_priority (stdin_source, G_PRIORITY_DEFAULT);
577   g_source_set_callback (stdin_source, (GSourceFunc) have_stdin_data_cb, NULL,
578       NULL);
579   g_source_attach (stdin_source, NULL);
580
581   /* Create stdout channel */
582   stdout_channel = g_io_channel_unix_new (STDOUT_FILENO);
583   if (g_io_channel_set_encoding (stdout_channel, NULL,
584           NULL) == G_IO_STATUS_ERROR)
585     g_error ("Failed to set stdout to binary encoding");
586   g_io_channel_set_buffered (stdout_channel, FALSE);
587 }
588
589 static void
590 write_clock_id (void)
591 {
592   GError *err = NULL;
593   GIOStatus status;
594   StdIOHeader header = { 0, };
595   gsize written;
596
597   /* Write clock id to stdout */
598
599   header.type = TYPE_CLOCK_ID;
600   header.size = 8;
601   status =
602       g_io_channel_write_chars (stdout_channel, (gchar *) & header,
603       sizeof (header), &written, &err);
604   if (status == G_IO_STATUS_ERROR) {
605     g_error ("Failed to write to stdout: %s", err->message);
606     g_clear_error (&err);
607   } else if (status == G_IO_STATUS_EOF) {
608     g_message ("EOF on stdout");
609     exit (0);
610   } else if (status != G_IO_STATUS_NORMAL) {
611     g_error ("Unexpected stdout write status: %d", status);
612   } else if (written != sizeof (header)) {
613     g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
614   }
615
616   status =
617       g_io_channel_write_chars (stdout_channel,
618       (const gchar *) clock_id_array, sizeof (clock_id_array), &written, &err);
619   if (status == G_IO_STATUS_ERROR) {
620     g_error ("Failed to write to stdout: %s", err->message);
621     g_clear_error (&err);
622   } else if (status == G_IO_STATUS_EOF) {
623     g_message ("EOF on stdout");
624     exit (0);
625   } else if (status != G_IO_STATUS_NORMAL) {
626     g_error ("Unexpected stdout write status: %d", status);
627   } else if (written != sizeof (clock_id_array)) {
628     g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
629   }
630 }
631
632 #ifdef __APPLE__
633 static gint
634 dummy_poll (GPollFD * fds, guint nfds, gint timeout)
635 {
636   return g_poll (fds, nfds, timeout);
637 }
638 #endif
639
640 gint
641 main (gint argc, gchar ** argv)
642 {
643   GOptionContext *opt_ctx;
644   GMainLoop *loop;
645   GError *err = NULL;
646
647   /* FIXME: Work around some side effects of the changes from
648    * https://bugzilla.gnome.org/show_bug.cgi?id=741054
649    *
650    * The modified poll function somehow calls setugid(), which
651    * then abort()s the application. Make sure that we use g_poll()
652    * here!
653    */
654 #ifdef __APPLE__
655   {
656     GMainContext *context = g_main_context_default ();
657     g_main_context_set_poll_func (context, dummy_poll);
658   }
659 #endif
660
661 #ifdef HAVE_PTP_HELPER_SETUID
662   if (setuid (0) < 0)
663     g_error ("not running with superuser privileges");
664 #endif
665
666   opt_ctx = g_option_context_new ("- GStreamer PTP helper process");
667   g_option_context_add_main_entries (opt_ctx, opt_entries, NULL);
668   if (!g_option_context_parse (opt_ctx, &argc, &argv, &err))
669     g_error ("Error parsing options: %s", err->message);
670   g_clear_error (&err);
671   g_option_context_free (opt_ctx);
672
673   setup_sockets ();
674   drop_privileges ();
675   setup_stdio_channels ();
676   write_clock_id ();
677
678   /* Get running */
679   loop = g_main_loop_new (NULL, FALSE);
680   g_main_loop_run (loop);
681
682   /* We never exit cleanly, so don't do cleanup */
683   g_assert_not_reached ();
684
685   return 0;
686 }