/[rdesktop]/jpeg/rdesktop/trunk/rdesktop.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /jpeg/rdesktop/trunk/rdesktop.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1508 - (show annotations)
Mon Jul 20 16:47:49 2009 UTC (14 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 35331 byte(s)
Date: Sun, 19 Jul 2009 14:00:30 -0400
From: Daniel Jarboe <daniel.jarboe(at)gmail.com>
To: Dobrica Pavlinusic <dpavlin(at)rot13.org>
Subject: Re: rdesktop diff

On Sun, Jul 19, 2009 at 8:01 AM, Dobrica Pavlinusic <dpavlin(at)rot13.org>wrote:
>
> I'm looking forward for your patch, and will keep you informed what I
> did with it :-)

This diff was an earlier one with some debug printfs in so you can see how
the tuning knobs work.  I was only keeping an eye on a young computer user's
activities so ignored small screen changes and wrote out the stills to lossy
jpegs with libjpeg.  If you plan on saving screens no matter if there are
changes or not then I'd throw away all the g_bitmap_data_last_write stuff.

diff is against rdesktop-1.6 with whatever patches are in ubuntu 9.04
jaunty.  Added libjpeg62-dev in addition to the regular rdesktop build
dependencies.  Have fun and thanks for letting me know what you end up with.

~ Daniel

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

  ViewVC Help
Powered by ViewVC 1.1.26