VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdesktop.c@ 37112

Last change on this file since 37112 was 35532, checked in by vboxsync, 14 years ago

RDP/client: disable iprt logging on startup as iprt threading is not available

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.6 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Entrypoint and utility functions
4 Copyright (C) Matthew Chapman 1999-2008
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
22 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
23 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
24 * the General Public License version 2 (GPLv2) at this time for any software where
25 * a choice of GPL license versions is made available with the language indicating
26 * that GPLv2 or any later version may be used, or where a choice of which version
27 * of the GPL is applied is otherwise unspecified.
28 */
29
30#include <stdarg.h> /* va_list va_start va_end */
31#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
32#include <fcntl.h> /* open */
33#include <pwd.h> /* getpwuid */
34#include <termios.h> /* tcgetattr tcsetattr */
35#include <sys/stat.h> /* stat */
36#include <sys/time.h> /* gettimeofday */
37#include <sys/times.h> /* times */
38#include <ctype.h> /* toupper */
39#include <errno.h>
40#include "rdesktop.h"
41
42#ifdef VBOX
43# include <VBox/version.h>
44# include <iprt/log.h>
45#endif
46
47#ifdef HAVE_LOCALE_H
48#include <locale.h>
49#endif
50#ifdef HAVE_ICONV
51#ifdef HAVE_LANGINFO_H
52#include <langinfo.h>
53#endif
54#endif
55
56#ifdef EGD_SOCKET
57#include <sys/types.h>
58#include <sys/socket.h> /* socket connect */
59#include <sys/un.h> /* sockaddr_un */
60#endif
61
62#include "ssl.h"
63
64char g_title[64] = "";
65char g_username[64];
66char g_hostname[16];
67char g_keymapname[PATH_MAX] = "";
68unsigned int g_keylayout = 0x409; /* Defaults to US keyboard layout */
69int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
70int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
71int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
72
73int g_width = 800; /* width is special: If 0, the
74 geometry will be fetched from
75 _NET_WORKAREA. If negative,
76 absolute value specifies the
77 percent of the whole screen. */
78int g_height = 600;
79int g_xpos = 0;
80int g_ypos = 0;
81int g_pos = 0; /* 0 position unspecified,
82 1 specified,
83 2 xpos neg,
84 4 ypos neg */
85extern int g_tcp_port_rdp;
86int g_server_depth = -1;
87int g_win_button_size = 0; /* If zero, disable single app mode */
88RD_BOOL g_bitmap_compression = True;
89RD_BOOL g_sendmotion = True;
90RD_BOOL g_bitmap_cache = True;
91RD_BOOL g_bitmap_cache_persist_enable = False;
92RD_BOOL g_bitmap_cache_precache = True;
93RD_BOOL g_encryption = True;
94RD_BOOL g_packet_encryption = True;
95RD_BOOL g_desktop_save = True; /* desktop save order */
96RD_BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */
97RD_BOOL g_fullscreen = False;
98RD_BOOL g_grab_keyboard = True;
99RD_BOOL g_hide_decorations = False;
100RD_BOOL g_use_rdp5 = True;
101RD_BOOL g_rdpclip = True;
102RD_BOOL g_console_session = False;
103#ifndef VBOX
104RD_BOOL g_numlock_sync = False;
105#else /* VBOX */
106/* Always use numlock synchronization with VRDP. */
107RD_BOOL g_numlock_sync = True;
108#endif /* VBOX */
109RD_BOOL g_lspci_enabled = False;
110RD_BOOL g_owncolmap = False;
111RD_BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
112RD_BOOL g_seamless_rdp = False;
113uint32 g_embed_wnd;
114uint32 g_rdp5_performanceflags =
115 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
116/* Session Directory redirection */
117RD_BOOL g_redirect = False;
118char g_redirect_server[64];
119char g_redirect_domain[16];
120char g_redirect_password[64];
121char g_redirect_username[64];
122char g_redirect_cookie[128];
123uint32 g_redirect_flags = 0;
124
125#ifdef WITH_RDPSND
126RD_BOOL g_rdpsnd = False;
127#endif
128
129#ifdef WITH_RDPUSB
130RD_BOOL g_rdpusb = False;
131#endif
132
133#ifdef HAVE_ICONV
134char g_codepage[16] = "";
135#endif
136
137extern RDPDR_DEVICE g_rdpdr_device[];
138extern uint32 g_num_devices;
139extern char *g_rdpdr_clientname;
140
141#ifdef RDP2VNC
142extern int rfb_port;
143extern int defer_time;
144void
145rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
146 char *shell, char *directory);
147#endif
148/* Display usage information */
149static void
150usage(char *program)
151{
152 fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
153 fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2008 Matthew Chapman.\n");
154#ifdef VBOX
155 fprintf(stderr, "Modified for VirtualBox by " VBOX_VENDOR "\n");
156#endif
157 fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
158
159 fprintf(stderr, "Usage: %s [options] server[:port]\n", program);
160#ifdef RDP2VNC
161 fprintf(stderr, " -V: vnc port\n");
162 fprintf(stderr, " -Q: defer time (ms)\n");
163#endif
164 fprintf(stderr, " -u: user name\n");
165 fprintf(stderr, " -d: domain\n");
166 fprintf(stderr, " -s: shell\n");
167 fprintf(stderr, " -c: working directory\n");
168 fprintf(stderr, " -p: password (- to prompt)\n");
169 fprintf(stderr, " -n: client hostname\n");
170 fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
171 fprintf(stderr, " -g: desktop geometry (WxH)\n");
172 fprintf(stderr, " -f: full-screen mode\n");
173 fprintf(stderr, " -b: force bitmap updates\n");
174#ifdef HAVE_ICONV
175 fprintf(stderr, " -L: local codepage\n");
176#endif
177 fprintf(stderr, " -A: enable SeamlessRDP mode\n");
178 fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
179 fprintf(stderr, " -e: disable encryption (French TS)\n");
180 fprintf(stderr, " -E: disable encryption from client to server\n");
181 fprintf(stderr, " -m: do not send motion events\n");
182 fprintf(stderr, " -C: use private colour map\n");
183 fprintf(stderr, " -D: hide window manager decorations\n");
184 fprintf(stderr, " -K: keep window manager key bindings\n");
185 fprintf(stderr, " -S: caption button size (single application mode)\n");
186 fprintf(stderr, " -T: window title\n");
187 fprintf(stderr, " -N: enable numlock syncronization\n");
188 fprintf(stderr, " -X: embed into another window with a given id.\n");
189 fprintf(stderr, " -a: connection colour depth\n");
190 fprintf(stderr, " -z: enable rdp compression\n");
191 fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
192 fprintf(stderr, " -P: use persistent bitmap caching\n");
193 fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
194 fprintf(stderr,
195 " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
196 fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n");
197 fprintf(stderr,
198 " '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n");
199 fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n");
200 fprintf(stderr, " '-r clientname=<client name>': Set the client name displayed\n");
201 fprintf(stderr, " for redirected disks\n");
202 fprintf(stderr,
203 " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n");
204 fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n");
205 fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n");
206 fprintf(stderr,
207 " or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n");
208#ifdef WITH_RDPSND
209 fprintf(stderr,
210 " '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n");
211 fprintf(stderr, " remote would leave sound on server\n");
212 fprintf(stderr, " available drivers for 'local':\n");
213 rdpsnd_show_help();
214#endif
215#ifdef WITH_RDPUSB
216 fprintf(stderr,
217 " '-r usb': enable USB redirection\n");
218#endif
219 fprintf(stderr,
220 " '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n");
221 fprintf(stderr, " redirection.\n");
222 fprintf(stderr,
223 " 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n");
224 fprintf(stderr, " when sending data to server.\n");
225 fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n");
226#ifdef WITH_SCARD
227 fprintf(stderr, " '-r scard[:\"Scard Name\"=\"Alias Name[;Vendor Name]\"[,...]]\n");
228 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0\"\n");
229 fprintf(stderr,
230 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
231 fprintf(stderr,
232 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
233 fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0;AKS\"\n");
234 fprintf(stderr,
235 " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n");
236 fprintf(stderr,
237 " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n");
238 fprintf(stderr,
239 " \"AKS\" -> Device vendor name \n");
240#endif
241 fprintf(stderr, " -0: attach to console\n");
242 fprintf(stderr, " -4: use RDP version 4\n");
243 fprintf(stderr, " -5: use RDP version 5 (default)\n");
244}
245
246static void
247print_disconnect_reason(uint16 reason)
248{
249 char *text;
250
251 switch (reason)
252 {
253 case exDiscReasonNoInfo:
254 text = "No information available";
255 break;
256
257 case exDiscReasonAPIInitiatedDisconnect:
258 text = "Server initiated disconnect";
259 break;
260
261 case exDiscReasonAPIInitiatedLogoff:
262 text = "Server initiated logoff";
263 break;
264
265 case exDiscReasonServerIdleTimeout:
266 text = "Server idle timeout reached";
267 break;
268
269 case exDiscReasonServerLogonTimeout:
270 text = "Server logon timeout reached";
271 break;
272
273 case exDiscReasonReplacedByOtherConnection:
274 text = "The session was replaced";
275 break;
276
277 case exDiscReasonOutOfMemory:
278 text = "The server is out of memory";
279 break;
280
281 case exDiscReasonServerDeniedConnection:
282 text = "The server denied the connection";
283 break;
284
285 case exDiscReasonServerDeniedConnectionFips:
286 text = "The server denied the connection for security reason";
287 break;
288
289 case exDiscReasonLicenseInternal:
290 text = "Internal licensing error";
291 break;
292
293 case exDiscReasonLicenseNoLicenseServer:
294 text = "No license server available";
295 break;
296
297 case exDiscReasonLicenseNoLicense:
298 text = "No valid license available";
299 break;
300
301 case exDiscReasonLicenseErrClientMsg:
302 text = "Invalid licensing message";
303 break;
304
305 case exDiscReasonLicenseHwidDoesntMatchLicense:
306 text = "Hardware id doesn't match software license";
307 break;
308
309 case exDiscReasonLicenseErrClientLicense:
310 text = "Client license error";
311 break;
312
313 case exDiscReasonLicenseCantFinishProtocol:
314 text = "Network error during licensing protocol";
315 break;
316
317 case exDiscReasonLicenseClientEndedProtocol:
318 text = "Licensing protocol was not completed";
319 break;
320
321 case exDiscReasonLicenseErrClientEncryption:
322 text = "Incorrect client license enryption";
323 break;
324
325 case exDiscReasonLicenseCantUpgradeLicense:
326 text = "Can't upgrade license";
327 break;
328
329 case exDiscReasonLicenseNoRemoteConnections:
330 text = "The server is not licensed to accept remote connections";
331 break;
332
333 default:
334 if (reason > 0x1000 && reason < 0x7fff)
335 {
336 text = "Internal protocol error";
337 }
338 else
339 {
340 text = "Unknown reason";
341 }
342 }
343 fprintf(stderr, "disconnect: %s.\n", text);
344}
345
346static void
347rdesktop_reset_state(void)
348{
349 rdp_reset_state();
350}
351
352static RD_BOOL
353read_password(char *password, int size)
354{
355 struct termios tios;
356 RD_BOOL ret = False;
357 int istty = 0;
358 char *p;
359
360 if (tcgetattr(STDIN_FILENO, &tios) == 0)
361 {
362 fprintf(stderr, "Password: ");
363 tios.c_lflag &= ~ECHO;
364 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
365 istty = 1;
366 }
367
368 if (fgets(password, size, stdin) != NULL)
369 {
370 ret = True;
371
372 /* strip final newline */
373 p = strchr(password, '\n');
374 if (p != NULL)
375 *p = 0;
376 }
377
378 if (istty)
379 {
380 tios.c_lflag |= ECHO;
381 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
382 fprintf(stderr, "\n");
383 }
384
385 return ret;
386}
387
388static void
389parse_server_and_port(char *server)
390{
391 char *p;
392#ifdef IPv6
393 int addr_colons;
394#endif
395
396#ifdef IPv6
397 p = server;
398 addr_colons = 0;
399 while (*p)
400 if (*p++ == ':')
401 addr_colons++;
402 if (addr_colons >= 2)
403 {
404 /* numeric IPv6 style address format - [1:2:3::4]:port */
405 p = strchr(server, ']');
406 if (*server == '[' && p != NULL)
407 {
408 if (*(p + 1) == ':' && *(p + 2) != '\0')
409 g_tcp_port_rdp = strtol(p + 2, NULL, 10);
410 /* remove the port number and brackets from the address */
411 *p = '\0';
412 strncpy(server, server + 1, strlen(server));
413 }
414 }
415 else
416 {
417 /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */
418 p = strchr(server, ':');
419 if (p != NULL)
420 {
421 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
422 *p = 0;
423 }
424 }
425#else /* no IPv6 support */
426 p = strchr(server, ':');
427 if (p != NULL)
428 {
429 g_tcp_port_rdp = strtol(p + 1, NULL, 10);
430 *p = 0;
431 }
432#endif /* IPv6 */
433
434}
435
436#ifdef VBOX
437/* This disables iprt logging */
438DECLEXPORT(PRTLOGGER) RTLogDefaultInit(void)
439{
440 return NULL;
441}
442#endif
443
444/* Client program */
445int
446main(int argc, char *argv[])
447{
448 char server[64];
449 char fullhostname[64];
450 char domain[16];
451 char password[64];
452 char shell[256];
453 char directory[256];
454 RD_BOOL prompt_password, deactivated;
455 struct passwd *pw;
456 uint32 flags, ext_disc_reason = 0;
457 char *p;
458 int c;
459 char *locale = NULL;
460 int username_option = 0;
461 RD_BOOL geometry_option = False;
462 int run_count = 0; /* Session Directory support */
463 RD_BOOL continue_connect = True; /* Session Directory support */
464#ifdef WITH_RDPSND
465 char *rdpsnd_optarg = NULL;
466#endif
467
468#ifdef HAVE_LOCALE_H
469 /* Set locale according to environment */
470 locale = setlocale(LC_ALL, "");
471 if (locale)
472 {
473 locale = xstrdup(locale);
474 }
475
476#endif
477 flags = RDP_LOGON_NORMAL;
478 prompt_password = False;
479 domain[0] = password[0] = shell[0] = directory[0] = 0;
480 g_embed_wnd = 0;
481
482 g_num_devices = 0;
483
484#ifdef RDP2VNC
485#define VNCOPT "V:Q:"
486#else
487#define VNCOPT
488#endif
489
490 while ((c = getopt(argc, argv,
491 VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
492 {
493 switch (c)
494 {
495#ifdef RDP2VNC
496 case 'V':
497 rfb_port = strtol(optarg, NULL, 10);
498 if (rfb_port < 100)
499 rfb_port += 5900;
500 break;
501
502 case 'Q':
503 defer_time = strtol(optarg, NULL, 10);
504 if (defer_time < 0)
505 defer_time = 0;
506 break;
507#endif
508
509 case 'A':
510 g_seamless_rdp = True;
511 break;
512
513 case 'u':
514 STRNCPY(g_username, optarg, sizeof(g_username));
515 username_option = 1;
516 break;
517
518 case 'L':
519#ifdef HAVE_ICONV
520 STRNCPY(g_codepage, optarg, sizeof(g_codepage));
521#else
522 error("iconv support not available\n");
523#endif
524 break;
525
526 case 'd':
527 STRNCPY(domain, optarg, sizeof(domain));
528 break;
529
530 case 's':
531 STRNCPY(shell, optarg, sizeof(shell));
532 break;
533
534 case 'c':
535 STRNCPY(directory, optarg, sizeof(directory));
536 break;
537
538 case 'p':
539 if ((optarg[0] == '-') && (optarg[1] == 0))
540 {
541 prompt_password = True;
542 break;
543 }
544
545 STRNCPY(password, optarg, sizeof(password));
546 flags |= RDP_LOGON_AUTO;
547
548 /* try to overwrite argument so it won't appear in ps */
549 p = optarg;
550 while (*p)
551 *(p++) = 'X';
552 break;
553
554 case 'n':
555 STRNCPY(g_hostname, optarg, sizeof(g_hostname));
556 break;
557
558 case 'k':
559 STRNCPY(g_keymapname, optarg, sizeof(g_keymapname));
560 break;
561
562 case 'g':
563 geometry_option = True;
564 g_fullscreen = False;
565 if (!strcmp(optarg, "workarea"))
566 {
567 g_width = g_height = 0;
568 break;
569 }
570
571 g_width = strtol(optarg, &p, 10);
572 if (g_width <= 0)
573 {
574 error("invalid geometry\n");
575 return 1;
576 }
577
578 if (*p == 'x')
579 g_height = strtol(p + 1, &p, 10);
580
581 if (g_height <= 0)
582 {
583 error("invalid geometry\n");
584 return 1;
585 }
586
587 if (*p == '%')
588 {
589 g_width = -g_width;
590 p++;
591 }
592
593 if (*p == '+' || *p == '-')
594 {
595 g_pos |= (*p == '-') ? 2 : 1;
596 g_xpos = strtol(p, &p, 10);
597
598 }
599 if (*p == '+' || *p == '-')
600 {
601 g_pos |= (*p == '-') ? 4 : 1;
602 g_ypos = strtol(p, NULL, 10);
603 }
604
605 break;
606
607 case 'f':
608 g_fullscreen = True;
609 break;
610
611 case 'b':
612 g_bitmap_cache = False;
613 break;
614
615 case 'B':
616 g_ownbackstore = False;
617 break;
618
619 case 'e':
620 g_encryption = False;
621 break;
622 case 'E':
623 g_packet_encryption = False;
624 break;
625 case 'm':
626 g_sendmotion = False;
627 break;
628
629 case 'C':
630 g_owncolmap = True;
631 break;
632
633 case 'D':
634 g_hide_decorations = True;
635 break;
636
637 case 'K':
638 g_grab_keyboard = False;
639 break;
640
641 case 'S':
642 if (!strcmp(optarg, "standard"))
643 {
644 g_win_button_size = 18;
645 break;
646 }
647
648 g_win_button_size = strtol(optarg, &p, 10);
649
650 if (*p)
651 {
652 error("invalid button size\n");
653 return 1;
654 }
655
656 break;
657
658 case 'T':
659 STRNCPY(g_title, optarg, sizeof(g_title));
660 break;
661
662 case 'N':
663 g_numlock_sync = True;
664 break;
665
666 case 'X':
667 g_embed_wnd = strtol(optarg, NULL, 0);
668 break;
669
670 case 'a':
671 g_server_depth = strtol(optarg, NULL, 10);
672 if (g_server_depth != 8 &&
673 g_server_depth != 16 &&
674 g_server_depth != 15 && g_server_depth != 24
675 && g_server_depth != 32)
676 {
677 error("Invalid server colour depth.\n");
678 return 1;
679 }
680 break;
681
682 case 'z':
683 DEBUG(("rdp compression enabled\n"));
684 flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
685 break;
686
687 case 'x':
688 if (str_startswith(optarg, "m")) /* modem */
689 {
690 g_rdp5_performanceflags =
691 RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG |
692 RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING;
693 }
694 else if (str_startswith(optarg, "b")) /* broadband */
695 {
696 g_rdp5_performanceflags = RDP5_NO_WALLPAPER;
697 }
698 else if (str_startswith(optarg, "l")) /* lan */
699 {
700 g_rdp5_performanceflags = RDP5_DISABLE_NOTHING;
701 }
702 else
703 {
704 g_rdp5_performanceflags = strtol(optarg, NULL, 16);
705 }
706 break;
707
708 case 'P':
709 g_bitmap_cache_persist_enable = True;
710 break;
711
712 case 'r':
713
714 if (str_startswith(optarg, "sound"))
715 {
716 optarg += 5;
717
718 if (*optarg == ':')
719 {
720 optarg++;
721 while ((p = next_arg(optarg, ',')))
722 {
723 if (str_startswith(optarg, "remote"))
724 flags |= RDP_LOGON_LEAVE_AUDIO;
725
726 if (str_startswith(optarg, "local"))
727#ifdef WITH_RDPSND
728 {
729 rdpsnd_optarg =
730 next_arg(optarg, ':');
731 g_rdpsnd = True;
732 }
733
734#else
735 warning("Not compiled with sound support\n");
736#endif
737
738 if (str_startswith(optarg, "off"))
739#ifdef WITH_RDPSND
740 g_rdpsnd = False;
741#else
742 warning("Not compiled with sound support\n");
743#endif
744
745 optarg = p;
746 }
747 }
748 else
749 {
750#ifdef WITH_RDPSND
751 g_rdpsnd = True;
752#else
753 warning("Not compiled with sound support\n");
754#endif
755 }
756 }
757 else if (str_startswith(optarg, "usb"))
758 {
759#ifdef WITH_RDPUSB
760 g_rdpusb = True;
761#else
762 warning("Not compiled with USB support\n");
763#endif
764 }
765 else if (str_startswith(optarg, "disk"))
766 {
767 /* -r disk:h:=/mnt/floppy */
768 disk_enum_devices(&g_num_devices, optarg + 4);
769 }
770 else if (str_startswith(optarg, "comport"))
771 {
772 serial_enum_devices(&g_num_devices, optarg + 7);
773 }
774 else if (str_startswith(optarg, "lspci"))
775 {
776 g_lspci_enabled = True;
777 }
778 else if (str_startswith(optarg, "lptport"))
779 {
780 parallel_enum_devices(&g_num_devices, optarg + 7);
781 }
782 else if (str_startswith(optarg, "printer"))
783 {
784 printer_enum_devices(&g_num_devices, optarg + 7);
785 }
786 else if (str_startswith(optarg, "clientname"))
787 {
788 g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1);
789 strcpy(g_rdpdr_clientname, optarg + 11);
790 }
791 else if (str_startswith(optarg, "clipboard"))
792 {
793 optarg += 9;
794
795 if (*optarg == ':')
796 {
797 optarg++;
798
799 if (str_startswith(optarg, "off"))
800 g_rdpclip = False;
801 else
802 cliprdr_set_mode(optarg);
803 }
804 else
805 g_rdpclip = True;
806 }
807 else if (strncmp("scard", optarg, 5) == 0)
808 {
809#ifdef WITH_SCARD
810 scard_enum_devices(&g_num_devices, optarg + 5);
811#else
812 warning("Not compiled with smartcard support\n");
813#endif
814 }
815 else
816 {
817 warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n");
818 }
819 break;
820
821 case '0':
822 g_console_session = True;
823 break;
824
825 case '4':
826 g_use_rdp5 = False;
827 break;
828
829 case '5':
830 g_use_rdp5 = True;
831 break;
832
833 case 'h':
834 case '?':
835 default:
836 usage(argv[0]);
837 return 1;
838 }
839 }
840
841 if (argc - optind != 1)
842 {
843 usage(argv[0]);
844 return 1;
845 }
846
847 STRNCPY(server, argv[optind], sizeof(server));
848 parse_server_and_port(server);
849
850 if (g_seamless_rdp)
851 {
852 if (g_win_button_size)
853 {
854 error("You cannot use -S and -A at the same time\n");
855 return 1;
856 }
857 g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
858 if (geometry_option)
859 {
860 error("You cannot use -g and -A at the same time\n");
861 return 1;
862 }
863 if (g_fullscreen)
864 {
865 error("You cannot use -f and -A at the same time\n");
866 return 1;
867 }
868 if (g_hide_decorations)
869 {
870 error("You cannot use -D and -A at the same time\n");
871 return 1;
872 }
873 if (g_embed_wnd)
874 {
875 error("You cannot use -X and -A at the same time\n");
876 return 1;
877 }
878 if (!g_use_rdp5)
879 {
880 error("You cannot use -4 and -A at the same time\n");
881 return 1;
882 }
883 g_width = -100;
884 g_grab_keyboard = False;
885 }
886
887 if (!username_option)
888 {
889 pw = getpwuid(getuid());
890 if ((pw == NULL) || (pw->pw_name == NULL))
891 {
892 error("could not determine username, use -u\n");
893 return 1;
894 }
895
896 STRNCPY(g_username, pw->pw_name, sizeof(g_username));
897 }
898
899#ifdef HAVE_ICONV
900 if (g_codepage[0] == 0)
901 {
902 if (setlocale(LC_CTYPE, ""))
903 {
904 STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage));
905 }
906 else
907 {
908 STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage));
909 }
910 }
911#endif
912
913 if (g_hostname[0] == 0)
914 {
915 if (gethostname(fullhostname, sizeof(fullhostname)) == -1)
916 {
917 error("could not determine local hostname, use -n\n");
918 return 1;
919 }
920
921 p = strchr(fullhostname, '.');
922 if (p != NULL)
923 *p = 0;
924
925 STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
926 }
927
928 if (g_keymapname[0] == 0)
929 {
930 if (locale && xkeymap_from_locale(locale))
931 {
932 fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname);
933 }
934 else
935 {
936 STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname));
937 }
938 }
939 if (locale)
940 xfree(locale);
941
942
943 if (prompt_password && read_password(password, sizeof(password)))
944 flags |= RDP_LOGON_AUTO;
945
946 if (g_title[0] == 0)
947 {
948 strcpy(g_title, "rdesktop - ");
949 strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - "));
950 }
951
952#ifdef RDP2VNC
953 rdp2vnc_connect(server, flags, domain, password, shell, directory);
954 return 0;
955#else
956
957 if (!ui_init())
958 return 1;
959
960#ifdef WITH_RDPSND
961 if (g_rdpsnd)
962 {
963 if (!rdpsnd_init(rdpsnd_optarg))
964 {
965 warning("Initializing sound-support failed!\n");
966 }
967 }
968#endif
969
970#ifdef WITH_RDPUSB
971 if (g_rdpusb)
972 rdpusb_init();
973#endif
974
975 if (g_lspci_enabled)
976 lspci_init();
977
978 rdpdr_init();
979
980 while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */
981 {
982 if (run_count == 0)
983 {
984 if (!rdp_connect(server, flags, domain, password, shell, directory))
985 return 1;
986 }
987 else if (!rdp_reconnect
988 (server, flags, domain, password, shell, directory, g_redirect_cookie))
989 return 1;
990
991 /* By setting encryption to False here, we have an encrypted login
992 packet but unencrypted transfer of other packets */
993 if (!g_packet_encryption)
994 g_encryption = False;
995
996
997 DEBUG(("Connection successful.\n"));
998 memset(password, 0, sizeof(password));
999
1000 if (run_count == 0)
1001 if (!ui_create_window())
1002 continue_connect = False;
1003
1004 if (continue_connect)
1005 rdp_main_loop(&deactivated, &ext_disc_reason);
1006
1007 DEBUG(("Disconnecting...\n"));
1008 rdp_disconnect();
1009
1010 if ((g_redirect == True) && (run_count == 0)) /* Support for Session Directory */
1011 {
1012 /* reset state of major globals */
1013 rdesktop_reset_state();
1014
1015 STRNCPY(domain, g_redirect_domain, sizeof(domain));
1016 STRNCPY(g_username, g_redirect_username, sizeof(g_username));
1017 STRNCPY(password, g_redirect_password, sizeof(password));
1018 STRNCPY(server, g_redirect_server, sizeof(server));
1019 flags |= RDP_LOGON_AUTO;
1020
1021 g_redirect = False;
1022 }
1023 else
1024 {
1025 continue_connect = False;
1026 ui_destroy_window();
1027 break;
1028 }
1029
1030 run_count++;
1031 }
1032
1033 cache_save_state();
1034 ui_deinit();
1035
1036#ifdef WITH_RDPUSB
1037 if (g_rdpusb)
1038 rdpusb_close();
1039#endif
1040
1041 if (ext_disc_reason >= 2)
1042 print_disconnect_reason(ext_disc_reason);
1043
1044 if (deactivated)
1045 {
1046 /* clean disconnect */
1047 return 0;
1048 }
1049 else
1050 {
1051 if (ext_disc_reason == exDiscReasonAPIInitiatedDisconnect
1052 || ext_disc_reason == exDiscReasonAPIInitiatedLogoff)
1053 {
1054 /* not so clean disconnect, but nothing to worry about */
1055 return 0;
1056 }
1057 else
1058 {
1059 /* return error */
1060 return 2;
1061 }
1062 }
1063
1064#endif
1065
1066}
1067
1068#ifdef EGD_SOCKET
1069/* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */
1070static RD_BOOL
1071generate_random_egd(uint8 * buf)
1072{
1073 struct sockaddr_un addr;
1074 RD_BOOL ret = False;
1075 int fd;
1076
1077 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1078 if (fd == -1)
1079 return False;
1080
1081 addr.sun_family = AF_UNIX;
1082 memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET));
1083 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
1084 goto err;
1085
1086 /* PRNGD and EGD use a simple communications protocol */
1087 buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */
1088 buf[1] = 32; /* Number of requested random bytes */
1089 if (write(fd, buf, 2) != 2)
1090 goto err;
1091
1092 if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */
1093 goto err;
1094
1095 if (read(fd, buf, 32) != 32)
1096 goto err;
1097
1098 ret = True;
1099
1100 err:
1101 close(fd);
1102 return ret;
1103}
1104#endif
1105
1106/* Generate a 32-byte random for the secure transport code. */
1107void
1108generate_random(uint8 * random)
1109{
1110 struct stat st;
1111 struct tms tmsbuf;
1112 SSL_MD5 md5;
1113 uint32 *r;
1114 int fd, n;
1115
1116 /* If we have a kernel random device, try that first */
1117 if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
1118 || ((fd = open("/dev/random", O_RDONLY)) != -1))
1119 {
1120 n = read(fd, random, 32);
1121 close(fd);
1122 if (n == 32)
1123 return;
1124 }
1125
1126#ifdef EGD_SOCKET
1127 /* As a second preference use an EGD */
1128 if (generate_random_egd(random))
1129 return;
1130#endif
1131
1132 /* Otherwise use whatever entropy we can gather - ideas welcome. */
1133 r = (uint32 *) random;
1134 r[0] = (getpid()) | (getppid() << 16);
1135 r[1] = (getuid()) | (getgid() << 16);
1136 r[2] = times(&tmsbuf); /* system uptime (clocks) */
1137 gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
1138 stat("/tmp", &st);
1139 r[5] = st.st_atime;
1140 r[6] = st.st_mtime;
1141 r[7] = st.st_ctime;
1142
1143 /* Hash both halves with MD5 to obscure possible patterns */
1144 ssl_md5_init(&md5);
1145 ssl_md5_update(&md5, random, 16);
1146 ssl_md5_final(&md5, random);
1147 ssl_md5_update(&md5, random + 16, 16);
1148 ssl_md5_final(&md5, random + 16);
1149}
1150
1151/* malloc; exit if out of memory */
1152void *
1153xmalloc(int size)
1154{
1155 void *mem = malloc(size);
1156 if (mem == NULL)
1157 {
1158 error("xmalloc %d\n", size);
1159 exit(1);
1160 }
1161 return mem;
1162}
1163
1164/* Exit on NULL pointer. Use to verify result from XGetImage etc */
1165void
1166exit_if_null(void *ptr)
1167{
1168 if (ptr == NULL)
1169 {
1170 error("unexpected null pointer. Out of memory?\n");
1171 exit(1);
1172 }
1173}
1174
1175/* strdup */
1176char *
1177xstrdup(const char *s)
1178{
1179 char *mem = strdup(s);
1180 if (mem == NULL)
1181 {
1182 perror("strdup");
1183 exit(1);
1184 }
1185 return mem;
1186}
1187
1188/* realloc; exit if out of memory */
1189void *
1190xrealloc(void *oldmem, size_t size)
1191{
1192 void *mem;
1193
1194 if (size == 0)
1195 size = 1;
1196 mem = realloc(oldmem, size);
1197 if (mem == NULL)
1198 {
1199 error("xrealloc %ld\n", size);
1200 exit(1);
1201 }
1202 return mem;
1203}
1204
1205/* free */
1206void
1207xfree(void *mem)
1208{
1209 free(mem);
1210}
1211
1212/* report an error */
1213void
1214error(char *format, ...)
1215{
1216 va_list ap;
1217
1218 fprintf(stderr, "ERROR: ");
1219
1220 va_start(ap, format);
1221 vfprintf(stderr, format, ap);
1222 va_end(ap);
1223}
1224
1225/* report a warning */
1226void
1227warning(char *format, ...)
1228{
1229 va_list ap;
1230
1231 fprintf(stderr, "WARNING: ");
1232
1233 va_start(ap, format);
1234 vfprintf(stderr, format, ap);
1235 va_end(ap);
1236}
1237
1238/* report an unimplemented protocol feature */
1239void
1240unimpl(char *format, ...)
1241{
1242 va_list ap;
1243
1244 fprintf(stderr, "NOT IMPLEMENTED: ");
1245
1246 va_start(ap, format);
1247 vfprintf(stderr, format, ap);
1248 va_end(ap);
1249}
1250
1251/* produce a hex dump */
1252void
1253hexdump(unsigned char *p, unsigned int len)
1254{
1255 unsigned char *line = p;
1256 int i, thisline, offset = 0;
1257
1258 while (offset < len)
1259 {
1260 printf("%04x ", offset);
1261 thisline = len - offset;
1262 if (thisline > 16)
1263 thisline = 16;
1264
1265 for (i = 0; i < thisline; i++)
1266 printf("%02x ", line[i]);
1267
1268 for (; i < 16; i++)
1269 printf(" ");
1270
1271 for (i = 0; i < thisline; i++)
1272 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1273
1274 printf("\n");
1275 offset += thisline;
1276 line += thisline;
1277 }
1278}
1279
1280/*
1281 input: src is the string we look in for needle.
1282 Needle may be escaped by a backslash, in
1283 that case we ignore that particular needle.
1284 return value: returns next src pointer, for
1285 succesive executions, like in a while loop
1286 if retval is 0, then there are no more args.
1287 pitfalls:
1288 src is modified. 0x00 chars are inserted to
1289 terminate strings.
1290 return val, points on the next val chr after ins
1291 0x00
1292
1293 example usage:
1294 while( (pos = next_arg( optarg, ',')) ){
1295 printf("%s\n",optarg);
1296 optarg=pos;
1297 }
1298
1299*/
1300char *
1301next_arg(char *src, char needle)
1302{
1303 char *nextval;
1304 char *p;
1305 char *mvp = 0;
1306
1307 /* EOS */
1308 if (*src == (char) 0x00)
1309 return 0;
1310
1311 p = src;
1312 /* skip escaped needles */
1313 while ((nextval = strchr(p, needle)))
1314 {
1315 mvp = nextval - 1;
1316 /* found backslashed needle */
1317 if (*mvp == '\\' && (mvp > src))
1318 {
1319 /* move string one to the left */
1320 while (*(mvp + 1) != (char) 0x00)
1321 {
1322 *mvp = *(mvp + 1);
1323 mvp++;
1324 }
1325 *mvp = (char) 0x00;
1326 p = nextval;
1327 }
1328 else
1329 {
1330 p = nextval + 1;
1331 break;
1332 }
1333
1334 }
1335
1336 /* more args available */
1337 if (nextval)
1338 {
1339 *nextval = (char) 0x00;
1340 return ++nextval;
1341 }
1342
1343 /* no more args after this, jump to EOS */
1344 nextval = src + strlen(src);
1345 return nextval;
1346}
1347
1348
1349void
1350toupper_str(char *p)
1351{
1352 while (*p)
1353 {
1354 if ((*p >= 'a') && (*p <= 'z'))
1355 *p = toupper((int) *p);
1356 p++;
1357 }
1358}
1359
1360
1361RD_BOOL
1362str_startswith(const char *s, const char *prefix)
1363{
1364 return (strncmp(s, prefix, strlen(prefix)) == 0);
1365}
1366
1367
1368/* Split input into lines, and call linehandler for each
1369 line. Incomplete lines are saved in the rest variable, which should
1370 initially point to NULL. When linehandler returns False, stop and
1371 return False. Otherwise, return True. */
1372RD_BOOL
1373str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data)
1374{
1375 char *buf, *p;
1376 char *oldrest;
1377 size_t inputlen;
1378 size_t buflen;
1379 size_t restlen = 0;
1380 RD_BOOL ret = True;
1381
1382 /* Copy data to buffer */
1383 inputlen = strlen(input);
1384 if (*rest)
1385 restlen = strlen(*rest);
1386 buflen = restlen + inputlen + 1;
1387 buf = (char *) xmalloc(buflen);
1388 buf[0] = '\0';
1389 if (*rest)
1390 STRNCPY(buf, *rest, buflen);
1391 strncat(buf, input, inputlen);
1392 p = buf;
1393
1394 while (1)
1395 {
1396 char *newline = strchr(p, '\n');
1397 if (newline)
1398 {
1399 *newline = '\0';
1400 if (!linehandler(p, data))
1401 {
1402 p = newline + 1;
1403 ret = False;
1404 break;
1405 }
1406 p = newline + 1;
1407 }
1408 else
1409 {
1410 break;
1411
1412 }
1413 }
1414
1415 /* Save in rest */
1416 oldrest = *rest;
1417 restlen = buf + buflen - p;
1418 *rest = (char *) xmalloc(restlen);
1419 STRNCPY((*rest), p, restlen);
1420 xfree(oldrest);
1421
1422 xfree(buf);
1423 return ret;
1424}
1425
1426/* Execute the program specified by argv. For each line in
1427 stdout/stderr output, call linehandler. Returns false on failure. */
1428RD_BOOL
1429subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
1430{
1431 pid_t child;
1432 int fd[2];
1433 int n = 1;
1434 char output[256];
1435 char *rest = NULL;
1436
1437 if (pipe(fd) < 0)
1438 {
1439 perror("pipe");
1440 return False;
1441 }
1442
1443 if ((child = fork()) < 0)
1444 {
1445 perror("fork");
1446 return False;
1447 }
1448
1449 /* Child */
1450 if (child == 0)
1451 {
1452 /* Close read end */
1453 close(fd[0]);
1454
1455 /* Redirect stdout and stderr to pipe */
1456 dup2(fd[1], 1);
1457 dup2(fd[1], 2);
1458
1459 /* Execute */
1460 execvp(argv[0], argv);
1461 perror("Error executing child");
1462 _exit(128);
1463 }
1464
1465 /* Parent. Close write end. */
1466 close(fd[1]);
1467 while (n > 0)
1468 {
1469 n = read(fd[0], output, 255);
1470 output[n] = '\0';
1471 str_handle_lines(output, &rest, linehandler, data);
1472 }
1473 xfree(rest);
1474
1475 return True;
1476}
1477
1478
1479/* not all clibs got ltoa */
1480#define LTOA_BUFSIZE (sizeof(long) * 8 + 1)
1481
1482char *
1483l_to_a(long N, int base)
1484{
1485 static char ret[LTOA_BUFSIZE];
1486
1487 char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf);
1488
1489 register int divrem;
1490
1491 if (base < 36 || 2 > base)
1492 base = 10;
1493
1494 if (N < 0)
1495 {
1496 *head++ = '-';
1497 N = -N;
1498 }
1499
1500 tail = buf + sizeof(buf);
1501 *--tail = 0;
1502
1503 do
1504 {
1505 divrem = N % base;
1506 *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10;
1507 N /= base;
1508 }
1509 while (N);
1510
1511 strcpy(head, tail);
1512 return ret;
1513}
1514
1515
1516int
1517load_licence(unsigned char **data)
1518{
1519 char *home, *path;
1520 struct stat st;
1521 int fd, length;
1522
1523 home = getenv("HOME");
1524 if (home == NULL)
1525 return -1;
1526
1527 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1528 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1529
1530 fd = open(path, O_RDONLY);
1531 if (fd == -1)
1532 return -1;
1533
1534 if (fstat(fd, &st))
1535 return -1;
1536
1537 *data = (uint8 *) xmalloc(st.st_size);
1538 length = read(fd, *data, st.st_size);
1539 close(fd);
1540 xfree(path);
1541 return length;
1542}
1543
1544void
1545save_licence(unsigned char *data, int length)
1546{
1547 char *home, *path, *tmppath;
1548 int fd;
1549
1550 home = getenv("HOME");
1551 if (home == NULL)
1552 return;
1553
1554 path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + sizeof("/.rdesktop/licence."));
1555
1556 sprintf(path, "%s/.rdesktop", home);
1557 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1558 {
1559 perror(path);
1560 return;
1561 }
1562
1563 /* write licence to licence.hostname.new, then atomically rename to licence.hostname */
1564
1565 sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1566 tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1567 strcpy(tmppath, path);
1568 strcat(tmppath, ".new");
1569
1570 fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1571 if (fd == -1)
1572 {
1573 perror(tmppath);
1574 return;
1575 }
1576
1577 if (write(fd, data, length) != length)
1578 {
1579 perror(tmppath);
1580 unlink(tmppath);
1581 }
1582 else if (rename(tmppath, path) == -1)
1583 {
1584 perror(path);
1585 unlink(tmppath);
1586 }
1587
1588 close(fd);
1589 xfree(tmppath);
1590 xfree(path);
1591}
1592
1593/* Create the bitmap cache directory */
1594RD_BOOL
1595rd_pstcache_mkdir(void)
1596{
1597 char *home;
1598 char bmpcache_dir[256];
1599
1600 home = getenv("HOME");
1601
1602 if (home == NULL)
1603 return False;
1604
1605#ifdef VBOX
1606 snprintf(bmpcache_dir, sizeof(bmpcache_dir), "%s/%s", home, ".rdesktop");
1607#else
1608 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1609#endif
1610
1611 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1612 {
1613 perror(bmpcache_dir);
1614 return False;
1615 }
1616
1617#ifdef VBOX
1618 snprintf(bmpcache_dir, sizeof(bmpcache_dir), "%s/%s", home, ".rdesktop/cache");
1619#else
1620 sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1621#endif
1622
1623 if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1624 {
1625 perror(bmpcache_dir);
1626 return False;
1627 }
1628
1629 return True;
1630}
1631
1632/* open a file in the .rdesktop directory */
1633int
1634rd_open_file(char *filename)
1635{
1636 char *home;
1637 char fn[256];
1638 int fd;
1639
1640 home = getenv("HOME");
1641 if (home == NULL)
1642 return -1;
1643#ifdef VBOX
1644 snprintf(fn, sizeof(fn), "%s/.rdesktop/%s", home, filename);
1645#else
1646 sprintf(fn, "%s/.rdesktop/%s", home, filename);
1647#endif
1648 fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1649 if (fd == -1)
1650 perror(fn);
1651 return fd;
1652}
1653
1654/* close file */
1655void
1656rd_close_file(int fd)
1657{
1658 close(fd);
1659}
1660
1661/* read from file*/
1662int
1663rd_read_file(int fd, void *ptr, int len)
1664{
1665 return read(fd, ptr, len);
1666}
1667
1668/* write to file */
1669int
1670rd_write_file(int fd, void *ptr, int len)
1671{
1672 return write(fd, ptr, len);
1673}
1674
1675/* move file pointer */
1676int
1677rd_lseek_file(int fd, int offset)
1678{
1679 return lseek(fd, offset, SEEK_SET);
1680}
1681
1682/* do a write lock on a file */
1683RD_BOOL
1684rd_lock_file(int fd, int start, int len)
1685{
1686 struct flock lock;
1687
1688 lock.l_type = F_WRLCK;
1689 lock.l_whence = SEEK_SET;
1690 lock.l_start = start;
1691 lock.l_len = len;
1692 if (fcntl(fd, F_SETLK, &lock) == -1)
1693 return False;
1694 return True;
1695}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette